usb: gadget: dummy_hcd: use the shared_hcd infrastructure
authorTatyana Brokhman <tlinder@codeaurora.org>
Wed, 29 Jun 2011 13:41:51 +0000 (16:41 +0300)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 1 Jul 2011 21:27:05 +0000 (14:27 -0700)
This patch is a preparation for adding SuperSpeed
support to dummy hcd.

It takes the master side fields out of the struct
dummy to a separate structure. The init process
was also modified to resemble the way it is
done by xHCI.

Signed-off-by: Tatyana Brokhman <tlinder@codeaurora.org>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/gadget/dummy_hcd.c

index cbcb4c7fd26c02b2f5a69de3d0593557dfd63f93..fcbff1cd180c0b84cd84dee7803890096cbc5bae 100644 (file)
@@ -152,6 +152,22 @@ enum dummy_rh_state {
        DUMMY_RH_RUNNING
 };
 
+struct dummy_hcd {
+       struct dummy                    *dum;
+       enum dummy_rh_state             rh_state;
+       struct timer_list               timer;
+       u32                             port_status;
+       u32                             old_status;
+       unsigned long                   re_timeout;
+
+       struct usb_device               *udev;
+       struct list_head                urbp_list;
+
+       unsigned                        active:1;
+       unsigned                        old_active:1;
+       unsigned                        resuming:1;
+};
+
 struct dummy {
        spinlock_t                      lock;
 
@@ -167,36 +183,26 @@ struct dummy {
        u16                             devstatus;
        unsigned                        udc_suspended:1;
        unsigned                        pullup:1;
-       unsigned                        active:1;
-       unsigned                        old_active:1;
 
        /*
         * MASTER/HOST side support
         */
-       enum dummy_rh_state             rh_state;
-       struct timer_list               timer;
-       u32                             port_status;
-       u32                             old_status;
-       unsigned                        resuming:1;
-       unsigned long                   re_timeout;
-
-       struct usb_device               *udev;
-       struct list_head                urbp_list;
+       struct dummy_hcd                *hs_hcd;
 };
 
-static inline struct dummy *hcd_to_dummy (struct usb_hcd *hcd)
+static inline struct dummy_hcd *hcd_to_dummy_hcd(struct usb_hcd *hcd)
 {
-       return (struct dummy *) (hcd->hcd_priv);
+       return (struct dummy_hcd *) (hcd->hcd_priv);
 }
 
-static inline struct usb_hcd *dummy_to_hcd (struct dummy *dum)
+static inline struct usb_hcd *dummy_hcd_to_hcd(struct dummy_hcd *dum)
 {
        return container_of((void *) dum, struct usb_hcd, hcd_priv);
 }
 
-static inline struct device *dummy_dev (struct dummy *dum)
+static inline struct device *dummy_dev(struct dummy_hcd *dum)
 {
-       return dummy_to_hcd(dum)->self.controller;
+       return dummy_hcd_to_hcd(dum)->self.controller;
 }
 
 static inline struct device *udc_dev (struct dummy *dum)
@@ -209,9 +215,10 @@ static inline struct dummy *ep_to_dummy (struct dummy_ep *ep)
        return container_of (ep->gadget, struct dummy, gadget);
 }
 
-static inline struct dummy *gadget_to_dummy (struct usb_gadget *gadget)
+static inline struct dummy_hcd *gadget_to_dummy_hcd(struct usb_gadget *gadget)
 {
-       return container_of (gadget, struct dummy, gadget);
+       struct dummy *dum = container_of(gadget, struct dummy, gadget);
+       return dum->hs_hcd;
 }
 
 static inline struct dummy *gadget_dev_to_dummy (struct device *dev)
@@ -219,7 +226,7 @@ static inline struct dummy *gadget_dev_to_dummy (struct device *dev)
        return container_of (dev, struct dummy, gadget.dev);
 }
 
-static struct dummy                    *the_controller;
+static struct dummy                    the_controller;
 
 /*-------------------------------------------------------------------------*/
 
@@ -260,60 +267,64 @@ stop_activity (struct dummy *dum)
 }
 
 /* caller must hold lock */
-static void
-set_link_state (struct dummy *dum)
+static void set_link_state(struct dummy_hcd *dum_hcd)
 {
-       dum->active = 0;
-       if ((dum->port_status & USB_PORT_STAT_POWER) == 0)
-               dum->port_status = 0;
+       struct dummy *dum = dum_hcd->dum;
+
+       dum_hcd->active = 0;
+       if ((dum_hcd->port_status & USB_PORT_STAT_POWER) == 0)
+               dum_hcd->port_status = 0;
 
        /* UDC suspend must cause a disconnect */
        else if (!dum->pullup || dum->udc_suspended) {
-               dum->port_status &= ~(USB_PORT_STAT_CONNECTION |
+               dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION |
                                        USB_PORT_STAT_ENABLE |
                                        USB_PORT_STAT_LOW_SPEED |
                                        USB_PORT_STAT_HIGH_SPEED |
                                        USB_PORT_STAT_SUSPEND);
-               if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0)
-                       dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16);
+               if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0)
+                       dum_hcd->port_status |=
+                               (USB_PORT_STAT_C_CONNECTION << 16);
        } else {
-               dum->port_status |= USB_PORT_STAT_CONNECTION;
-               if ((dum->old_status & USB_PORT_STAT_CONNECTION) == 0)
-                       dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16);
-               if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0)
-                       dum->port_status &= ~USB_PORT_STAT_SUSPEND;
-               else if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
-                               dum->rh_state != DUMMY_RH_SUSPENDED)
-                       dum->active = 1;
+               dum_hcd->port_status |= USB_PORT_STAT_CONNECTION;
+               if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) == 0)
+                       dum_hcd->port_status |=
+                               (USB_PORT_STAT_C_CONNECTION << 16);
+               if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0)
+                       dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
+               else if ((dum_hcd->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
+                               dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
+                       dum_hcd->active = 1;
        }
 
-       if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0 || dum->active)
-               dum->resuming = 0;
+       if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0 ||
+            dum_hcd->active)
+               dum_hcd->resuming = 0;
 
