dev->errors = urb->status;
} else {
dev->bulk_in_filled = urb->actual_length;
}
dev->ongoing_read = 0;
spin_unlock(&dev->err_lock);
complete(&dev->bulk_in_completion);
}
static int skel_do_read_io(struct usb_skel *dev, size_t count)
{
int rv;
/* prepare a read */
usb_fill_bulk_urb(dev->bulk_in_urb,
dev->udev,
usb_rcvbulkpipe(dev->udev,
dev->bulk_in_endpointAddr),
dev->bulk_in_buffer,
min(dev->bulk_in_size, count),
skel_read_bulk_callback,
dev);
/* tell everybody to leave the URB alone */
spin_lock_irq(&dev->err_lock);
dev->ongoing_read = 1;
spin_unlock_irq(&dev->err_lock);
/* do it */
rv = usb_submit_urb(dev->bulk_in_urb, GFP_KERNEL);
if (rv < 0) {
err("%s - failed submitting read urb, error %d",
__func__, rv);
dev->bulk_in_filled = 0;
rv = (rv == -ENOMEM) ? rv : -EIO;
spin_lock_irq(&dev->err_lock);
dev->ongoing_read = 0;
spin_unlock_irq(&dev->err_lock);
}
return rv;
}
static ssize_t skel_read(struct file *file, char *buffer, size_t count,
loff_t *ppos)
{
struct usb_skel *dev;
int rv;
bool ongoing_io;
dev = (struct usb_skel *)file->private_data;
/* if we cannot read at all, return EOF */
if (!dev->bulk_in_urb || !count)
return 0;
/* no concurrent readers */
rv = mutex_lock_interruptible(&dev->io_mutex);
if (rv < 0)
return rv;
if (!dev->interface) { /* disconnect() was called */
rv = -ENODEV;
goto exit;
}
/* if IO is under way, we must not touch things */
retry:
spin_lock_irq(&dev->err_lock);
ongoing_io = dev->ongoing_read;
spin_unlock_irq(&dev->err_lock);
if (ongoing_io) {
/* nonblocking IO shall not wait */
if (file->f_flags & O_NONBLOCK) {
rv = -EAGAIN;
goto exit;
}
/*
* IO may take forever
* hence wait in an interruptible state
*/
rv = wait_for_completion_interruptible(&dev->bulk_in_completion);
if (rv < 0)
goto exit;
/*
* by waiting we also semiprocessed the urb
* we must finish now
*/
dev->bulk_in_copied = 0;
dev->processed_urb = 1;
}