#define DRIVER_DESC "USB Host+Gadget Emulator"
-#define DRIVER_VERSION "29 Oct 2004"
+#define DRIVER_VERSION "14 Mar 2004"
static const char driver_name [] = "dummy_hcd";
static const char driver_desc [] = "USB Host+Gadget Emulator";
struct usb_request req;
};
-static inline struct dummy_ep *usb_ep_to_dummy_ep (struct usb_ep *_ep)
-{
- return container_of (_ep, struct dummy_ep, ep);
-}
-
-static inline struct dummy_request *usb_request_to_dummy_request
- (struct usb_request *_req)
-{
- return container_of (_req, struct dummy_request, req);
-}
-
/*-------------------------------------------------------------------------*/
/*
#define FIFO_SIZE 64
struct dummy {
- struct usb_hcd hcd; /* must come first! */
spinlock_t lock;
/*
/*
* MASTER/HOST side support
*/
+ struct usb_hcd hcd;
+ struct platform_device pdev;
struct timer_list timer;
u32 port_status;
- unsigned started:1;
+ int started;
+ struct completion released;
unsigned resuming:1;
unsigned long re_timeout;
struct usb_device *udev;
};
-static inline struct dummy *hcd_to_dummy (struct usb_hcd *hcd)
-{
- return container_of(hcd, struct dummy, hcd);
-}
-
-static inline struct device *dummy_dev (struct dummy *dum)
-{
- return dum->hcd.self.controller;
-}
+static struct dummy *the_controller;
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)
-{
- return container_of (gadget, struct dummy, gadget);
-}
-
static inline struct dummy *gadget_dev_to_dummy (struct device *dev)
{
return container_of (dev, struct dummy, gadget.dev);
}
-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;
+#define hardware (&the_controller->pdev.dev)
+
+/*-------------------------------------------------------------------------*/
static struct device_driver dummy_driver = {
.name = (char *) driver_name,
* drivers would do real i/o using dma, fifos, irqs, timers, etc.
*/
-#define is_enabled(dum) \
- (dum->port_status & USB_PORT_STAT_ENABLE)
+#define is_enabled() \
+ (the_controller->port_status & USB_PORT_STAT_ENABLE)
static int
dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
unsigned max;
int retval;
- ep = usb_ep_to_dummy_ep (_ep);
+ ep = container_of (_ep, struct dummy_ep, ep);
if (!_ep || !desc || ep->desc || _ep->name == ep0name
|| desc->bDescriptorType != USB_DT_ENDPOINT)
- return -EINVAL;
- dum = ep_to_dummy (ep);
- if (!dum->driver || !is_enabled (dum))
+ if (!the_controller->driver || !is_enabled ())
return -ESHUTDOWN;
max = desc->wMaxPacketSize & 0x3ff;
* have some extra sanity checks. (there could be more though,
* especially for "ep9out" style fixed function ones.)
*/
+ dum = container_of (ep->gadget, struct dummy, gadget);
retval = -EINVAL;
switch (desc->bmAttributes & 0x03) {
case USB_ENDPOINT_XFER_BULK:
_ep->maxpacket = max;
ep->desc = desc;
- dev_dbg (dummy_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d\n",
+ dev_dbg (hardware, "enabled %s (ep%d%s-%s) maxpacket %d\n",
_ep->name,
desc->bEndpointAddress & 0x0f,
(desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
unsigned long flags;
int retval;
- ep = usb_ep_to_dummy_ep (_ep);
+ ep = container_of (_ep, struct dummy_ep, ep);
if (!_ep || !ep->desc || _ep->name == ep0name)
return -EINVAL;
dum = ep_to_dummy (ep);
nuke (dum, ep);
spin_unlock_irqrestore (&dum->lock, flags);
- dev_dbg (dummy_dev(dum), "disabled %s\n", _ep->name);
+ dev_dbg (hardware, "disabled %s\n", _ep->name);
return retval;
}
struct dummy_ep *ep;
struct dummy_request *req;
+ ep = container_of (_ep, struct dummy_ep, ep);
if (!_ep)
return 0;
- ep = usb_ep_to_dummy_ep (_ep);
req = kmalloc (sizeof *req, mem_flags);
if (!req)
struct dummy_ep *ep;
struct dummy_request *req;
- ep = usb_ep_to_dummy_ep (_ep);
+ ep = container_of (_ep, struct dummy_ep, ep);
if (!ep || !_req || (!ep->desc && _ep->name != ep0name))
return;
- req = usb_request_to_dummy_request (_req);
+ req = container_of (_req, struct dummy_request, req);
WARN_ON (!list_empty (&req->queue));
kfree (req);
}
dma_addr_t *dma,
int mem_flags
) {
- char *retval;
- struct dummy_ep *ep;
- struct dummy *dum;
-
- ep = usb_ep_to_dummy_ep (_ep);
- dum = ep_to_dummy (ep);
+ char *retval;
- if (!dum->driver)
+ if (!the_controller->driver)
return 0;
retval = kmalloc (bytes, mem_flags);
*dma = (dma_addr_t) retval;
static void
fifo_complete (struct usb_ep *ep, struct usb_request *req)
{
+#if 0
+ dev_dbg (hardware, "fifo_complete: %d\n", req->status);
+#endif
}
static int
struct dummy *dum;
unsigned long flags;
- req = usb_request_to_dummy_request (_req);
+ req = container_of (_req, struct dummy_request, req);
if (!_req || !list_empty (&req->queue) || !_req->complete)
return -EINVAL;
- ep = usb_ep_to_dummy_ep (_ep);
+ ep = container_of (_ep, struct dummy_ep, ep);
if (!_ep || (!ep->desc && _ep->name != ep0name))
return -EINVAL;
- dum = ep_to_dummy (ep);
- if (!dum->driver || !is_enabled (dum))
+ if (!the_controller->driver || !is_enabled ())
return -ESHUTDOWN;
+ dum = container_of (ep->gadget, struct dummy, gadget);
+
#if 0
- dev_dbg (dummy_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n",
+ dev_dbg (hardware, "ep %p queue req %p to %s, len %d buf %p\n",
ep, _req, _ep->name, _req->length, _req->buf);
#endif
unsigned long flags;
struct dummy_request *req = 0;
+ if (!the_controller->driver)
+ return -ESHUTDOWN;
+
if (!_ep || !_req)
return retval;
- ep = usb_ep_to_dummy_ep (_ep);
- dum = ep_to_dummy (ep);
-
- if (!dum->driver)
- return -ESHUTDOWN;
+ ep = container_of (_ep, struct dummy_ep, ep);
+ dum = container_of (ep->gadget, struct dummy, gadget);
spin_lock_irqsave (&dum->lock, flags);
list_for_each_entry (req, &ep->queue, queue) {
spin_unlock_irqrestore (&dum->lock, flags);
if (retval == 0) {
- dev_dbg (dummy_dev(dum),
- "dequeued req %p from %s, len %d buf %p\n",
+ dev_dbg (hardware, "dequeued req %p from %s, len %d buf %p\n",
req, _ep->name, _req->length, _req->buf);
+
_req->complete (_ep, _req);
}
return retval;
dummy_set_halt (struct usb_ep *_ep, int value)
{
struct dummy_ep *ep;
- struct dummy *dum;
if (!_ep)
return -EINVAL;
- ep = usb_ep_to_dummy_ep (_ep);
- dum = ep_to_dummy (ep);
- if (!dum->driver)
+ if (!the_controller->driver)
return -ESHUTDOWN;
+ ep = container_of (_ep, struct dummy_ep, ep);
if (!value)
ep->halted = 0;
else if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
{
struct dummy *dum;
- dum = gadget_to_dummy (_gadget);
+ dum = container_of (_gadget, struct dummy, gadget);
if ((dum->devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) == 0
|| !(dum->port_status & (1 << USB_PORT_FEAT_SUSPEND)))
return -EINVAL;
{
struct dummy *dum;
- dum = gadget_to_dummy (_gadget);
+ dum = container_of (_gadget, struct dummy, gadget);
if (value)
dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
else
static void
dummy_udc_release (struct device *dev)
{
+ struct dummy *dum = gadget_dev_to_dummy (dev);
+
+ complete (&dum->released);
}
static void
-dummy_pdev_release (struct device *dev)
+dummy_hc_release (struct device *dev)
{
+ struct dummy *dum = dev_get_drvdata (dev);
+
+ complete (&dum->released);
}
static int
int rc;
strcpy (dum->gadget.dev.bus_id, "udc");
- dum->gadget.dev.parent = dummy_dev(dum);
+ dum->gadget.dev.parent = &dum->pdev.dev;
dum->gadget.dev.release = dummy_udc_release;
rc = device_register (&dum->gadget.dev);
dummy_unregister_udc (struct dummy *dum)
{
device_remove_file (&dum->gadget.dev, &dev_attr_function);
+ init_completion (&dum->released);
device_unregister (&dum->gadget.dev);
+ wait_for_completion (&dum->released);
}
int
dum->driver = driver;
dum->gadget.dev.driver = &driver->driver;
- dev_dbg (dummy_dev(dum), "binding gadget driver '%s'\n",
- driver->driver.name);
+ dev_dbg (hardware, "binding gadget driver '%s'\n", driver->driver.name);
if ((retval = driver->bind (&dum->gadget)) != 0) {
dum->driver = 0;
dum->gadget.dev.driver = 0;
}
// FIXME: Check these calls for errors and re-order
- driver->driver.bus = dum->gadget.dev.parent->bus;
+ driver->driver.bus = dum->pdev.dev.bus;
driver_register (&driver->driver);
device_bind_driver (&dum->gadget.dev);
if (!driver || driver != dum->driver)
return -EINVAL;
- dev_dbg (dummy_dev(dum), "unregister gadget driver '%s'\n",
+ dev_dbg (hardware, "unregister gadget driver '%s'\n",
driver->driver.name);
spin_lock_irqsave (&dum->lock, flags);
stop_activity (dum, driver);
- dum->port_status &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE |
- USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED);
+ dum->port_status &= ~USB_PORT_STAT_CONNECTION;
dum->port_status |= (1 << USB_PORT_FEAT_C_CONNECTION);
spin_unlock_irqrestore (&dum->lock, flags);
struct dummy *dum;
unsigned long flags;
- if (!urb->transfer_buffer && urb->transfer_buffer_length)
- return -EINVAL;
+ /* patch to usb_sg_init() is in 2.5.60 */
+ BUG_ON (!urb->transfer_buffer && urb->transfer_buffer_length);
- dum = hcd_to_dummy (hcd);
+ dum = container_of (hcd, struct dummy, hcd);
spin_lock_irqsave (&dum->lock, flags);
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");
+ dev_err (hardware, "usb_device address has changed!\n");
urb->hcpriv = dum;
if (usb_pipetype (urb->pipe) == PIPE_CONTROL)
total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/;
break;
default:
- dev_err (dummy_dev(dum), "bogus device speed\n");
+ dev_err (hardware, "bogus device speed\n");
return;
}
spin_lock_irqsave (&dum->lock, flags);
if (!dum->udev) {
- dev_err (dummy_dev(dum),
- "timer fired with no URBs pending?\n");
+ dev_err (hardware, "timer fired with no URBs pending?\n");
spin_unlock_irqrestore (&dum->lock, flags);
return;
}
ep = find_endpoint(dum, address);
if (!ep) {
/* set_configuration() disagreement */
- dev_dbg (dummy_dev(dum),
+ dev_err (hardware,
"no ep configured for urb %p\n",
urb);
- maybe_set_status (urb, -EPROTO);
+ maybe_set_status (urb, -ETIMEDOUT);
goto return_urb;
}
}
if (ep->halted && !ep->setup_stage) {
/* NOTE: must not be iso! */
- dev_dbg (dummy_dev(dum), "ep %s halted, urb %p\n",
+ dev_dbg (hardware, "ep %s halted, urb %p\n",
ep->ep.name, urb);
maybe_set_status (urb, -EPIPE);
goto return_urb;
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",
- req);
+ dev_dbg (hardware, "stale req = %p\n", req);
spin_unlock (&dum->lock);
req->req.complete (&ep->ep, &req->req);
break;
dum->address = setup.wValue;
maybe_set_status (urb, 0);
- dev_dbg (dummy_dev(dum), "set_address = %d\n",
+ dev_dbg (hardware, "set_address = %d\n",
setup.wValue);
value = 0;
break;
if (value < 0) {
if (value != -EOPNOTSUPP)
- dev_dbg (dummy_dev(dum),
+ dev_dbg (hardware,
"setup --> %d\n",
value);
maybe_set_status (urb, -EPIPE);
unsigned long flags;
int retval;
- dum = hcd_to_dummy (hcd);
+ dum = container_of (hcd, struct dummy, hcd);
spin_lock_irqsave (&dum->lock, flags);
if (!(dum->port_status & PORT_C_MASK))
retval = 0;
else {
*buf = (1 << 1);
- dev_dbg (dummy_dev(dum), "port status 0x%08x has changes\n",
+ dev_dbg (hardware, "port status 0x%08x has changes\n",
dum->port_status);
retval = 1;
}
int retval = 0;
unsigned long flags;
- dum = hcd_to_dummy (hcd);
+ dum = container_of (hcd, struct dummy, hcd);
spin_lock_irqsave (&dum->lock, flags);
switch (typeReq) {
case ClearHubFeature:
case ClearPortFeature:
switch (wValue) {
case USB_PORT_FEAT_SUSPEND:
- if (dum->port_status & (1 << USB_PORT_FEAT_SUSPEND)) {
- /* 20msec resume signaling */
- dum->resuming = 1;
- dum->re_timeout = jiffies +
- msecs_to_jiffies(20);
- }
+ /* 20msec resume signaling */
+ dum->resuming = 1;
+ dum->re_timeout = jiffies + ((HZ * 20)/1000);
break;
case USB_PORT_FEAT_POWER:
dum->port_status = 0;
dum->port_status &= ~(1 << USB_PORT_FEAT_SUSPEND);
dum->resuming = 0;
dum->re_timeout = 0;
- if (dum->driver && dum->driver->resume) {
+ if (dum->driver->resume) {
spin_unlock (&dum->lock);
dum->driver->resume (&dum->gadget);
spin_lock (&dum->lock);
case SetPortFeature:
switch (wValue) {
case USB_PORT_FEAT_SUSPEND:
- if ((dum->port_status & (1 << USB_PORT_FEAT_SUSPEND))
- == 0) {
- dum->port_status |=
- (1 << USB_PORT_FEAT_SUSPEND);
- if (dum->driver && dum->driver->suspend) {
- spin_unlock (&dum->lock);
- dum->driver->suspend (&dum->gadget);
- spin_lock (&dum->lock);
- }
+ dum->port_status |= (1 << USB_PORT_FEAT_SUSPEND);
+ if (dum->driver->suspend) {
+ spin_unlock (&dum->lock);
+ dum->driver->suspend (&dum->gadget);
+ spin_lock (&dum->lock);
}
break;
case USB_PORT_FEAT_RESET:
| USB_PORT_STAT_LOW_SPEED
| USB_PORT_STAT_HIGH_SPEED);
if (dum->driver) {
- dev_dbg (dummy_dev(dum),
- "disconnect\n");
+ dev_dbg (hardware, "disconnect\n");
stop_activity (dum, dum->driver);
}
/* FIXME test that code path! */
}
/* 50msec reset signaling */
- dum->re_timeout = jiffies + msecs_to_jiffies(50);
+ dum->re_timeout = jiffies + ((HZ * 50)/1000);
/* FALLTHROUGH */
default:
dum->port_status |= (1 << wValue);
break;
default:
- dev_dbg (dummy_dev(dum),
+ dev_dbg (hardware,
"hub control req%04x v%04x i%04x l%d\n",
typeReq, wValue, wIndex, wLength);
dum = kmalloc (sizeof *dum, SLAB_KERNEL);
if (dum == NULL)
- return NULL;
- the_controller = dum;
+ return 0;
memset (dum, 0, sizeof *dum);
return &dum->hcd;
}
+static void dummy_free (struct usb_hcd *hcd)
+{
+ struct dummy *dum;
+
+ dum = container_of (hcd, struct dummy, hcd);
+ WARN_ON (dum->driver != 0);
+ kfree (dum);
+}
+
/*-------------------------------------------------------------------------*/
static inline ssize_t
static ssize_t
show_urbs (struct device *dev, char *buf)
{
- struct usb_hcd *hcd = dev_get_drvdata (dev);
- struct dummy *dum = hcd_to_dummy (hcd);
+ struct dummy *dum = dev_get_drvdata(dev);
struct urb *urb;
size_t size = 0;
unsigned long flags;
}
static DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL);
+
+static const struct hc_driver dummy_hcd;
+
static int dummy_start (struct usb_hcd *hcd)
{
struct dummy *dum;
+ struct usb_bus *bus;
struct usb_device *root;
int retval;
- dum = hcd_to_dummy (hcd);
+ dum = container_of (hcd, struct dummy, hcd);
/*
* MASTER side init ... we emulate a root hub that'll only ever
*/
spin_lock_init (&dum->lock);
+ retval = driver_register (&dummy_driver);
+ if (retval < 0)
+ return retval;
+
+ dum->pdev.name = "hc";
+ dum->pdev.dev.driver = &dummy_driver;
+ dev_set_drvdata(&dum->pdev.dev, dum);
+ dum->pdev.dev.release = dummy_hc_release;
+ retval = platform_device_register (&dum->pdev);
+ if (retval < 0) {
+ driver_unregister (&dummy_driver);
+ return retval;
+ }
+ dev_info (&dum->pdev.dev, "%s, driver " DRIVER_VERSION "\n",
+ driver_desc);
+
+ hcd->self.controller = &dum->pdev.dev;
+
+ /* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
+ device_create_file (hcd->self.controller, &dev_attr_urbs);
+
init_timer (&dum->timer);
dum->timer.function = dummy_timer;
dum->timer.data = (unsigned long) dum;
- root = usb_alloc_dev (0, &hcd->self, 0);
- if (!root)
- return -ENOMEM;
+ /* root hub will appear as another device */
+ dum->hcd.driver = (struct hc_driver *) &dummy_hcd;
+ dum->hcd.description = dummy_hcd.description;
+ dum->hcd.product_desc = "Dummy host controller";
+
+ bus = hcd_to_bus (&dum->hcd);
+ bus->bus_name = dum->pdev.dev.bus_id;
+ usb_bus_init (bus);
+ bus->op = &usb_hcd_operations;
+ bus->hcpriv = &dum->hcd;
+
+ /* FIXME don't require the pci-based buffer/alloc impls;
+ * the "generic dma" implementation still requires them,
+ * it's not very generic yet.
+ */
+ if ((retval = hcd_buffer_create (&dum->hcd)) != 0) {
+clean0:
+ init_completion (&dum->released);
+ platform_device_unregister (&dum->pdev);
+ wait_for_completion (&dum->released);
+ driver_unregister (&dummy_driver);
+ return retval;
+ }
+
+ INIT_LIST_HEAD (&hcd->dev_list);
+ usb_register_bus (bus);
+
+ root = usb_alloc_dev (0, bus, 0);
+ if (!root) {
+ retval = -ENOMEM;
+clean1:
+ hcd_buffer_destroy (&dum->hcd);
+ usb_deregister_bus (bus);
+ goto clean0;
+ }
/* root hub enters addressed state... */
- hcd->state = USB_STATE_RUNNING;
+ dum->hcd.state = USB_STATE_RUNNING;
root->speed = USB_SPEED_HIGH;
/* ...then configured, so khubd sees us. */
- if ((retval = hcd_register_root (root, hcd)) != 0) {
+ if ((retval = hcd_register_root (root, &dum->hcd)) != 0) {
usb_put_dev (root);
-clean:
- hcd->state = USB_STATE_QUIESCING;
- return retval;
+clean2:
+ dum->hcd.state = USB_STATE_QUIESCING;
+ goto clean1;
}
/* only show a low-power port: just 8mA */
hub_set_power_budget (root, 8);
+ dum->started = 1;
+
if ((retval = dummy_register_udc (dum)) != 0) {
- usb_disconnect (&hcd->self.root_hub);
- goto clean;
+ dum->started = 0;
+ usb_disconnect (&bus->root_hub);
+ goto clean2;
}
-
- /* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
- device_create_file (dummy_dev(dum), &dev_attr_urbs);
-
- dum->started = 1;
return 0;
}
static void dummy_stop (struct usb_hcd *hcd)
{
struct dummy *dum;
+ struct usb_bus *bus;
- dum = hcd_to_dummy (hcd);
+ dum = container_of (hcd, struct dummy, hcd);
if (!dum->started)
return;
dum->started = 0;
- 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");
+ bus = hcd_to_bus (&dum->hcd);
+ hcd->state = USB_STATE_QUIESCING;
+ dev_dbg (hardware, "remove root hub\n");
+ usb_disconnect (&bus->root_hub);
+
+ hcd_buffer_destroy (&dum->hcd);
+ usb_deregister_bus (bus);
+
+ dev_info (hardware, "stopped\n");
+
+ device_remove_file (hcd->self.controller, &dev_attr_urbs);
+ init_completion (&dum->released);
+ platform_device_unregister (&dum->pdev);
+ wait_for_completion (&dum->released);
+
+ driver_unregister (&dummy_driver);
}
/*-------------------------------------------------------------------------*/
.stop = dummy_stop,
.hcd_alloc = dummy_alloc,
+ .hcd_free = dummy_free,
.urb_enqueue = dummy_urb_enqueue,
.urb_dequeue = dummy_urb_dequeue,
.hub_control = dummy_hub_control,
};
-static void dummy_remove (struct device *dev);
+/*-------------------------------------------------------------------------*/
-static int dummy_probe (struct device *dev)
+static int __init init (void)
{
struct usb_hcd *hcd;
- struct dummy *dum;
- int retval;
+ int value;
- dev_info (dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
-
- hcd = dummy_alloc ();
- if (hcd == NULL) {
- dev_dbg (dev, "hcd_alloc failed\n");
+ if (usb_disabled ())
+ return -ENODEV;
+ if ((hcd = dummy_alloc ()) == 0)
return -ENOMEM;
- }
-
- dev_set_drvdata (dev, hcd);
- dum = hcd_to_dummy (hcd);
- hcd->driver = (struct hc_driver *) &dummy_hcd;
- hcd->description = dummy_hcd.description;
- hcd->self.controller = dev;
+ the_controller = container_of (hcd, struct dummy, hcd);
+ value = dummy_start (hcd);
- /* FIXME don't require the pci-based buffer/alloc impls;
- * the "generic dma" implementation still requires them,
- * it's not very generic yet.
- */
- retval = hcd_buffer_create (hcd);
- if (retval != 0) {
- dev_dbg (dev, "pool alloc failed\n");
- goto err1;
+ if (value != 0) {
+ dummy_free (hcd);
+ the_controller = 0;
}
-
- usb_bus_init (&hcd->self);
- hcd->self.op = &usb_hcd_operations;
- hcd->self.release = &usb_hcd_release;
- hcd->self.hcpriv = hcd;
- hcd->self.bus_name = dev->bus_id;
- hcd->product_desc = "Dummy host controller";
-
- INIT_LIST_HEAD (&hcd->dev_list);
-
- usb_register_bus (&hcd->self);
-
- if ((retval = dummy_start (hcd)) < 0)
- dummy_remove (dev);
- return retval;
-
-err1:
- kfree (hcd);
- dev_set_drvdata (dev, NULL);
- return retval;
-}
-
-static void dummy_remove (struct device *dev)
-{
- struct usb_hcd *hcd;
- struct dummy *dum;
-
- hcd = dev_get_drvdata (dev);
- dum = hcd_to_dummy (hcd);
-
- hcd->state = USB_STATE_QUIESCING;
-
- dev_dbg (dev, "roothub graceful disconnect\n");
- usb_disconnect (&hcd->self.root_hub);
-
- hcd->driver->stop (hcd);
- hcd->state = USB_STATE_HALT;
-
- hcd_buffer_destroy (hcd);
-
- dev_set_drvdata (dev, NULL);
- usb_deregister_bus (&hcd->self);
- the_controller = NULL;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static int dummy_pdev_detect (void)
-{
- int retval;
-
- retval = driver_register (&dummy_driver);
- if (retval < 0)
- return retval;
-
- 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;
-}
-
-static void dummy_pdev_remove (void)
-{
- platform_device_unregister (&the_pdev);
- driver_unregister (&dummy_driver);
-}
-
-/*-------------------------------------------------------------------------*/
-
-static int __init init (void)
-{
- int retval;
-
- if (usb_disabled ())
- return -ENODEV;
- if ((retval = dummy_pdev_detect ()) != 0)
- return retval;
- if ((retval = dummy_probe (&the_pdev.dev)) != 0)
- dummy_pdev_remove ();
- return retval;
+ return value;
}
module_init (init);
static void __exit cleanup (void)
{
- dummy_remove (&the_pdev.dev);
- dummy_pdev_remove ();
+ dummy_stop (&the_controller->hcd);
+ dummy_free (&the_controller->hcd);
+ the_controller = 0;
}
module_exit (cleanup);
+