-       if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
-                       (dum->port_status & USB_PORT_STAT_RESET) != 0) {
-               if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0 &&
-                               (dum->old_status & USB_PORT_STAT_RESET) == 0 &&
+       if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
+                       (dum_hcd->port_status & USB_PORT_STAT_RESET) != 0) {
+               if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0 &&
+                       (dum_hcd->old_status & USB_PORT_STAT_RESET) == 0 &&
                                dum->driver) {
                        stop_activity (dum);
                        spin_unlock (&dum->lock);
                        dum->driver->disconnect (&dum->gadget);
                        spin_lock (&dum->lock);
                }
-       } else if (dum->active != dum->old_active) {
-               if (dum->old_active && dum->driver->suspend) {
+       } else if (dum_hcd->active != dum_hcd->old_active) {
+               if (dum_hcd->old_active && dum->driver->suspend) {
                        spin_unlock (&dum->lock);
                        dum->driver->suspend (&dum->gadget);
                        spin_lock (&dum->lock);
-               } else if (!dum->old_active && dum->driver->resume) {
+               } else if (!dum_hcd->old_active && dum->driver->resume) {
                        spin_unlock (&dum->lock);
                        dum->driver->resume (&dum->gadget);
                        spin_lock (&dum->lock);
                }
        }
 
-       dum->old_status = dum->port_status;
-       dum->old_active = dum->active;
+       dum_hcd->old_status = dum_hcd->port_status;
+       dum_hcd->old_active = dum_hcd->active;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -332,6 +343,7 @@ static int
 dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 {
        struct dummy            *dum;
+       struct dummy_hcd        *dum_hcd;
        struct dummy_ep         *ep;
        unsigned                max;
        int                     retval;
@@ -341,9 +353,17 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
                        || desc->bDescriptorType != USB_DT_ENDPOINT)
                return -EINVAL;
        dum = ep_to_dummy (ep);
-       if (!dum->driver || !is_enabled (dum))
+       if (!dum->driver)
+               return -ESHUTDOWN;
+       dum_hcd = dum->hs_hcd;
+       if (!is_enabled(dum_hcd))
                return -ESHUTDOWN;
-       max = le16_to_cpu(desc->wMaxPacketSize) & 0x3ff;
+
+       /*
+        * For HS/FS devices only bits 0..10 of the wMaxPacketSize represent the
+        * maximum packet size.
+        */
+       max = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff;
 
        /* drivers must not request bad settings, since lower levels
         * (hardware or its drivers) may not check.  some endpoints
@@ -515,6 +535,7 @@ dummy_queue (struct usb_ep *_ep, struct usb_request *_req,
        struct dummy_ep         *ep;
        struct dummy_request    *req;
        struct dummy            *dum;
+       struct dummy_hcd        *dum_hcd;
        unsigned long           flags;
 
        req = usb_request_to_dummy_request (_req);
@@ -526,7 +547,8 @@ dummy_queue (struct usb_ep *_ep, struct usb_request *_req,
                return -EINVAL;
 
        dum = ep_to_dummy (ep);
-       if (!dum->driver || !is_enabled (dum))
+       dum_hcd = dum->hs_hcd;
+       if (!dum->driver || !is_enabled(dum_hcd))
                return -ESHUTDOWN;
 
 #if 0
@@ -670,24 +692,24 @@ static int dummy_g_get_frame (struct usb_gadget *_gadget)
 
 static int dummy_wakeup (struct usb_gadget *_gadget)
 {
-       struct dummy    *dum;
+       struct dummy_hcd *dum_hcd;
 
-       dum = gadget_to_dummy (_gadget);
-       if (!(dum->devstatus &  ( (1 << USB_DEVICE_B_HNP_ENABLE)
+       dum_hcd = gadget_to_dummy_hcd(_gadget);
+       if (!(dum_hcd->dum->devstatus & ((1 << USB_DEVICE_B_HNP_ENABLE)
                                | (1 << USB_DEVICE_REMOTE_WAKEUP))))
                return -EINVAL;
-       if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0)
+       if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0)
                return -ENOLINK;
-       if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
-                        dum->rh_state != DUMMY_RH_SUSPENDED)
+       if ((dum_hcd->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
+                        dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
                return -EIO;
 
        /* FIXME: What if the root hub is suspended but the port isn't? */
 
        /* hub notices our request, issues downstream resume, etc */
-       dum->resuming = 1;
-       dum->re_timeout = jiffies + msecs_to_jiffies(20);
-       mod_timer (&dummy_to_hcd (dum)->rh_timer, dum->re_timeout);
+       dum_hcd->resuming = 1;
+       dum_hcd->re_timeout = jiffies + msecs_to_jiffies(20);
+       mod_timer(&dummy_hcd_to_hcd(dum_hcd)->rh_timer, dum_hcd->re_timeout);
        return 0;
 }
 
