summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb/usb_generic.c
diff options
context:
space:
mode:
authorthompsa <thompsa@FreeBSD.org>2010-05-12 22:42:35 +0000
committerthompsa <thompsa@FreeBSD.org>2010-05-12 22:42:35 +0000
commitf61fd930ea6d4ab1f68a77846ad3ce133636197c (patch)
tree5cb412eb53df6be590b70f2b1455668701879e35 /sys/dev/usb/usb_generic.c
parent2cc73b6656a9910435455e662e86cf485e86b069 (diff)
downloadFreeBSD-src-f61fd930ea6d4ab1f68a77846ad3ce133636197c.zip
FreeBSD-src-f61fd930ea6d4ab1f68a77846ad3ce133636197c.tar.gz
If a USB device is suspended and a USB set config request is issued when the
USB enumeration lock is locked, then the USB stack fails to resume the device because locking the USB enumeration lock is part of the resume procedure. To solve this issue a new lock is introduced which only protects the suspend and resume callbacks, which can be dropped inside the usbd_do_request_flags() function, to allow suspend and resume during so-called enumeration operations. Submitted by: Hans Petter Selasky
Diffstat (limited to 'sys/dev/usb/usb_generic.c')
-rw-r--r--sys/dev/usb/usb_generic.c28
1 files changed, 24 insertions, 4 deletions
diff --git a/sys/dev/usb/usb_generic.c b/sys/dev/usb/usb_generic.c
index db27468..6667751 100644
--- a/sys/dev/usb/usb_generic.c
+++ b/sys/dev/usb/usb_generic.c
@@ -1735,14 +1735,34 @@ ugen_set_power_mode(struct usb_fifo *f, int mode)
break;
case USB_POWER_MODE_RESUME:
- err = usbd_req_clear_port_feature(udev->parent_hub,
- NULL, udev->port_no, UHF_PORT_SUSPEND);
+#if USB_HAVE_POWERD
+ /* let USB-powerd handle resume */
+ USB_BUS_LOCK(udev->bus);
+ udev->pwr_save.write_refs++;
+ udev->pwr_save.last_xfer_time = ticks;
+ USB_BUS_UNLOCK(udev->bus);
+
+ /* set new power mode */
+ usbd_set_power_mode(udev, USB_POWER_MODE_SAVE);
+
+ /* wait for resume to complete */
+ usb_pause_mtx(NULL, hz / 4);
+
+ /* clear write reference */
+ USB_BUS_LOCK(udev->bus);
+ udev->pwr_save.write_refs--;
+ USB_BUS_UNLOCK(udev->bus);
+#endif
mode = USB_POWER_MODE_SAVE;
break;
case USB_POWER_MODE_SUSPEND:
- err = usbd_req_set_port_feature(udev->parent_hub,
- NULL, udev->port_no, UHF_PORT_SUSPEND);
+#if USB_HAVE_POWERD
+ /* let USB-powerd handle suspend */
+ USB_BUS_LOCK(udev->bus);
+ udev->pwr_save.last_xfer_time = ticks - (256 * hz);
+ USB_BUS_UNLOCK(udev->bus);
+#endif
mode = USB_POWER_MODE_SAVE;
break;
OpenPOWER on IntegriCloud