[RFT 2/4] chaoskey: introduce asynchronous reads

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This divides requesting IO and waiting for IO from each other.

Signed-off-by: Oliver Neukum <oneukum@xxxxxxxx>
---
 drivers/usb/misc/chaoskey.c | 39 +++++++++++++++++++++++++++++++--------
 1 file changed, 31 insertions(+), 8 deletions(-)

diff --git a/drivers/usb/misc/chaoskey.c b/drivers/usb/misc/chaoskey.c
index ad4c0b6d02cf..d47c2cc65269 100644
--- a/drivers/usb/misc/chaoskey.c
+++ b/drivers/usb/misc/chaoskey.c
@@ -336,15 +336,13 @@ static void chaos_read_callback(struct urb *urb)
 	wake_up(&dev->wait_q);
 }
 
-/* Fill the buffer. Called with dev->lock held
- */
-static int _chaoskey_fill(struct chaoskey *dev)
+static int chaoskey_request_fill(struct chaoskey *dev)
 {
 	DEFINE_WAIT(wait);
 	int result;
 	bool started;
 
-	usb_dbg(dev->interface, "fill");
+	usb_dbg(dev->interface, "request fill");
 
 	/* Return immediately if someone called before the buffer was
 	 * empty */
@@ -382,10 +380,26 @@ static int _chaoskey_fill(struct chaoskey *dev)
 	 */
 	started = dev->reads_started;
 	dev->reads_started = true;
+	/*
+	 * powering down while a read is under way
+	 * is blocked in suspend()
+	 */
+	usb_autopm_put_interface(dev->interface);
+	return 0;
+out:
+	usb_autopm_put_interface(dev->interface);
+	return result;
+}
+
+static int chaoskey_wait_fill(struct chaoskey *dev)
+{
+	DEFINE_WAIT(wait);
+	int result;
+
 	result = wait_event_interruptible_timeout(
 		dev->wait_q,
 		!dev->reading,
-		(started ? NAK_TIMEOUT : ALEA_FIRST_TIMEOUT) );
+		(dev->reads_started ? NAK_TIMEOUT : ALEA_FIRST_TIMEOUT) );
 
 	if (result < 0) {
 		usb_kill_urb(dev->urb);
@@ -400,7 +414,6 @@ static int _chaoskey_fill(struct chaoskey *dev)
 	}
 out:
 	/* Let the device go back to sleep eventually */
-	usb_autopm_put_interface(dev->interface);
 
 	usb_dbg(dev->interface, "read %d bytes", dev->valid);
 
@@ -449,7 +462,12 @@ static ssize_t chaoskey_read(struct file *file,
 				goto bail;
 		}
 		if (dev->valid == dev->used) {
-			result = _chaoskey_fill(dev);
+			result = chaoskey_request_fill(dev);
+			if (result < 0) {
+				mutex_unlock(&dev->lock);
+				goto bail;
+			}
+			result = chaoskey_wait_fill(dev);
 			if (result < 0) {
 				mutex_unlock(&dev->lock);
 				goto bail;
@@ -517,7 +535,7 @@ static int chaoskey_rng_read(struct hwrng *rng, void *data,
 	 * the buffer will still be empty
 	 */
 	if (dev->valid == dev->used)
-		(void) _chaoskey_fill(dev);
+		(void) chaoskey_request_fill(dev);
 
 	this_time = dev->valid - dev->used;
 	if (this_time > max)
@@ -537,6 +555,11 @@ static int chaoskey_rng_read(struct hwrng *rng, void *data,
 static int chaoskey_suspend(struct usb_interface *interface,
 			    pm_message_t message)
 {
+	struct chaoskey *dev = usb_get_intfdata(interface);
+
+	if (dev->reading && PMSG_IS_AUTO(message))
+		return -EBUSY;
+
 	usb_dbg(interface, "suspend");
 	return 0;
 }
-- 
2.16.4




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux