};
 #define DUMMY_ENDPOINTS        (sizeof(ep_name)/sizeof(char *))
 
+/*-------------------------------------------------------------------------*/
+
 #define FIFO_SIZE              64
 
 struct urbp {
        return dummy_to_hcd(dum)->self.controller;
 }
 
+static inline struct device *udc_dev (struct dummy *dum)
+{
+       return dum->gadget.dev.parent;
+}
+
 static inline struct dummy *ep_to_dummy (struct dummy_ep *ep)
 {
        return container_of (ep->gadget, struct dummy, gadget);
 
 /*-------------------------------------------------------------------------*/
 
-/*
- * This "hardware" may look a bit odd in diagnostics since it's got both
- * host and device sides; and it binds different drivers to each side.
- */
-static struct platform_device          the_pdev;
-
-static struct device_driver dummy_driver = {
-       .name           = (char *) driver_name,
-       .bus            = &platform_bus_type,
-};
-
-/*-------------------------------------------------------------------------*/
-
 /* SLAVE/GADGET SIDE DRIVER
  *
  * This only tracks gadget state.  All the work is done when the host
        _ep->maxpacket = max;
        ep->desc = desc;
 
-       dev_dbg (dummy_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d\n",
+       dev_dbg (udc_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d\n",
                _ep->name,
                desc->bEndpointAddress & 0x0f,
                (desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
        nuke (dum, ep);
        spin_unlock_irqrestore (&dum->lock, flags);
 
-       dev_dbg (dummy_dev(dum), "disabled %s\n", _ep->name);
+       dev_dbg (udc_dev(dum), "disabled %s\n", _ep->name);
        return retval;
 }
 
                return -ESHUTDOWN;
 
 #if 0
-       dev_dbg (dummy_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n",
+       dev_dbg (udc_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n",
                        ep, _req, _ep->name, _req->length, _req->buf);
 #endif
 
        spin_unlock_irqrestore (&dum->lock, flags);
 
        if (retval == 0) {
-               dev_dbg (dummy_dev(dum),
+               dev_dbg (udc_dev(dum),
                                "dequeued req %p from %s, len %d buf %p\n",
                                req, _ep->name, _req->length, _req->buf);
                _req->complete (_ep, _req);
  * for each driver that registers:  just add to a big root hub.
  */
 
-/* This doesn't need to do anything because the udc device structure is
- * stored inside the hcd and will be deallocated along with it. */
-static void
-dummy_udc_release (struct device *dev) {}
-
-/* This doesn't need to do anything because the pdev structure is
- * statically allocated. */
-static void
-dummy_pdev_release (struct device *dev) {}
-
-static int
-dummy_register_udc (struct dummy *dum)
-{
-       int             rc;
-
-       strcpy (dum->gadget.dev.bus_id, "udc");
-       dum->gadget.dev.parent = dummy_dev(dum);
-       dum->gadget.dev.release = dummy_udc_release;
-
-       rc = device_register (&dum->gadget.dev);
-       if (rc == 0)
-               device_create_file (&dum->gadget.dev, &dev_attr_function);
-       return rc;
-}
-
-static void
-dummy_unregister_udc (struct dummy *dum)
-{
-       device_remove_file (&dum->gadget.dev, &dev_attr_function);
-       device_unregister (&dum->gadget.dev);
-}
-
 int
 usb_gadget_register_driver (struct usb_gadget_driver *driver)
 {
         * SLAVE side init ... the layer above hardware, which
         * can't enumerate without help from the driver we're binding.
         */
-       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);
 
        dum->devstatus = 0;
        dum->resuming = 0;
 
        dum->driver = driver;
        dum->gadget.dev.driver = &driver->driver;
-       dev_dbg (dummy_dev(dum), "binding gadget driver '%s'\n",
+       dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n",
                        driver->driver.name);
        if ((retval = driver->bind (&dum->gadget)) != 0) {
                dum->driver = NULL;
        if (!driver || driver != dum->driver)
                return -EINVAL;
 
-       dev_dbg (dummy_dev(dum), "unregister gadget driver '%s'\n",
+       dev_dbg (udc_dev(dum), "unregister gadget driver '%s'\n",
                        driver->driver.name);
 
        spin_lock_irqsave (&dum->lock, flags);
 }
 EXPORT_SYMBOL (net2280_set_fifo_mode);
 
+
+/* The gadget structure is stored inside the hcd structure and will be
+ * released along with it. */
+static void
+dummy_gadget_release (struct device *dev)
+{
+#if 0          /* usb_bus_put isn't EXPORTed! */
+       struct dummy    *dum = gadget_dev_to_dummy (dev);
+
+       usb_bus_put (&dummy_to_hcd (dum)->self);
+#endif
+}
+
+static int dummy_udc_probe (struct device *dev)
+{
+       struct dummy    *dum = the_controller;
+       int             rc;
+
+       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);
+
+       strcpy (dum->gadget.dev.bus_id, "gadget");
+       dum->gadget.dev.parent = dev;
+       dum->gadget.dev.release = dummy_gadget_release;
+       rc = device_register (&dum->gadget.dev);
+       if (rc < 0)
+               return rc;
+
+#if 0          /* usb_bus_get isn't EXPORTed! */
+       usb_bus_get (&dummy_to_hcd (dum)->self);
+#endif
+
+       dev_set_drvdata (dev, dum);
+       device_create_file (&dum->gadget.dev, &dev_attr_function);
+       return rc;
+}
+
+static int dummy_udc_remove (struct device *dev)
+{
+       struct dummy    *dum = dev_get_drvdata (dev);
+
+       dev_set_drvdata (dev, NULL);
+       device_remove_file (&dum->gadget.dev, &dev_attr_function);
+       device_unregister (&dum->gadget.dev);
+       return 0;
+}
+
+static struct device_driver dummy_udc_driver = {
+       .name           = (char *) gadget_name,
+       .bus            = &platform_bus_type,
+       .probe          = dummy_udc_probe,
+       .remove         = dummy_udc_remove,
+};
+
 /*-------------------------------------------------------------------------*/
 
 /* MASTER/HOST SIDE DRIVER
                        list_for_each_entry (req, &ep->queue, queue) {
                                list_del_init (&req->queue);
                                req->req.status = -EOVERFLOW;
-                               dev_dbg (dummy_dev(dum), "stale req = %p\n",
+                               dev_dbg (udc_dev(dum), "stale req = %p\n",
                                                req);
 
                                spin_unlock (&dum->lock);
                                        break;
                                dum->address = setup.wValue;
                                maybe_set_status (urb, 0);
-                               dev_dbg (dummy_dev(dum), "set_address = %d\n",
+                               dev_dbg (udc_dev(dum), "set_address = %d\n",
                                                setup.wValue);
                                value = 0;
                                break;
 
                        if (value < 0) {
                                if (value != -EOPNOTSUPP)
-                                       dev_dbg (dummy_dev(dum),
+                                       dev_dbg (udc_dev(dum),
                                                "setup --> %d\n",
                                                value);
                                maybe_set_status (urb, -EPIPE);
                                                | USB_PORT_STAT_LOW_SPEED
                                                | USB_PORT_STAT_HIGH_SPEED);
                                if (dum->driver) {
-                                       dev_dbg (dummy_dev(dum),
+                                       dev_dbg (udc_dev(dum),
                                                        "disconnect\n");
                                        stop_activity (dum, dum->driver);
                                }
 static int dummy_start (struct usb_hcd *hcd)
 {
        struct dummy            *dum;
-       int                     retval;
 
        dum = hcd_to_dummy (hcd);
 
 
        INIT_LIST_HEAD (&dum->urbp_list);
 
-       if ((retval = dummy_register_udc (dum)) != 0)
-               return retval;
-
        /* only show a low-power port: just 8mA */
        hcd->power_budget = 8;
        hcd->state = HC_STATE_RUNNING;
        dum = hcd_to_dummy (hcd);
 
        device_remove_file (dummy_dev(dum), &dev_attr_urbs);
-
        usb_gadget_unregister_driver (dum->driver);
-       dummy_unregister_udc (dum);
-
        dev_info (dummy_dev(dum), "stopped\n");
 }
 
        .hub_control =          dummy_hub_control,
 };
 