@@ -695,7 +717,7 @@ static int dummy_set_selfpowered (struct usb_gadget *_gadget, int value)
 {
        struct dummy    *dum;
 
-       dum = gadget_to_dummy (_gadget);
+       dum = (gadget_to_dummy_hcd(_gadget))->dum;
        if (value)
                dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
        else
@@ -708,13 +730,12 @@ static int dummy_pullup (struct usb_gadget *_gadget, int value)
        struct dummy    *dum;
        unsigned long   flags;
 
-       dum = gadget_to_dummy (_gadget);
+       dum = gadget_to_dummy_hcd(_gadget)->dum;
        spin_lock_irqsave (&dum->lock, flags);
        dum->pullup = (value != 0);
-       set_link_state (dum);
+       set_link_state(dum->hs_hcd);
        spin_unlock_irqrestore (&dum->lock, flags);
-
-       usb_hcd_poll_rh_status (dummy_to_hcd (dum));
+       usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd));
        return 0;
 }
 
@@ -764,7 +785,7 @@ static DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
 static int dummy_udc_start(struct usb_gadget_driver *driver,
                int (*bind)(struct usb_gadget *))
 {
-       struct dummy    *dum = the_controller;
+       struct dummy    *dum = &the_controller;
        int             retval, i;
 
        if (!dum)
@@ -800,7 +821,8 @@ static int dummy_udc_start(struct usb_gadget_driver *driver,
        }
 
        dum->gadget.ep0 = &dum->ep [0].ep;
-       dum->ep [0].ep.maxpacket = 64;
+       dum->gadget.speed = min((u8)driver->speed, (u8)USB_SPEED_HIGH) ;
+       dum->ep[0].ep.maxpacket = 64;
        list_del_init (&dum->ep [0].ep.ep_list);
        INIT_LIST_HEAD(&dum->fifo_req.queue);
 
@@ -819,16 +841,18 @@ static int dummy_udc_start(struct usb_gadget_driver *driver,
        /* khubd will enumerate this in a while */
        spin_lock_irq (&dum->lock);
        dum->pullup = 1;
-       set_link_state (dum);
+       dum->gadget.is_otg =
+               (dummy_hcd_to_hcd(dum->hs_hcd)->self.otg_port != 0);
+       set_link_state(dum->hs_hcd);
        spin_unlock_irq (&dum->lock);
 
-       usb_hcd_poll_rh_status (dummy_to_hcd (dum));
+       usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd));
        return 0;
 }
 
 static int dummy_udc_stop(struct usb_gadget_driver *driver)
 {
-       struct dummy    *dum = the_controller;
+       struct dummy    *dum = &the_controller;
        unsigned long   flags;
 
        if (!dum)
@@ -841,7 +865,7 @@ static int dummy_udc_stop(struct usb_gadget_driver *driver)
 
        spin_lock_irqsave (&dum->lock, flags);
        dum->pullup = 0;
-       set_link_state (dum);
+       set_link_state(dum->hs_hcd);
        spin_unlock_irqrestore (&dum->lock, flags);
 
        driver->unbind (&dum->gadget);
@@ -850,10 +874,9 @@ static int dummy_udc_stop(struct usb_gadget_driver *driver)
 
        spin_lock_irqsave (&dum->lock, flags);
        dum->pullup = 0;
-       set_link_state (dum);
+       set_link_state(dum->hs_hcd);
        spin_unlock_irqrestore (&dum->lock, flags);
-
-       usb_hcd_poll_rh_status (dummy_to_hcd (dum));
+       usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd));
        return 0;
 }
 
@@ -874,25 +897,18 @@ EXPORT_SYMBOL (net2280_set_fifo_mode);
 static void
 dummy_gadget_release (struct device *dev)
 {
-       struct dummy    *dum = gadget_dev_to_dummy (dev);
-
-       usb_put_hcd (dummy_to_hcd (dum));
+       return;
 }
 
 static int dummy_udc_probe (struct platform_device *pdev)
 {
-       struct dummy    *dum = the_controller;
+       struct dummy    *dum = &the_controller;
        int             rc;
 
-       usb_get_hcd(dummy_to_hcd(dum));
-
        dum->gadget.name = gadget_name;
        dum->gadget.ops = &dummy_ops;
        dum->gadget.is_dualspeed = 1;
 
-       /* maybe claim OTG support, though we won't complete HNP */
-       dum->gadget.is_otg = (dummy_to_hcd(dum)->self.otg_port != 0);
-
        dev_set_name(&dum->gadget.dev, "gadget");
        dum->gadget.dev.parent = &pdev->dev;
        dum->gadget.dev.release = dummy_gadget_release;
@@ -937,10 +953,10 @@ static int dummy_udc_suspend (struct platform_device *pdev, pm_message_t state)
        dev_dbg (&pdev->dev, "%s\n", __func__);
        spin_lock_irq (&dum->lock);
        dum->udc_suspended = 1;
-       set_link_state (dum);
+       set_link_state(dum->hs_hcd);
        spin_unlock_irq (&dum->lock);
 
-       usb_hcd_poll_rh_status (dummy_to_hcd (dum));
+       usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd));
        return 0;
 }
 
@@ -951,10 +967,10 @@ static int dummy_udc_resume (struct platform_device *pdev)
        dev_dbg (&pdev->dev, "%s\n", __func__);
        spin_lock_irq (&dum->lock);
        dum->udc_suspended = 0;
-       set_link_state (dum);
+       set_link_state(dum->hs_hcd);
        spin_unlock_irq (&dum->lock);
 
-       usb_hcd_poll_rh_status (dummy_to_hcd (dum));
+       usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd));
        return 0;
 }
 
