diff options
author | thompsa <thompsa@FreeBSD.org> | 2010-05-12 22:42:35 +0000 |
---|---|---|
committer | thompsa <thompsa@FreeBSD.org> | 2010-05-12 22:42:35 +0000 |
commit | f61fd930ea6d4ab1f68a77846ad3ce133636197c (patch) | |
tree | 5cb412eb53df6be590b70f2b1455668701879e35 /sys/dev/usb/usb_generic.c | |
parent | 2cc73b6656a9910435455e662e86cf485e86b069 (diff) | |
download | FreeBSD-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.c | 28 |
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; |