]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - include/linux/usb.h
USB: keep count of unsuspended children
[linux-2.6-omap-h63xx.git] / include / linux / usb.h
index df5c93eb3ce9cc1336b75bd44dcae67107df1fbf..0cd73edeef139f3d0a4d2bd8d1b43151d8b51eb4 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/fs.h>          /* for struct file_operations */
 #include <linux/completion.h>  /* for struct completion */
 #include <linux/sched.h>       /* for current && schedule_timeout */
+#include <linux/mutex.h>       /* for struct mutex */
 
 struct usb_device;
 struct usb_driver;
@@ -103,8 +104,12 @@ enum usb_interface_condition {
  * @condition: binding state of the interface: not bound, binding
  *     (in probe()), bound to a driver, or unbinding (in disconnect())
  * @is_active: flag set when the interface is bound and not suspended.
+ * @needs_remote_wakeup: flag set when the driver requires remote-wakeup
+ *     capability during autosuspend.
  * @dev: driver model's view of this device
  * @class_dev: driver model's class view of this device.
+ * @pm_usage_cnt: PM usage counter for this interface; autosuspend is not
+ *     allowed unless the counter is 0.
  *
  * USB device drivers attach to interfaces on a physical device.  Each
  * interface encapsulates a single high level function, such as feeding
@@ -144,9 +149,11 @@ struct usb_interface {
                                         * bound to */
        enum usb_interface_condition condition;         /* state of binding */
        unsigned is_active:1;           /* the interface is not suspended */
+       unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */
 
        struct device dev;              /* interface specific device info */
        struct class_device *class_dev;
+       int pm_usage_cnt;               /* usage counter for autosuspend */
 };
 #define        to_usb_interface(d) container_of(d, struct usb_interface, dev)
 #define        interface_to_usbdev(intf) \
@@ -306,8 +313,13 @@ struct usb_bus {
 /* This is arbitrary.
  * From USB 2.0 spec Table 11-13, offset 7, a hub can
  * have up to 255 ports. The most yet reported is 10.
+ *
+ * Current Wireless USB host hardware (Intel i1480 for example) allows
+ * up to 22 devices to connect. Upcoming hardware might raise that
+ * limit. Because the arrays need to add a bit for hub status data, we
+ * do 31, so plus one evens out to four bytes.
  */
-#define USB_MAXCHILDREN                (16)
+#define USB_MAXCHILDREN                (31)
 
 struct usb_tt;
 
@@ -350,7 +362,8 @@ struct usb_device {
        u8 portnum;                     /* Parent port number (origin 1) */
        u8 level;                       /* Number of USB hub ancestors */
 
-       int have_langid;                /* whether string_langid is valid */
+       unsigned discon_suspended:1;    /* Disconnected while suspended */
+       unsigned have_langid:1;         /* whether string_langid is valid */
        int string_langid;              /* language ID for strings */
 
        /* static strings from the device */
@@ -372,6 +385,15 @@ struct usb_device {
 
        int maxchild;                   /* Number of ports if hub */
        struct usb_device *children[USB_MAXCHILDREN];
+
+       int pm_usage_cnt;               /* usage counter for autosuspend */
+#ifdef CONFIG_PM
+       struct work_struct autosuspend; /* for delayed autosuspends */
+       struct mutex pm_mutex;          /* protects PM operations */
+
+       unsigned auto_pm:1;             /* autosuspend/resume in progress */
+       unsigned do_remote_wakeup:1;    /* remote wakeup should be enabled */
+#endif
 };
 #define        to_usb_device(d) container_of(d, struct usb_device, dev)
 
@@ -392,6 +414,40 @@ extern int usb_reset_composite_device(struct usb_device *dev,
 
 extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id);
 
+/* USB autosuspend and autoresume */
+#ifdef CONFIG_USB_SUSPEND
+extern int usb_autopm_set_interface(struct usb_interface *intf);
+extern int usb_autopm_get_interface(struct usb_interface *intf);
+extern void usb_autopm_put_interface(struct usb_interface *intf);
+
+static inline void usb_autopm_enable(struct usb_interface *intf)
+{
+       intf->pm_usage_cnt = 0;
+       usb_autopm_set_interface(intf);
+}
+
+static inline void usb_autopm_disable(struct usb_interface *intf)
+{
+       intf->pm_usage_cnt = 1;
+       usb_autopm_set_interface(intf);
+}
+
+#else
+
+static inline int usb_autopm_set_interface(struct usb_interface *intf)
+{ return 0; }
+
+static inline int usb_autopm_get_interface(struct usb_interface *intf)
+{ return 0; }
+
+static inline void usb_autopm_put_interface(struct usb_interface *intf)
+{ }
+static inline void usb_autopm_enable(struct usb_interface *intf)
+{ }
+static inline void usb_autopm_disable(struct usb_interface *intf)
+{ }
+#endif
+
 /*-------------------------------------------------------------------------*/
 
 /* for drivers using iso endpoints */
@@ -463,17 +519,137 @@ static inline int usb_make_path (struct usb_device *dev, char *buf,
 
 /*-------------------------------------------------------------------------*/
 
-extern int usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd);
-extern int usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd);
-extern int usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd);
-extern int usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd);
-extern int usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd);
-extern int usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd);
-extern int usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd);
-extern int usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd);
-extern int usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd);
-extern int usb_endpoint_is_isoc_in(const struct usb_endpoint_descriptor *epd);
-extern int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor *epd);
+/**
+ * usb_endpoint_dir_in - check if the endpoint has IN direction
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint is of type IN, otherwise it returns false.
+ */
+static inline int usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd)
+{
+       return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN);
+}
+
+/**
+ * usb_endpoint_dir_out - check if the endpoint has OUT direction
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint is of type OUT, otherwise it returns false.
+ */
+static inline int usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd)
+{
+       return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
+}
+
+/**
+ * usb_endpoint_xfer_bulk - check if the endpoint has bulk transfer type
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint is of type bulk, otherwise it returns false.
+ */
+static inline int usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd)
+{
+       return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+               USB_ENDPOINT_XFER_BULK);
+}
+
+/**
+ * usb_endpoint_xfer_int - check if the endpoint has interrupt transfer type
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint is of type interrupt, otherwise it returns
+ * false.
+ */
+static inline int usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd)
+{
+       return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+               USB_ENDPOINT_XFER_INT);
+}
+
+/**
+ * usb_endpoint_xfer_isoc - check if the endpoint has isochronous transfer type
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint is of type isochronous, otherwise it returns
+ * false.
+ */
+static inline int usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd)
+{
+       return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+               USB_ENDPOINT_XFER_ISOC);
+}
+
+/**
+ * usb_endpoint_is_bulk_in - check if the endpoint is bulk IN
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint has bulk transfer type and IN direction,
+ * otherwise it returns false.
+ */
+static inline int usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd)
+{
+       return (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_in(epd));
+}
+
+/**
+ * usb_endpoint_is_bulk_out - check if the endpoint is bulk OUT
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint has bulk transfer type and OUT direction,
+ * otherwise it returns false.
+ */
+static inline int usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd)
+{
+       return (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_out(epd));
+}
+
+/**
+ * usb_endpoint_is_int_in - check if the endpoint is interrupt IN
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint has interrupt transfer type and IN direction,
+ * otherwise it returns false.
+ */
+static inline int usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd)
+{
+       return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_in(epd));
+}
+
+/**
+ * usb_endpoint_is_int_out - check if the endpoint is interrupt OUT
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint has interrupt transfer type and OUT direction,
+ * otherwise it returns false.
+ */
+static inline int usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd)
+{
+       return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_out(epd));
+}
+
+/**
+ * usb_endpoint_is_isoc_in - check if the endpoint is isochronous IN
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint has isochronous transfer type and IN direction,
+ * otherwise it returns false.
+ */
+static inline int usb_endpoint_is_isoc_in(const struct usb_endpoint_descriptor *epd)
+{
+       return (usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_in(epd));
+}
+
+/**
+ * usb_endpoint_is_isoc_out - check if the endpoint is isochronous OUT
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint has isochronous transfer type and OUT direction,
+ * otherwise it returns false.
+ */
+static inline int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor *epd)
+{
+       return (usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_out(epd));
+}
 
 /*-------------------------------------------------------------------------*/
 