@@ -988,7 +1004,7 @@ static int dummy_urb_enqueue (
        struct urb                      *urb,
        gfp_t                           mem_flags
 ) {
-       struct dummy    *dum;
+       struct dummy_hcd *dum_hcd;
        struct urbp     *urbp;
        unsigned long   flags;
        int             rc;
@@ -1001,51 +1017,51 @@ static int dummy_urb_enqueue (
                return -ENOMEM;
        urbp->urb = urb;
 
-       dum = hcd_to_dummy (hcd);
-       spin_lock_irqsave (&dum->lock, flags);
+       dum_hcd = hcd_to_dummy_hcd(hcd);
+       spin_lock_irqsave(&dum_hcd->dum->lock, flags);
        rc = usb_hcd_link_urb_to_ep(hcd, urb);
        if (rc) {
                kfree(urbp);
                goto done;
        }
 
-       if (!dum->udev) {
-               dum->udev = urb->dev;
-               usb_get_dev (dum->udev);
-       } else if (unlikely (dum->udev != urb->dev))
-               dev_err (dummy_dev(dum), "usb_device address has changed!\n");
+       if (!dum_hcd->udev) {
+               dum_hcd->udev = urb->dev;
+               usb_get_dev(dum_hcd->udev);
+       } else if (unlikely(dum_hcd->udev != urb->dev))
+               dev_err(dummy_dev(dum_hcd), "usb_device address has changed!\n");
 
-       list_add_tail (&urbp->urbp_list, &dum->urbp_list);
+       list_add_tail(&urbp->urbp_list, &dum_hcd->urbp_list);
        urb->hcpriv = urbp;
        if (usb_pipetype (urb->pipe) == PIPE_CONTROL)
                urb->error_count = 1;           /* mark as a new urb */
 
        /* kick the scheduler, it'll do the rest */
-       if (!timer_pending (&dum->timer))
-               mod_timer (&dum->timer, jiffies + 1);
+       if (!timer_pending(&dum_hcd->timer))
+               mod_timer(&dum_hcd->timer, jiffies + 1);
 
  done:
-       spin_unlock_irqrestore(&dum->lock, flags);
+       spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
        return rc;
 }
 
 static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
-       struct dummy    *dum;
+       struct dummy_hcd *dum_hcd;
        unsigned long   flags;
        int             rc;
 
        /* giveback happens automatically in timer callback,
         * so make sure the callback happens */
-       dum = hcd_to_dummy (hcd);
-       spin_lock_irqsave (&dum->lock, flags);
+       dum_hcd = hcd_to_dummy_hcd(hcd);
+       spin_lock_irqsave(&dum_hcd->dum->lock, flags);
 
        rc = usb_hcd_check_unlink_urb(hcd, urb, status);
-       if (!rc && dum->rh_state != DUMMY_RH_RUNNING &&
-                       !list_empty(&dum->urbp_list))
-               mod_timer (&dum->timer, jiffies);
+       if (!rc && dum_hcd->rh_state != DUMMY_RH_RUNNING &&
+                       !list_empty(&dum_hcd->urbp_list))
+               mod_timer(&dum_hcd->timer, jiffies);
 
-       spin_unlock_irqrestore (&dum->lock, flags);
+       spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
        return rc;
 }
 
@@ -1185,7 +1201,7 @@ static int periodic_bytes (struct dummy *dum, struct dummy_ep *ep)
        return limit;
 }
 
-#define is_active(dum) ((dum->port_status & \
+#define is_active(dum_hcd)     ((dum_hcd->port_status & \
                (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | \
                        USB_PORT_STAT_SUSPEND)) \
                == (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE))
@@ -1194,7 +1210,7 @@ static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)
 {
        int             i;
 
-       if (!is_active (dum))
+       if (!is_active(dum->hs_hcd))
                return NULL;
        if ((address & ~USB_DIR_IN) == 0)
                return &dum->ep [0];
@@ -1231,11 +1247,12 @@ static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)
  *       1 - if the request wasn't handles
  *       error code on error
  */
