This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / drivers / usb / core / hcd.c
index e40346c..ecac9fa 100644 (file)
@@ -171,10 +171,10 @@ static const u8 fs_rh_config_descriptor [] = {
        0x01,       /*  __u8  bNumInterfaces; (1) */
        0x01,       /*  __u8  bConfigurationValue; */
        0x00,       /*  __u8  iConfiguration; */
-       0x40,       /*  __u8  bmAttributes; 
-                                Bit 7: Bus-powered,
+       0xc0,       /*  __u8  bmAttributes; 
+                                Bit 7: must be set,
                                     6: Self-powered,
-                                    5 Remote-wakwup,
+                                    5: Remote wakeup,
                                     4..0: resvd */
        0x00,       /*  __u8  MaxPower; */
       
@@ -218,10 +218,10 @@ static const u8 hs_rh_config_descriptor [] = {
        0x01,       /*  __u8  bNumInterfaces; (1) */
        0x01,       /*  __u8  bConfigurationValue; */
        0x00,       /*  __u8  iConfiguration; */
-       0x40,       /*  __u8  bmAttributes; 
-                                Bit 7: Bus-powered,
+       0xc0,       /*  __u8  bmAttributes; 
+                                Bit 7: must be set,
                                     6: Self-powered,
-                                    5 Remote-wakwup,
+                                    5: Remote wakeup,
                                     4..0: resvd */
        0x00,       /*  __u8  MaxPower; */
       
@@ -324,13 +324,15 @@ static int rh_string (
 /* Root hub control transfers execute synchronously */
 static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
 {
-       struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet;
+       struct usb_ctrlrequest *cmd;
        u16             typeReq, wValue, wIndex, wLength;
        const u8        *bufp = 0;
        u8              *ubuf = urb->transfer_buffer;
        int             len = 0;
+       int             patch_wakeup = 0;
        unsigned long   flags;
 
+       cmd = (struct usb_ctrlrequest *) urb->setup_packet;
        typeReq  = (cmd->bRequestType << 8) | cmd->bRequest;
        wValue   = le16_to_cpu (cmd->wValue);
        wIndex   = le16_to_cpu (cmd->wIndex);
@@ -347,13 +349,21 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
        /* DEVICE REQUESTS */
 
        case DeviceRequest | USB_REQ_GET_STATUS:
-               // DEVICE_REMOTE_WAKEUP
-               ubuf [0] = 1; // selfpowered
+               ubuf [0] = (hcd->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP)
+                               | (1 << USB_DEVICE_SELF_POWERED);
                ubuf [1] = 0;
-                       /* FALLTHROUGH */
+               break;
        case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
+               if (wValue == USB_DEVICE_REMOTE_WAKEUP)
+                       hcd->remote_wakeup = 0;
+               else
+                       goto error;
+               break;
        case DeviceOutRequest | USB_REQ_SET_FEATURE:
-               dev_dbg (hcd->self.controller, "no device features yet yet\n");
+               if (hcd->can_wakeup && wValue == USB_DEVICE_REMOTE_WAKEUP)
+                       hcd->remote_wakeup = 1;
+               else
+                       goto error;
                break;
        case DeviceRequest | USB_REQ_GET_CONFIGURATION:
                ubuf [0] = 1;
@@ -379,6 +389,8 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
                                bufp = fs_rh_config_descriptor;
                                len = sizeof fs_rh_config_descriptor;
                        }
+                       if (hcd->can_wakeup)
+                               patch_wakeup = 1;
                        break;
                case USB_DT_STRING << 8:
                        urb->actual_length = rh_string (
@@ -444,6 +456,11 @@ error:
                urb->actual_length = len;
                // always USB_DIR_IN, toward host
                memcpy (ubuf, bufp, len);
+
+               /* report whether RH hardware supports remote wakeup */
+               if (patch_wakeup)
+                       ((struct usb_config_descriptor *)ubuf)->bmAttributes
+                               |= USB_CONFIG_ATT_WAKEUP;
        }
 
        /* any errors get returned through the urb completion */
@@ -747,8 +764,9 @@ EXPORT_SYMBOL (usb_deregister_bus);
  *
  * The USB host controller calls this function to register the root hub
  * properly with the USB subsystem.  It sets up the device properly in
- * the device model tree, and then calls usb_new_device() to register the
- * usb device.  It also assigns the root hub's USB address (always 1).
+ * the device tree and stores the root_hub pointer in the bus structure,
+ * then calls usb_new_device() to register the usb device.  It also
+ * assigns the root hub's USB address (always 1).
  */
 int usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev)
 {
@@ -760,12 +778,28 @@ int usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev
        memset (&usb_dev->bus->devmap.devicemap, 0,
                        sizeof usb_dev->bus->devmap.devicemap);
        set_bit (devnum, usb_dev->bus->devmap.devicemap);
-       usb_dev->state = USB_STATE_ADDRESS;
+       usb_set_device_state(usb_dev, USB_STATE_ADDRESS);
 
+       down (&usb_bus_list_lock);
+       usb_dev->bus->root_hub = usb_dev;
+
+       usb_dev->epmaxpacketin[0] = usb_dev->epmaxpacketout[0] = 64;
+       retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);
+       if (retval != sizeof usb_dev->descriptor) {
+               dev_dbg (parent_dev, "can't read %s device descriptor %d\n",
+                               usb_dev->dev.bus_id, retval);
+               return (retval < 0) ? retval : -EMSGSIZE;
+       }
+
+       down (&usb_dev->serialize);
        retval = usb_new_device (usb_dev);
-       if (retval)
+       up (&usb_dev->serialize);
+       if (retval) {
+               usb_dev->bus->root_hub = NULL;
                dev_err (parent_dev, "can't register root hub for %s, %d\n",
                                usb_dev->dev.bus_id, retval);
+       }
+       up (&usb_bus_list_lock);
        return retval;
 }
 EXPORT_SYMBOL (usb_register_root_hub);
@@ -1545,11 +1579,13 @@ static void hcd_panic (void *_hcd)
        unsigned                i;
 
        /* hc's root hub is removed later removed in hcd->stop() */
-       hub->state = USB_STATE_NOTATTACHED;
+       down (&hub->serialize);
+       usb_set_device_state(hub, USB_STATE_NOTATTACHED);
        for (i = 0; i < hub->maxchild; i++) {
                if (hub->children [i])
                        usb_disconnect (&hub->children [i]);
        }
+       up (&hub->serialize);
 }
 
 /**