diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2005-05-03 16:15:43 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2005-06-27 14:43:52 -0700 |
commit | d9b762510c186584a6be0d3ece03e8a4b2ac13a8 (patch) | |
tree | 23cd5e51145e4a11ad669a5f6ddca20b0fd7272f /drivers/usb/gadget | |
parent | c2db8b5e5692a6f35913a829607ee6efde3c7cbd (diff) | |
download | op-kernel-dev-d9b762510c186584a6be0d3ece03e8a4b2ac13a8.zip op-kernel-dev-d9b762510c186584a6be0d3ece03e8a4b2ac13a8.tar.gz |
[PATCH] USB dummy_hcd: Use separate pdevs for HC and UDC
This patch makes the dummy_hcd driver create separate platform devices for
the emulated host controller and emulated device controller. This gives a
more accurate simulation and will permit testing of situations where only
one of the two devices is suspended.
This also changes the name of the host controller platform device to match
the name of the driver. That way the normal platform bus probe mechanism
will handle binding the driver to the device.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r-- | drivers/usb/gadget/dummy_hcd.c | 231 |
1 files changed, 133 insertions, 98 deletions
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index ffedf4d..dc0e323 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -141,6 +141,8 @@ static const char *const ep_name [] = { }; #define DUMMY_ENDPOINTS (sizeof(ep_name)/sizeof(char *)) +/*-------------------------------------------------------------------------*/ + #define FIFO_SIZE 64 struct urbp { @@ -189,6 +191,11 @@ static inline struct device *dummy_dev (struct dummy *dum) 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); @@ -208,19 +215,6 @@ static struct dummy *the_controller; /*-------------------------------------------------------------------------*/ -/* - * 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 @@ -324,7 +318,7 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) _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", @@ -379,7 +373,7 @@ static int dummy_disable (struct usb_ep *_ep) 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; } @@ -474,7 +468,7 @@ dummy_queue (struct usb_ep *_ep, struct usb_request *_req, int mem_flags) 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 @@ -537,7 +531,7 @@ static int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req) 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); @@ -661,38 +655,6 @@ DEVICE_ATTR (function, S_IRUGO, show_function, NULL); * 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) { @@ -711,12 +673,6 @@ 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; @@ -745,7 +701,7 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver) 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; @@ -798,7 +754,7 @@ usb_gadget_unregister_driver (struct usb_gadget_driver *driver) 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); @@ -826,6 +782,64 @@ int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode) } 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 @@ -1184,7 +1198,7 @@ restart: 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); @@ -1207,7 +1221,7 @@ restart: 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; @@ -1333,7 +1347,7 @@ restart: 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); @@ -1561,7 +1575,7 @@ static int dummy_hub_control ( | 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); } @@ -1643,7 +1657,6 @@ static DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL); static int dummy_start (struct usb_hcd *hcd) { struct dummy *dum; - int retval; dum = hcd_to_dummy (hcd); @@ -1659,9 +1672,6 @@ static int dummy_start (struct usb_hcd *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; @@ -1682,10 +1692,7 @@ static void dummy_stop (struct usb_hcd *hcd) 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"); } @@ -1715,7 +1722,7 @@ static const struct hc_driver dummy_hcd = { .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; @@ -1735,7 +1742,7 @@ static int dummy_probe (struct device *dev) return retval; } -static void dummy_remove (struct device *dev) +static int dummy_hcd_remove (struct device *dev) { struct usb_hcd *hcd; @@ -1743,35 +1750,41 @@ static void dummy_remove (struct device *dev) 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) { @@ -1779,17 +1792,39 @@ 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); |