aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/usb
diff options
context:
space:
mode:
authorAndrew Thompson <thompsa@FreeBSD.org>2010-09-02 04:05:00 +0000
committerAndrew Thompson <thompsa@FreeBSD.org>2010-09-02 04:05:00 +0000
commitd2d71ce7a8e60d6617b5c4ae2480397687f4882c (patch)
tree7e83eba44b1bf404b2c855b2410efd3723330e56 /sys/dev/usb
parent527aa7b226444c9b34752c1becf739381161e408 (diff)
downloadsrc-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.h4
-rw-r--r--sys/dev/usb/usb_device.c2
-rw-r--r--sys/dev/usb/usb_generic.c5
-rw-r--r--sys/dev/usb/usb_hub.c31
-rw-r--r--sys/dev/usb/usbdi.h1
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,