From 075d334923bee2644bcb2cb59a1f4aee1369c800 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Wed, 17 Feb 2016 14:56:57 +0100 Subject: [PATCH 2/2] chaoskey: use an URB for requesting data This allows handling signals. Signed-off-by: Oliver Neukum --- drivers/usb/misc/chaoskey.c | 76 +++++++++++++++++++++++++++++++++------------ 1 file changed, 56 insertions(+), 20 deletions(-) diff --git a/drivers/usb/misc/chaoskey.c b/drivers/usb/misc/chaoskey.c index 5a67a04..67102b4 100644 --- a/drivers/usb/misc/chaoskey.c +++ b/drivers/usb/misc/chaoskey.c @@ -73,6 +73,8 @@ static const struct usb_device_id chaoskey_table[] = { }; MODULE_DEVICE_TABLE(usb, chaoskey_table); +static void chaos_read_callback(struct urb *urb); + /* Driver-local specific stuff */ struct chaoskey { struct usb_interface *interface; @@ -159,6 +161,14 @@ static int chaoskey_probe(struct usb_interface *interface, if (!dev->urb) goto out; + usb_fill_bulk_urb(dev->urb, + udev, + usb_rcvbulkpipe(udev, altsetting->endpoint[in_ep].desc.bEndpointAddress), + dev->buf, + size, + chaos_read_callback, + dev); + /* Construct a name using the product and serial values. Each * device needs a unique name for the hwrng code */ @@ -245,6 +255,7 @@ static void chaoskey_disconnect(struct usb_interface *interface) mutex_lock(&dev->lock); dev->present = 0; + usb_poison_urb(dev->urb); if (!dev->open) { mutex_unlock(&dev->lock); @@ -319,14 +330,33 @@ static int chaoskey_release(struct inode *inode, struct file *file) return 0; } +static void chaos_read_callback(struct urb *urb) +{ + struct chaoskey *dev = urb->context; + int status = urb->status; + + usb_dbg(dev->interface, "callback status (%d)", status); + + if (status == 0) + dev->valid = urb->actual_length; + else + dev->valid = 0; + + dev->used = 0; + + /* must be seen first before validity is announced */ + smp_wmb(); + + dev->reading = false; + wake_up(&dev->wait_q); +} + /* Fill the buffer. Called with dev->lock held */ static int _chaoskey_fill(struct chaoskey *dev) { DEFINE_WAIT(wait); int result; - int this_read; - struct usb_device *udev = interface_to_usbdev(dev->interface); usb_dbg(dev->interface, "fill"); @@ -351,21 +381,31 @@ static int _chaoskey_fill(struct chaoskey *dev) return result; } - result = usb_bulk_msg(udev, - usb_rcvbulkpipe(udev, dev->in_ep), - dev->buf, dev->size, &this_read, - NAK_TIMEOUT); + dev->reading = true; + result = usb_submit_urb(dev->urb, GFP_KERNEL); + if (result < 0) { + result = usb_translate_errors(result); + dev->reading = false; + goto out; + } + + result = wait_event_interruptible_timeout( + dev->wait_q, + !dev->reading, + NAK_TIMEOUT); + + if (result < 0) + goto out; + if (result == 0) + result = -ETIMEDOUT; + else + result = dev->valid; +out: /* Let the device go back to sleep eventually */ usb_autopm_put_interface(dev->interface); - if (result == 0) { - dev->valid = this_read; - dev->used = 0; - } - - usb_dbg(dev->interface, "bulk_msg result %d this_read %d", - result, this_read); + usb_dbg(dev->interface, "read %d bytes", dev->valid); return result; } @@ -403,13 +443,7 @@ static ssize_t chaoskey_read(struct file *file, goto bail; if (dev->valid == dev->used) { result = _chaoskey_fill(dev); - if (result) { - mutex_unlock(&dev->lock); - goto bail; - } - - /* Read returned zero bytes */ - if (dev->used == dev->valid) { + if (result < 0) { mutex_unlock(&dev->lock); goto bail; } @@ -443,6 +477,8 @@ bail: return read_count; } usb_dbg(dev->interface, "empty read, result %d", result); + if (result == -ETIMEDOUT) + result = -EAGAIN; return result; } -- 2.1.4