-static int dummy_probe (struct device *dev)
+static int dummy_hcd_probe (struct device *dev)
 {
        struct usb_hcd          *hcd;
        int                     retval;
        return retval;
 }
 
-static void dummy_remove (struct device *dev)
+static int dummy_hcd_remove (struct device *dev)
 {
        struct usb_hcd          *hcd;
 
        usb_remove_hcd (hcd);
        usb_put_hcd (hcd);
        the_controller = NULL;
+       return 0;
 }
 
-/*-------------------------------------------------------------------------*/
-
-static int dummy_pdev_detect (void)
-{
-       int                     retval;
-
-       retval = driver_register (&dummy_driver);
-       if (retval < 0)
-               return retval;
+static struct device_driver dummy_hcd_driver = {
+       .name           = (char *) driver_name,
+       .bus            = &platform_bus_type,
+       .probe          = dummy_hcd_probe,
+       .remove         = dummy_hcd_remove,
+};
 
-       the_pdev.name = "hc";
-       the_pdev.dev.driver = &dummy_driver;
-       the_pdev.dev.release = dummy_pdev_release;
+/*-------------------------------------------------------------------------*/
 
-       retval = platform_device_register (&the_pdev);
-       if (retval < 0)
-               driver_unregister (&dummy_driver);
-       return retval;
-}
+/* These don't need to do anything because the pdev structures are
+ * statically allocated. */
+static void
+dummy_udc_release (struct device *dev) {}
 
-static void dummy_pdev_remove (void)
-{
-       platform_device_unregister (&the_pdev);
-       driver_unregister (&dummy_driver);
-}
+static void
+dummy_hcd_release (struct device *dev) {}
+
+static struct platform_device          the_udc_pdev = {
+       .name           = (char *) gadget_name,
+       .id             = -1,
+       .dev            = {
+               .release        = dummy_udc_release,
+       },
+};
 
-/*-------------------------------------------------------------------------*/
+static struct platform_device          the_hcd_pdev = {
+       .name           = (char *) driver_name,
+       .id             = -1,
+       .dev            = {
+               .release        = dummy_hcd_release,
+       },
+};
 
 static int __init init (void)
 {
 
        if (usb_disabled ())
                return -ENODEV;
-       if ((retval = dummy_pdev_detect ()) != 0)
+
+       retval = driver_register (&dummy_hcd_driver);
+       if (retval < 0)
                return retval;
-       if ((retval = dummy_probe (&the_pdev.dev)) != 0)
-               dummy_pdev_remove ();
+
+       retval = driver_register (&dummy_udc_driver);
+       if (retval < 0)
+               goto err_register_udc_driver;
+
+       retval = platform_device_register (&the_hcd_pdev);
+       if (retval < 0)
+               goto err_register_hcd;
+
+       retval = platform_device_register (&the_udc_pdev);
+       if (retval < 0)
+               goto err_register_udc;
+       return retval;
+
+err_register_udc:
+       platform_device_unregister (&the_hcd_pdev);
+err_register_hcd:
+       driver_unregister (&dummy_udc_driver);
+err_register_udc_driver:
+       driver_unregister (&dummy_hcd_driver);
        return retval;
 }
 module_init (init);
 
 static void __exit cleanup (void)
 {
-       dummy_remove (&the_pdev.dev);
-       dummy_pdev_remove ();
+       platform_device_unregister (&the_udc_pdev);
+       platform_device_unregister (&the_hcd_pdev);
+       driver_unregister (&dummy_udc_driver);
+       driver_unregister (&dummy_hcd_driver);
 }
 module_exit (cleanup);