@@ -593,6 +769,8 @@ struct usbdrv_wrap {
  * @drvwrap: Driver-model core structure wrapper.
  * @no_dynamic_id: if set to 1, the USB core will not allow dynamic ids to be
  *     added to this driver by preventing the sysfs file from being created.
+ * @supports_autosuspend: if set to 0, the USB core will not allow autosuspend
+ *     for interfaces bound to this driver.
  *
  * USB interface drivers must provide a name, probe() and disconnect()
  * methods, and an id_table.  Other driver fields are optional.
@@ -631,6 +809,7 @@ struct usb_driver {
        struct usb_dynids dynids;
        struct usbdrv_wrap drvwrap;
        unsigned int no_dynamic_id:1;
+       unsigned int supports_autosuspend:1;
 };
 #define        to_usb_driver(d) container_of(d, struct usb_driver, drvwrap.driver)
 
@@ -648,6 +827,8 @@ struct usb_driver {
  * @suspend: Called when the device is going to be suspended by the system.
  * @resume: Called when the device is being resumed by the system.
  * @drvwrap: Driver-model core structure wrapper.
+ * @supports_autosuspend: if set to 0, the USB core will not allow autosuspend
+ *     for devices bound to this driver.
  *
  * USB drivers must provide all the fields listed above except drvwrap.
  */
@@ -660,6 +841,7 @@ struct usb_device_driver {
        int (*suspend) (struct usb_device *udev, pm_message_t message);
        int (*resume) (struct usb_device *udev);
        struct usbdrv_wrap drvwrap;
+       unsigned int supports_autosuspend:1;
 };
 #define        to_usb_device_driver(d) container_of(d, struct usb_device_driver, \
                drvwrap.driver)
@@ -731,9 +913,8 @@ struct usb_iso_packet_descriptor {
 };
 
 struct urb;
-struct pt_regs;
 
-typedef void (*usb_complete_t)(struct urb *, struct pt_regs *);
+typedef void (*usb_complete_t)(struct urb *);
 
 /**
  * struct urb - USB Request Block