suspending hid devices

Oliver Neukum <[email protected]>
Newsgroups gmane.linux.usb.devel
Organization Novell
Message-ID <[email protected]>
Hi,

currently hid-core's suspend() method only kills the input URB and leaves
the output URB alone. I am afraid this is incorrect. I've done a patch,
but I am looking for a solution regarding resumption. It seems to me that
it might wake up tasks too early. Comments?

	Regards
		Oliver

----
--- a/drivers/usb/input/hid-core.c	2007-01-29 12:04:22.000000000 +0100
+++ b/drivers/usb/input/hid-core.c	2007-01-29 12:29:30.000000000 +0100
@@ -321,7 +321,7 @@
 	struct hid_device *hid = urb->context;
 	struct usbhid_device *usbhid = hid->driver_data;
 	unsigned long flags;
-	int unplug = 0;
+	int unplug = 0, killed = 0;
 
 	switch (urb->status) {
 		case 0:			/* success */
@@ -331,7 +331,9 @@
 		case -EILSEQ:		/* protocol error or unplug */
 		case -EPROTO:		/* protocol error or unplug */
 		case -ECONNRESET:	/* unlink */
-		case -ENOENT:
+			break;
+		case -ENOENT:		/* disconnect or suspend */
+			killed = 1;
 			break;
 		default:		/* error */
 			warn("output irq status %d received", urb->status);
@@ -339,10 +341,14 @@
 
 	spin_lock_irqsave(&usbhid->outlock, flags);
 
-	if (unplug)
+	if (unplug) {
 		usbhid->outtail = usbhid->outhead;
-	else
-		usbhid->outtail = (usbhid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1);
+	} else {
+		if (killed && test_bit(HID_SUSPENDED, &usbhid->iofl))
+			return; /* suspended: do nothing */
+		else
+			usbhid->outtail = (usbhid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1);
+	}
 
 	if (usbhid->outhead != usbhid->outtail) {
 		if (hid_submit_out(hid)) {
@@ -1402,10 +1408,13 @@
 	struct usbhid_device *usbhid = hid->driver_data;
 
 	spin_lock_irq(&usbhid->inlock);	/* Sync with error handler */
+	spin_lock(&usbhid->outlock); /* sync with output handler */
 	set_bit(HID_SUSPENDED, &usbhid->iofl);
+	spin_unlock(&usbhid->outlock);
 	spin_unlock_irq(&usbhid->inlock);
 	del_timer(&usbhid->io_retry);
 	usb_kill_urb(usbhid->urbin);
+	usb_kill_urb(usbhid->urbout);
 	dev_dbg(&intf->dev, "suspend\n");
 	return 0;
 }
@@ -1419,6 +1428,17 @@
 	clear_bit(HID_SUSPENDED, &usbhid->iofl);
 	usbhid->retry_delay = 0;
 	status = hid_start_in(hid);
+	if (status < 0)
+		goto err_out;
+
+	if (usbhid->outhead != usbhid->outtail) {
+		status = hid_submit_out(hid);
+		if (status < 0) {
+			clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
+			wake_up(&hid->wait);
+		}
+	}
+err_out:
 	dev_dbg(&intf->dev, "resume status %d\n", status);
 	return status;
 }

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.