diff options
author | Andrew Thompson <thompsa@FreeBSD.org> | 2010-09-02 04:05:00 +0000 |
---|---|---|
committer | Andrew Thompson <thompsa@FreeBSD.org> | 2010-09-02 04:05:00 +0000 |
commit | d2d71ce7a8e60d6617b5c4ae2480397687f4882c (patch) | |
tree | 7e83eba44b1bf404b2c855b2410efd3723330e56 /sys/dev/usb | |
parent | 527aa7b226444c9b34752c1becf739381161e408 (diff) | |
download | src-d2d71ce7a8e60d6617b5c4ae2480397687f4882c.tar.gz src-d2d71ce7a8e60d6617b5c4ae2480397687f4882c.zip |
Add support for power mode filtering as some USB hardware does not support
power saving.
Submitted by: Hans Petter Selasky
Notes
Notes:
svn path=/head/; revision=212135
Diffstat (limited to 'sys/dev/usb')
-rw-r--r-- | sys/dev/usb/usb_controller.h | 4 | ||||
-rw-r--r-- | sys/dev/usb/usb_device.c | 2 | ||||
-rw-r--r-- | sys/dev/usb/usb_generic.c | 5 | ||||
-rw-r--r-- | sys/dev/usb/usb_hub.c | 31 | ||||
-rw-r--r-- | sys/dev/usb/usbdi.h | 1 |
5 files changed, 37 insertions, 6 deletions
diff --git a/sys/dev/usb/usb_controller.h b/sys/dev/usb/usb_controller.h index 6de588ac9631..0f7ffac5d210 100644 --- a/sys/dev/usb/usb_controller.h +++ b/sys/dev/usb/usb_controller.h @@ -102,6 +102,10 @@ struct usb_bus_methods { /* Optional transfer polling support */ void (*xfer_poll) (struct usb_bus *); + + /* Optional fixed power mode support */ + + void (*get_power_mode) (struct usb_device *udev, int8_t *pmode); }; /* diff --git a/sys/dev/usb/usb_device.c b/sys/dev/usb/usb_device.c index 62f59b8632ff..41ed16bc2827 100644 --- a/sys/dev/usb/usb_device.c +++ b/sys/dev/usb/usb_device.c @@ -1524,7 +1524,7 @@ usb_alloc_device(device_t parent_dev, struct usb_bus *bus, * of USB devices out there that do not work very well with * automatic suspend and resume! */ - udev->power_mode = USB_POWER_MODE_ON; + udev->power_mode = usbd_filter_power_mode(udev, USB_POWER_MODE_ON); udev->pwr_save.last_xfer_time = ticks; /* we are not ready yet */ udev->refcount = 1; diff --git a/sys/dev/usb/usb_generic.c b/sys/dev/usb/usb_generic.c index 66677518a146..d98aba4c0825 100644 --- a/sys/dev/usb/usb_generic.c +++ b/sys/dev/usb/usb_generic.c @@ -1791,10 +1791,9 @@ ugen_get_power_mode(struct usb_fifo *f) { struct usb_device *udev = f->udev; - if ((udev == NULL) || - (udev->parent_hub == NULL)) { + if (udev == NULL) return (USB_POWER_MODE_ON); - } + return (udev->power_mode); } diff --git a/sys/dev/usb/usb_hub.c b/sys/dev/usb/usb_hub.c index 488c4bcdeb1c..d42b5a4c7f9b 100644 --- a/sys/dev/usb/usb_hub.c +++ b/sys/dev/usb/usb_hub.c @@ -2133,12 +2133,39 @@ usbd_set_power_mode(struct usb_device *udev, uint8_t power_mode) { /* filter input argument */ if ((power_mode != USB_POWER_MODE_ON) && - (power_mode != USB_POWER_MODE_OFF)) { + (power_mode != USB_POWER_MODE_OFF)) power_mode = USB_POWER_MODE_SAVE; - } + + power_mode = usbd_filter_power_mode(udev, power_mode); + udev->power_mode = power_mode; /* update copy of power mode */ #if USB_HAVE_POWERD usb_bus_power_update(udev->bus); #endif } + +/*------------------------------------------------------------------------* + * usbd_filter_power_mode + * + * This function filters the power mode based on hardware requirements. + *------------------------------------------------------------------------*/ +uint8_t +usbd_filter_power_mode(struct usb_device *udev, uint8_t power_mode) +{ + struct usb_bus_methods *mtod; + int8_t temp; + + mtod = udev->bus->methods; + temp = -1; + + if (mtod->get_power_mode != NULL) + (mtod->get_power_mode) (udev, &temp); + + /* check if we should not filter */ + if (temp < 0) + return (power_mode); + + /* use fixed power mode given by hardware driver */ + return (temp); +} diff --git a/sys/dev/usb/usbdi.h b/sys/dev/usb/usbdi.h index 9adf39adc776..79b73ca1735e 100644 --- a/sys/dev/usb/usbdi.h +++ b/sys/dev/usb/usbdi.h @@ -479,6 +479,7 @@ void usbd_set_parent_iface(struct usb_device *udev, uint8_t iface_index, uint8_t usbd_get_bus_index(struct usb_device *udev); uint8_t usbd_get_device_index(struct usb_device *udev); void usbd_set_power_mode(struct usb_device *udev, uint8_t power_mode); +uint8_t usbd_filter_power_mode(struct usb_device *udev, uint8_t power_mode); uint8_t usbd_device_attached(struct usb_device *udev); void usbd_xfer_status(struct usb_xfer *xfer, int *actlen, int *sumlen, |