-static int handle_control_request(struct dummy *dum, struct urb *urb,
+static int handle_control_request(struct dummy_hcd *dum_hcd, struct urb *urb,
                                  struct usb_ctrlrequest *setup,
                                  int *status)
 {
        struct dummy_ep         *ep2;
+       struct dummy            *dum = dum_hcd->dum;
        int                     ret_val = 1;
        unsigned        w_index;
        unsigned        w_value;
@@ -1354,9 +1371,10 @@ static int handle_control_request(struct dummy *dum, struct urb *urb,
 /* drive both sides of the transfers; looks like irq handlers to
  * both drivers except the callbacks aren't in_irq().
  */
-static void dummy_timer (unsigned long _dum)
+static void dummy_timer(unsigned long _dum_hcd)
 {
-       struct dummy            *dum = (struct dummy *) _dum;
+       struct dummy_hcd        *dum_hcd = (struct dummy_hcd *) _dum_hcd;
+       struct dummy            *dum = dum_hcd->dum;
        struct urbp             *urbp, *tmp;
        unsigned long           flags;
        int                     limit, total;
@@ -1374,7 +1392,7 @@ static void dummy_timer (unsigned long _dum)
                total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/;
                break;
        default:
-               dev_err (dummy_dev(dum), "bogus device speed\n");
+               dev_err(dummy_dev(dum_hcd), "bogus device speed\n");
                return;
        }
 
@@ -1383,8 +1401,8 @@ static void dummy_timer (unsigned long _dum)
        /* look at each urb queued by the host side driver */
        spin_lock_irqsave (&dum->lock, flags);
 
-       if (!dum->udev) {
-               dev_err (dummy_dev(dum),
+       if (!dum_hcd->udev) {
+               dev_err(dummy_dev(dum_hcd),
                                "timer fired with no URBs pending?\n");
                spin_unlock_irqrestore (&dum->lock, flags);
                return;
@@ -1397,7 +1415,7 @@ static void dummy_timer (unsigned long _dum)
        }
 
 restart:
-       list_for_each_entry_safe (urbp, tmp, &dum->urbp_list, urbp_list) {
+       list_for_each_entry_safe(urbp, tmp, &dum_hcd->urbp_list, urbp_list) {
                struct urb              *urb;
                struct dummy_request    *req;
                u8                      address;
@@ -1408,7 +1426,7 @@ restart:
                urb = urbp->urb;
                if (urb->unlinked)
                        goto return_urb;
-               else if (dum->rh_state != DUMMY_RH_RUNNING)
+               else if (dum_hcd->rh_state != DUMMY_RH_RUNNING)
                        continue;
                type = usb_pipetype (urb->pipe);
 
@@ -1426,7 +1444,7 @@ restart:
                ep = find_endpoint(dum, address);
                if (!ep) {
                        /* set_configuration() disagreement */
-                       dev_dbg (dummy_dev(dum),
+                       dev_dbg(dummy_dev(dum_hcd),
                                "no ep configured for urb %p\n",
                                urb);
                        status = -EPROTO;
@@ -1442,7 +1460,7 @@ restart:
                }
                if (ep->halted && !ep->setup_stage) {
                        /* NOTE: must not be iso! */
-                       dev_dbg (dummy_dev(dum), "ep %s halted, urb %p\n",
+                       dev_dbg(dummy_dev(dum_hcd), "ep %s halted, urb %p\n",
                                        ep->ep.name, urb);
                        status = -EPIPE;
                        goto return_urb;
@@ -1477,7 +1495,7 @@ restart:
                        ep->setup_stage = 0;
                        ep->halted = 0;
 
-                       value = handle_control_request(dum, urb, &setup,
+                       value = handle_control_request(dum_hcd, urb, &setup,
                                                       &status);
 
                        /* gadget driver handles all other requests.  block
@@ -1547,20 +1565,20 @@ return_urb:
                if (ep)
                        ep->already_seen = ep->setup_stage = 0;
 
-               usb_hcd_unlink_urb_from_ep(dummy_to_hcd(dum), urb);
+               usb_hcd_unlink_urb_from_ep(dummy_hcd_to_hcd(dum_hcd), urb);
                spin_unlock (&dum->lock);
-               usb_hcd_giveback_urb(dummy_to_hcd(dum), urb, status);
+               usb_hcd_giveback_urb(dummy_hcd_to_hcd(dum_hcd), urb, status);
                spin_lock (&dum->lock);
 
                goto restart;
        }
 
-       if (list_empty (&dum->urbp_list)) {
-               usb_put_dev (dum->udev);
-               dum->udev = NULL;
-       } else if (dum->rh_state == DUMMY_RH_RUNNING) {
+       if (list_empty(&dum_hcd->urbp_list)) {
+               usb_put_dev(dum_hcd->udev);
+               dum_hcd->udev = NULL;
+       } else if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
                /* want a 1 msec delay here */
-               mod_timer (&dum->timer, jiffies + msecs_to_jiffies(1));
+               mod_timer(&dum_hcd->timer, jiffies + msecs_to_jiffies(1));
        }
 
        spin_unlock_irqrestore (&dum->lock, flags);
@@ -1577,32 +1595,32 @@ return_urb:
 
 static int dummy_hub_status (struct usb_hcd *hcd, char *buf)
 {
-       struct dummy            *dum;
+       struct dummy_hcd        *dum_hcd;
        unsigned long           flags;
        int                     retval = 0;
 
-       dum = hcd_to_dummy (hcd);
+       dum_hcd = hcd_to_dummy_hcd(hcd);
 
-       spin_lock_irqsave (&dum->lock, flags);
+       spin_lock_irqsave(&dum_hcd->dum->lock, flags);
        if (!HCD_HW_ACCESSIBLE(hcd))
                goto done;
 
-       if (dum->resuming && time_after_eq (jiffies, dum->re_timeout)) {
-               dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
-               dum->port_status &= ~USB_PORT_STAT_SUSPEND;
-               set_link_state (dum);
+       if (dum_hcd->resuming && time_after_eq(jiffies, dum_hcd->re_timeout)) {
+               dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
+               dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
+               set_link_state(dum_hcd);
        }
 
-       if ((dum->port_status & PORT_C_MASK) != 0) {
+       if ((dum_hcd->port_status & PORT_C_MASK) != 0) {
                *buf = (1 << 1);
-               dev_dbg (dummy_dev(dum), "port status 0x%08x has changes\n",
-                               dum->port_status);
+               dev_dbg(dummy_dev(dum_hcd), "port status 0x%08x has changes\n",
+                               dum_hcd->port_status);
                retval = 1;
-               if (dum->rh_state == DUMMY_RH_SUSPENDED)
+               if (dum_hcd->rh_state == DUMMY_RH_SUSPENDED)
                        usb_hcd_resume_root_hub (hcd);
        }
 done:
-       spin_unlock_irqrestore (&dum->lock, flags);
+       spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
        return retval;
 }
 
@@ -1626,39 +1644,40 @@ static int dummy_hub_control (
        char            *buf,
        u16             wLength
 ) {
-       struct dummy    *dum;
+       struct dummy_hcd *dum_hcd;
        int             retval = 0;
        unsigned long   flags;
 
        if (!HCD_HW_ACCESSIBLE(hcd))
                return -ETIMEDOUT;
 
-       dum = hcd_to_dummy (hcd);
-       spin_lock_irqsave (&dum->lock, flags);
+       dum_hcd = hcd_to_dummy_hcd(hcd);
+
+       spin_lock_irqsave(&dum_hcd->dum->lock, flags);
        switch (typeReq) {
        case ClearHubFeature:
                break;
        case ClearPortFeature:
                switch (wValue) {
                case USB_PORT_FEAT_SUSPEND:
-                       if (dum->port_status & USB_PORT_STAT_SUSPEND) {
+                       if (dum_hcd->port_status & USB_PORT_STAT_SUSPEND) {
                                /* 20msec resume signaling */
-                               dum->resuming = 1;
-                               dum->re_timeout = jiffies +
+                               dum_hcd->resuming = 1;
+                               dum_hcd->re_timeout = jiffies +
                                                msecs_to_jiffies(20);
                        }
                        break;
                case USB_PORT_FEAT_POWER:
-                       if (dum->port_status & USB_PORT_STAT_POWER)
-                               dev_dbg (dummy_dev(dum), "power-off\n");
+                       if (dum_hcd->port_status & USB_PORT_STAT_POWER)
+                               dev_dbg(dummy_dev(dum_hcd), "power-off\n");
                        /* FALLS THROUGH */
                default:
-                       dum->port_status &= ~(1 << wValue);
-                       set_link_state (dum);
+                       dum_hcd->port_status &= ~(1 << wValue);
+                       set_link_state(dum_hcd);
                }
                break;
        case GetHubDescriptor:
-               hub_descriptor ((struct usb_hub_descriptor *) buf);
+               hub_descriptor((struct usb_hub_descriptor *) buf);
                break;
        case GetHubStatus:
                *(__le32 *) buf = cpu_to_le32 (0);
@@ -1670,39 +1689,38 @@ static int dummy_hub_control (
                /* whoever resets or resumes must GetPortStatus to
                 * complete it!!
                 */
-               if (dum->resuming &&
-                               time_after_eq (jiffies, dum->re_timeout)) {
-                       dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
-                       dum->port_status &= ~USB_PORT_STAT_SUSPEND;
+               if (dum_hcd->resuming &&
+                               time_after_eq(jiffies, dum_hcd->re_timeout)) {
+                       dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
+                       dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
                }
-               if ((dum->port_status & USB_PORT_STAT_RESET) != 0 &&
-                               time_after_eq (jiffies, dum->re_timeout)) {
-                       dum->port_status |= (USB_PORT_STAT_C_RESET << 16);
-                       dum->port_status &= ~USB_PORT_STAT_RESET;
-                       if (dum->pullup) {
-                               dum->port_status |= USB_PORT_STAT_ENABLE;
-                               /* give it the best speed we agree on */
-                               dum->gadget.speed = dum->driver->speed;
-                               dum->gadget.ep0->maxpacket = 64;
-                               switch (dum->gadget.speed) {
+               if ((dum_hcd->port_status & USB_PORT_STAT_RESET) != 0 &&
+                               time_after_eq(jiffies, dum_hcd->re_timeout)) {
+                       dum_hcd->port_status |= (USB_PORT_STAT_C_RESET << 16);
+                       dum_hcd->port_status &= ~USB_PORT_STAT_RESET;
+                       if (dum_hcd->dum->pullup) {
+                               dum_hcd->port_status |= USB_PORT_STAT_ENABLE;
+                               switch (dum_hcd->dum->gadget.speed) {
                                case USB_SPEED_HIGH:
-                                       dum->port_status |=
-                                               USB_PORT_STAT_HIGH_SPEED;
+                                       dum_hcd->port_status |=
+                                             USB_PORT_STAT_HIGH_SPEED;
                                        break;
                                case USB_SPEED_LOW:
-                                       dum->gadget.ep0->maxpacket = 8;
-                                       dum->port_status |=
+                                       dum_hcd->dum->gadget.ep0->
+                                               maxpacket = 8;
+                                       dum_hcd->port_status |=
                                                USB_PORT_STAT_LOW_SPEED;
                                        break;
                                default:
-                                       dum->gadget.speed = USB_SPEED_FULL;
+                                       dum_hcd->dum->gadget.speed =
+                                               USB_SPEED_FULL;
                                        break;
                                }
                        }
                }
-               set_link_state (dum);
-               ((__le16 *) buf)[0] = cpu_to_le16 (dum->port_status);
-               ((__le16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16);
+               set_link_state(dum_hcd);
+               ((__le16 *) buf)[0] = cpu_to_le16 (dum_hcd->port_status);
+               ((__le16 *) buf)[1] = cpu_to_le16 (dum_hcd->port_status >> 16);
                break;
        case SetHubFeature:
                retval = -EPIPE;
@@ -1710,87 +1728,91 @@ static int dummy_hub_control (
        case SetPortFeature:
                switch (wValue) {
                case USB_PORT_FEAT_SUSPEND:
-                       if (dum->active) {
-                               dum->port_status |= USB_PORT_STAT_SUSPEND;
+                       if (dum_hcd->active) {
+                               dum_hcd->port_status |= USB_PORT_STAT_SUSPEND;
 
                                /* HNP would happen here; for now we
                                 * assume b_bus_req is always true.
                                 */
-                               set_link_state (dum);
+                               set_link_state(dum_hcd);
                                if (((1 << USB_DEVICE_B_HNP_ENABLE)
-                                               & dum->devstatus) != 0)
-                                       dev_dbg (dummy_dev(dum),
+                                               & dum_hcd->dum->devstatus) != 0)
+                                       dev_dbg(dummy_dev(dum_hcd),
                                                        "no HNP yet!\n");
                        }
                        break;
                case USB_PORT_FEAT_POWER:
-                       dum->port_status |= USB_PORT_STAT_POWER;
-                       set_link_state (dum);
+                       dum_hcd->port_status |= USB_PORT_STAT_POWER;
+                       set_link_state(dum_hcd);
                        break;
                case USB_PORT_FEAT_RESET:
                        /* if it's already enabled, disable */
-                       dum->port_status &= ~(USB_PORT_STAT_ENABLE
+                       dum_hcd->port_status &= ~(USB_PORT_STAT_ENABLE
                                        | USB_PORT_STAT_LOW_SPEED
                                        | USB_PORT_STAT_HIGH_SPEED);
-                       dum->devstatus = 0;
-                       /* 50msec reset signaling */
-                       dum->re_timeout = jiffies + msecs_to_jiffies(50);
+                       /*
+                        * We want to reset device status. All but the
+                        * Self powered feature
+                        */
+                       dum_hcd->dum->devstatus &=
+                               (1 << USB_DEVICE_SELF_POWERED);
+                       dum_hcd->re_timeout = jiffies + msecs_to_jiffies(50);
                        /* FALLS THROUGH */
                default:
-                       if ((dum->port_status & USB_PORT_STAT_POWER) != 0) {
-                               dum->port_status |= (1 << wValue);
-                               set_link_state (dum);
+                       if ((dum_hcd->port_status &
+                            USB_PORT_STAT_POWER) != 0) {
+                               dum_hcd->port_status |= (1 << wValue);
+                               set_link_state(dum_hcd);
                        }
                }
                break;
 
        default:
-               dev_dbg (dummy_dev(dum),
+               dev_dbg(dummy_dev(dum_hcd),
                        "hub control req%04x v%04x i%04x l%d\n",
                        typeReq, wValue, wIndex, wLength);
-
                /* "protocol stall" on error */
                retval = -EPIPE;
        }
-       spin_unlock_irqrestore (&dum->lock, flags);
+       spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
 
-       if ((dum->port_status & PORT_C_MASK) != 0)
+       if ((dum_hcd->port_status & PORT_C_MASK) != 0)
                usb_hcd_poll_rh_status (hcd);
        return retval;
 }
 
 static int dummy_bus_suspend (struct usb_hcd *hcd)
 {
-       struct dummy *dum = hcd_to_dummy (hcd);
+       struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
 
        dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__);
 
-       spin_lock_irq (&dum->lock);
-       dum->rh_state = DUMMY_RH_SUSPENDED;
-       set_link_state (dum);
+       spin_lock_irq(&dum_hcd->dum->lock);
+       dum_hcd->rh_state = DUMMY_RH_SUSPENDED;
+       set_link_state(dum_hcd);
        hcd->state = HC_STATE_SUSPENDED;
-       spin_unlock_irq (&dum->lock);
+       spin_unlock_irq(&dum_hcd->dum->lock);
        return 0;
 }
 
 static int dummy_bus_resume (struct usb_hcd *hcd)
 {
-       struct dummy *dum = hcd_to_dummy (hcd);
+       struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
        int rc = 0;
 
        dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__);
 
-       spin_lock_irq (&dum->lock);
+       spin_lock_irq(&dum_hcd->dum->lock);
        if (!HCD_HW_ACCESSIBLE(hcd)) {
                rc = -ESHUTDOWN;
        } else {
-               dum->rh_state = DUMMY_RH_RUNNING;
-               set_link_state (dum);
-               if (!list_empty(&dum->urbp_list))
-                       mod_timer (&dum->timer, jiffies);
+               dum_hcd->rh_state = DUMMY_RH_RUNNING;
+               set_link_state(dum_hcd);
+               if (!list_empty(&dum_hcd->urbp_list))
+                       mod_timer(&dum_hcd->timer, jiffies);
                hcd->state = HC_STATE_RUNNING;
        }
-       spin_unlock_irq (&dum->lock);
+       spin_unlock_irq(&dum_hcd->dum->lock);
        return rc;
 }
 
@@ -1842,43 +1864,41 @@ static ssize_t
 show_urbs (struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct usb_hcd          *hcd = dev_get_drvdata (dev);
-       struct dummy            *dum = hcd_to_dummy (hcd);
+       struct dummy_hcd        *dum_hcd = hcd_to_dummy_hcd(hcd);
        struct urbp             *urbp;
        size_t                  size = 0;
        unsigned long           flags;
 
-       spin_lock_irqsave (&dum->lock, flags);
-       list_for_each_entry (urbp, &dum->urbp_list, urbp_list) {
+       spin_lock_irqsave(&dum_hcd->dum->lock, flags);
+       list_for_each_entry(urbp, &dum_hcd->urbp_list, urbp_list) {
                size_t          temp;
 
                temp = show_urb (buf, PAGE_SIZE - size, urbp->urb);
                buf += temp;
                size += temp;
        }
-       spin_unlock_irqrestore (&dum->lock, flags);
+       spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
 
        return size;
 }
 static DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL);
 
-static int dummy_start (struct usb_hcd *hcd)
+static int dummy_start(struct usb_hcd *hcd)
 {
-       struct dummy            *dum;
-
-       dum = hcd_to_dummy (hcd);
+       struct dummy_hcd        *dum_hcd = hcd_to_dummy_hcd(hcd);
 
        /*
         * MASTER side init ... we emulate a root hub that'll only ever
         * talk to one device (the slave side).  Also appears in sysfs,
         * just like more familiar pci-based HCDs.
         */
-       spin_lock_init (&dum->lock);
-       init_timer (&dum->timer);
-       dum->timer.function = dummy_timer;
-       dum->timer.data = (unsigned long) dum;
-       dum->rh_state = DUMMY_RH_RUNNING;
+       spin_lock_init(&dum_hcd->dum->lock);
+       init_timer(&dum_hcd->timer);
+       dum_hcd->timer.function = dummy_timer;
+       dum_hcd->timer.data = (unsigned long)dum_hcd;
+       dum_hcd->rh_state = DUMMY_RH_RUNNING;
 
-       INIT_LIST_HEAD (&dum->urbp_list);
+       INIT_LIST_HEAD(&dum_hcd->urbp_list);
 
        hcd->power_budget = POWER_BUDGET;
        hcd->state = HC_STATE_RUNNING;
@@ -1889,17 +1909,17 @@ static int dummy_start (struct usb_hcd *hcd)
 #endif
 
        /* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
-       return device_create_file (dummy_dev(dum), &dev_attr_urbs);
+       return device_create_file(dummy_dev(dum_hcd), &dev_attr_urbs);
 }
 
 static void dummy_stop (struct usb_hcd *hcd)
 {
        struct dummy            *dum;
 
-       dum = hcd_to_dummy (hcd);
-
-       device_remove_file (dummy_dev(dum), &dev_attr_urbs);
-       dev_info (dummy_dev(dum), "stopped\n");
+       dum = (hcd_to_dummy_hcd(hcd))->dum;
+       device_remove_file(dummy_dev(hcd_to_dummy_hcd(hcd)), &dev_attr_urbs);
+       usb_gadget_unregister_driver(dum->driver);
+       dev_info(dummy_dev(hcd_to_dummy_hcd(hcd)), "stopped\n");
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1909,13 +1929,26 @@ static int dummy_h_get_frame (struct usb_hcd *hcd)
        return dummy_g_get_frame (NULL);
 }
 
+static int dummy_setup(struct usb_hcd *hcd)
+{
+       if (usb_hcd_is_primary_hcd(hcd)) {
+               the_controller.hs_hcd = hcd_to_dummy_hcd(hcd);
+               the_controller.hs_hcd->dum = &the_controller;
+               /* Mark the first roothub as being USB 2.0. */
+               hcd->speed = HCD_USB2;
+               hcd->self.root_hub->speed = USB_SPEED_HIGH;
+       }
+       return 0;
+}
+
 static const struct hc_driver dummy_hcd = {
        .description =          (char *) driver_name,
        .product_desc =         "Dummy host controller",
-       .hcd_priv_size =        sizeof(struct dummy),
+       .hcd_priv_size =        sizeof(struct dummy_hcd),
 
        .flags =                HCD_USB2,
 
+       .reset =                dummy_setup,
        .start =                dummy_start,
        .stop =                 dummy_stop,
 
@@ -1932,47 +1965,47 @@ static const struct hc_driver dummy_hcd = {
 
 static int dummy_hcd_probe(struct platform_device *pdev)
 {
-       struct usb_hcd          *hcd;
+       struct usb_hcd          *hs_hcd;
        int                     retval;
 
        dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
 
-       hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev));
-       if (!hcd)
+       hs_hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev));
+       if (!hs_hcd)
                return -ENOMEM;
-       the_controller = hcd_to_dummy (hcd);
-       hcd->has_tt = 1;
+       hs_hcd->has_tt = 1;
 
-       retval = usb_add_hcd(hcd, 0, 0);
+       retval = usb_add_hcd(hs_hcd, 0, 0);
        if (retval != 0) {
-               usb_put_hcd (hcd);
-               the_controller = NULL;
+               usb_put_hcd(hs_hcd);
+               the_controller.hs_hcd = NULL;
        }
        return retval;
 }
 
-static int dummy_hcd_remove (struct platform_device *pdev)
+static int dummy_hcd_remove(struct platform_device *pdev)
 {
-       struct usb_hcd          *hcd;
+       struct dummy            *dum;
+
+       dum = (hcd_to_dummy_hcd(platform_get_drvdata(pdev)))->dum;
+       usb_remove_hcd(dummy_hcd_to_hcd(dum->hs_hcd));
+       usb_put_hcd(dummy_hcd_to_hcd(dum->hs_hcd));
+       the_controller.hs_hcd = NULL;
 
-       hcd = platform_get_drvdata (pdev);
-       usb_remove_hcd (hcd);
-       usb_put_hcd (hcd);
-       the_controller = NULL;
        return 0;
 }
 
 static int dummy_hcd_suspend (struct platform_device *pdev, pm_message_t state)
 {
        struct usb_hcd          *hcd;
-       struct dummy            *dum;
+       struct dummy_hcd        *dum_hcd;
        int                     rc = 0;
 
        dev_dbg (&pdev->dev, "%s\n", __func__);
 
        hcd = platform_get_drvdata (pdev);
-       dum = hcd_to_dummy (hcd);
-       if (dum->rh_state == DUMMY_RH_RUNNING) {
+       dum_hcd = hcd_to_dummy_hcd(hcd);
+       if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
                dev_warn(&pdev->dev, "Root hub isn't suspended!\n");
                rc = -EBUSY;
        } else
@@ -2032,7 +2065,7 @@ static int __init init (void)
        retval = platform_device_add(the_hcd_pdev);
        if (retval < 0)
                goto err_add_hcd;
-       if (!the_controller) {
+       if (!the_controller.hs_hcd) {
                /*
                 * The hcd was added successfully but its probe function failed
                 * for some reason.