diff options
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r-- | drivers/usb/gadget/Kconfig | 11 | ||||
-rw-r--r-- | drivers/usb/gadget/dummy_hcd.c | 745 | ||||
-rw-r--r-- | drivers/usb/gadget/ether.c | 353 | ||||
-rw-r--r-- | drivers/usb/gadget/file_storage.c | 61 | ||||
-rw-r--r-- | drivers/usb/gadget/goku_udc.c | 28 | ||||
-rw-r--r-- | drivers/usb/gadget/inode.c | 12 | ||||
-rw-r--r-- | drivers/usb/gadget/ndis.h | 14 | ||||
-rw-r--r-- | drivers/usb/gadget/net2280.c | 51 | ||||
-rw-r--r-- | drivers/usb/gadget/omap_udc.c | 301 | ||||
-rw-r--r-- | drivers/usb/gadget/omap_udc.h | 4 | ||||
-rw-r--r-- | drivers/usb/gadget/pxa2xx_udc.c | 43 | ||||
-rw-r--r-- | drivers/usb/gadget/pxa2xx_udc.h | 10 | ||||
-rw-r--r-- | drivers/usb/gadget/rndis.c | 515 | ||||
-rw-r--r-- | drivers/usb/gadget/rndis.h | 95 | ||||
-rw-r--r-- | drivers/usb/gadget/serial.c | 36 | ||||
-rw-r--r-- | drivers/usb/gadget/zero.c | 6 |
16 files changed, 1279 insertions, 1006 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 3b24f9f..ff075a5 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -53,6 +53,9 @@ config USB_GADGET_DEBUG_FILES driver on a new board. Enable these files by choosing "Y" here. If in doubt, or to conserve kernel memory, say "N". +config USB_GADGET_SELECTED + boolean + # # USB Peripheral Controller Support # @@ -85,6 +88,7 @@ config USB_NET2280 tristate depends on USB_GADGET_NET2280 default USB_GADGET + select USB_GADGET_SELECTED config USB_GADGET_PXA2XX boolean "PXA 25x or IXP 4xx" @@ -105,6 +109,7 @@ config USB_PXA2XX tristate depends on USB_GADGET_PXA2XX default USB_GADGET + select USB_GADGET_SELECTED # if there's only one gadget driver, using only two bulk endpoints, # don't waste memory for the other endpoints @@ -134,6 +139,7 @@ config USB_GOKU tristate depends on USB_GADGET_GOKU default USB_GADGET + select USB_GADGET_SELECTED config USB_GADGET_LH7A40X @@ -146,6 +152,7 @@ config USB_LH7A40X tristate depends on USB_GADGET_LH7A40X default USB_GADGET + select USB_GADGET_SELECTED config USB_GADGET_OMAP @@ -167,6 +174,7 @@ config USB_OMAP tristate depends on USB_GADGET_OMAP default USB_GADGET + select USB_GADGET_SELECTED config USB_OTG boolean "OTG Support" @@ -207,6 +215,7 @@ config USB_DUMMY_HCD tristate depends on USB_GADGET_DUMMY_HCD default USB_GADGET + select USB_GADGET_SELECTED # NOTE: Please keep dummy_hcd LAST so that "real hardware" appears # first and will be selected by default. @@ -226,7 +235,7 @@ config USB_GADGET_DUALSPEED # choice tristate "USB Gadget Drivers" - depends on USB_GADGET + depends on USB_GADGET && USB_GADGET_SELECTED default USB_ETH help A Linux "Gadget Driver" talks to the USB Peripheral Controller diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index c039d2f..4d69267 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -65,7 +65,7 @@ #define DRIVER_DESC "USB Host+Gadget Emulator" -#define DRIVER_VERSION "17 Dec 2004" +#define DRIVER_VERSION "02 May 2005" static const char driver_name [] = "dummy_hcd"; static const char driver_desc [] = "USB Host+Gadget Emulator"; @@ -141,6 +141,8 @@ static const char *const ep_name [] = { }; #define DUMMY_ENDPOINTS (sizeof(ep_name)/sizeof(char *)) +/*-------------------------------------------------------------------------*/ + #define FIFO_SIZE 64 struct urbp { @@ -148,6 +150,13 @@ struct urbp { struct list_head urbp_list; }; + +enum dummy_rh_state { + DUMMY_RH_RESET, + DUMMY_RH_SUSPENDED, + DUMMY_RH_RUNNING +}; + struct dummy { spinlock_t lock; @@ -161,12 +170,18 @@ struct dummy { struct dummy_request fifo_req; u8 fifo_buf [FIFO_SIZE]; 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; @@ -189,6 +204,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,16 +228,98 @@ 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; +/* SLAVE/GADGET SIDE UTILITY ROUTINES */ -static struct device_driver dummy_driver = { - .name = (char *) driver_name, - .bus = &platform_bus_type, -}; +/* called with spinlock held */ +static void nuke (struct dummy *dum, struct dummy_ep *ep) +{ + while (!list_empty (&ep->queue)) { + struct dummy_request *req; + + req = list_entry (ep->queue.next, struct dummy_request, queue); + list_del_init (&req->queue); + req->req.status = -ESHUTDOWN; + + spin_unlock (&dum->lock); + req->req.complete (&ep->ep, &req->req); + spin_lock (&dum->lock); + } +} + +/* caller must hold lock */ +static void +stop_activity (struct dummy *dum) +{ + struct dummy_ep *ep; + + /* prevent any more requests */ + dum->address = 0; + + /* The timer is left running so that outstanding URBs can fail */ + + /* nuke any pending requests first, so driver i/o is quiesced */ + list_for_each_entry (ep, &dum->gadget.ep_list, ep.ep_list) + nuke (dum, ep); + + /* driver now does any non-usb quiescing necessary */ +} + +/* caller must hold lock */ +static void +set_link_state (struct dummy *dum) +{ + dum->active = 0; + if ((dum->port_status & USB_PORT_STAT_POWER) == 0) + dum->port_status = 0; + + /* UDC suspend must cause a disconnect */ + else if (!dum->pullup || dum->udc_suspended) { + dum->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); + } 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; + } + + if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0 || dum->active) + dum->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 && + 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) { + spin_unlock (&dum->lock); + dum->driver->suspend (&dum->gadget); + spin_lock (&dum->lock); + } else if (!dum->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; +} /*-------------------------------------------------------------------------*/ @@ -324,7 +426,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", @@ -345,22 +447,6 @@ done: return retval; } -/* called with spinlock held */ -static void nuke (struct dummy *dum, struct dummy_ep *ep) -{ - while (!list_empty (&ep->queue)) { - struct dummy_request *req; - - req = list_entry (ep->queue.next, struct dummy_request, queue); - list_del_init (&req->queue); - req->req.status = -ESHUTDOWN; - - spin_unlock (&dum->lock); - req->req.complete (&ep->ep, &req->req); - spin_lock (&dum->lock); - } -} - static int dummy_disable (struct usb_ep *_ep) { struct dummy_ep *ep; @@ -379,7 +465,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 +560,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 +623,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); @@ -601,13 +687,21 @@ static int dummy_wakeup (struct usb_gadget *_gadget) struct dummy *dum; dum = gadget_to_dummy (_gadget); - if ((dum->devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) == 0 - || !(dum->port_status & (1 << USB_PORT_FEAT_SUSPEND))) + if (!(dum->devstatus & ( (1 << USB_DEVICE_B_HNP_ENABLE) + | (1 << USB_DEVICE_REMOTE_WAKEUP)))) return -EINVAL; + if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0) + return -ENOLINK; + if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 && + dum->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->port_status |= (1 << USB_PORT_FEAT_C_SUSPEND); + dum->re_timeout = jiffies + msecs_to_jiffies(20); + mod_timer (&dummy_to_hcd (dum)->rh_timer, dum->re_timeout); return 0; } @@ -623,10 +717,26 @@ static int dummy_set_selfpowered (struct usb_gadget *_gadget, int value) return 0; } +static int dummy_pullup (struct usb_gadget *_gadget, int value) +{ + struct dummy *dum; + unsigned long flags; + + dum = gadget_to_dummy (_gadget); + spin_lock_irqsave (&dum->lock, flags); + dum->pullup = (value != 0); + set_link_state (dum); + spin_unlock_irqrestore (&dum->lock, flags); + + usb_hcd_poll_rh_status (dummy_to_hcd (dum)); + return 0; +} + static const struct usb_gadget_ops dummy_ops = { .get_frame = dummy_g_get_frame, .wakeup = dummy_wakeup, .set_selfpowered = dummy_set_selfpowered, + .pullup = dummy_pullup, }; /*-------------------------------------------------------------------------*/ @@ -641,7 +751,7 @@ show_function (struct device *dev, struct device_attribute *attr, char *buf) return 0; return scnprintf (buf, PAGE_SIZE, "%s\n", dum->driver->function); } -DEVICE_ATTR (function, S_IRUGO, show_function, NULL); +static DEVICE_ATTR (function, S_IRUGO, show_function, NULL); /*-------------------------------------------------------------------------*/ @@ -659,38 +769,6 @@ DEVICE_ATTR (function, S_IRUGO, show_function, NULL); * for each driver that registers: just add to a big root hub. */ -static void -dummy_udc_release (struct device *dev) -{ -} - -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) { @@ -709,12 +787,8 @@ 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; dum->devstatus = 0; - dum->resuming = 0; INIT_LIST_HEAD (&dum->gadget.ep_list); for (i = 0; i < DUMMY_ENDPOINTS; i++) { @@ -740,7 +814,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; @@ -748,42 +822,21 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver) return retval; } - // FIXME: Check these calls for errors and re-order driver->driver.bus = dum->gadget.dev.parent->bus; driver_register (&driver->driver); - device_bind_driver (&dum->gadget.dev); /* khubd will enumerate this in a while */ - dum->port_status |= USB_PORT_STAT_CONNECTION - | (1 << USB_PORT_FEAT_C_CONNECTION); + spin_lock_irq (&dum->lock); + dum->pullup = 1; + set_link_state (dum); + spin_unlock_irq (&dum->lock); + + usb_hcd_poll_rh_status (dummy_to_hcd (dum)); return 0; } EXPORT_SYMBOL (usb_gadget_register_driver); -/* caller must hold lock */ -static void -stop_activity (struct dummy *dum, struct usb_gadget_driver *driver) -{ - struct dummy_ep *ep; - - /* prevent any more requests */ - dum->address = 0; - - /* The timer is left running so that outstanding URBs can fail */ - - /* nuke any pending requests first, so driver i/o is quiesced */ - list_for_each_entry (ep, &dum->gadget.ep_list, ep.ep_list) - nuke (dum, ep); - - /* driver now does any non-usb quiescing necessary */ - if (driver) { - spin_unlock (&dum->lock); - driver->disconnect (&dum->gadget); - spin_lock (&dum->lock); - } -} - int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) { @@ -795,35 +848,138 @@ 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); - 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 |= (1 << USB_PORT_FEAT_C_CONNECTION); + dum->pullup = 0; + set_link_state (dum); spin_unlock_irqrestore (&dum->lock, flags); driver->unbind (&dum->gadget); dum->driver = NULL; device_release_driver (&dum->gadget.dev); - driver_unregister (&driver->driver); + spin_lock_irqsave (&dum->lock, flags); + dum->pullup = 0; + set_link_state (dum); + spin_unlock_irqrestore (&dum->lock, flags); + + usb_hcd_poll_rh_status (dummy_to_hcd (dum)); return 0; } EXPORT_SYMBOL (usb_gadget_unregister_driver); #undef is_enabled +/* just declare this in any driver that really need it */ +extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode); + int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode) { return -ENOSYS; } 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 int dummy_udc_suspend (struct device *dev, pm_message_t state, + u32 level) +{ + struct dummy *dum = dev_get_drvdata(dev); + + if (level != SUSPEND_DISABLE) + return 0; + + dev_dbg (dev, "%s\n", __FUNCTION__); + spin_lock_irq (&dum->lock); + dum->udc_suspended = 1; + set_link_state (dum); + spin_unlock_irq (&dum->lock); + + dev->power.power_state = state; + usb_hcd_poll_rh_status (dummy_to_hcd (dum)); + return 0; +} + +static int dummy_udc_resume (struct device *dev, u32 level) +{ + struct dummy *dum = dev_get_drvdata(dev); + + if (level != RESUME_ENABLE) + return 0; + + dev_dbg (dev, "%s\n", __FUNCTION__); + spin_lock_irq (&dum->lock); + dum->udc_suspended = 0; + set_link_state (dum); + spin_unlock_irq (&dum->lock); + + dev->power.power_state = PMSG_ON; + usb_hcd_poll_rh_status (dummy_to_hcd (dum)); + 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, + .suspend = dummy_udc_suspend, + .resume = dummy_udc_resume, +}; + /*-------------------------------------------------------------------------*/ /* MASTER/HOST SIDE DRIVER @@ -880,7 +1036,16 @@ static int dummy_urb_enqueue ( static int dummy_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) { - /* giveback happens automatically in timer callback */ + struct dummy *dum; + unsigned long flags; + + /* giveback happens automatically in timer callback, + * so make sure the callback happens */ + dum = hcd_to_dummy (hcd); + spin_lock_irqsave (&dum->lock, flags); + if (dum->rh_state != DUMMY_RH_RUNNING && !list_empty(&dum->urbp_list)) + mod_timer (&dum->timer, jiffies); + spin_unlock_irqrestore (&dum->lock, flags); return 0; } @@ -1025,7 +1190,6 @@ static int periodic_bytes (struct dummy *dum, struct dummy_ep *ep) /* high bandwidth mode */ tmp = le16_to_cpu(ep->desc->wMaxPacketSize); - tmp = le16_to_cpu (tmp); tmp = (tmp >> 11) & 0x03; tmp *= 8 /* applies to entire frame */; limit += limit * tmp; @@ -1123,7 +1287,8 @@ restart: if (urb->status != -EINPROGRESS) { /* likely it was just unlinked */ goto return_urb; - } + } else if (dum->rh_state != DUMMY_RH_RUNNING) + continue; type = usb_pipetype (urb->pipe); /* used up this frame's non-periodic bandwidth? @@ -1168,12 +1333,14 @@ restart: struct usb_ctrlrequest setup; int value = 1; struct dummy_ep *ep2; + unsigned w_index; + unsigned w_value; setup = *(struct usb_ctrlrequest*) urb->setup_packet; - le16_to_cpus (&setup.wIndex); - le16_to_cpus (&setup.wValue); - le16_to_cpus (&setup.wLength); - if (setup.wLength != urb->transfer_buffer_length) { + w_index = le16_to_cpu(setup.wIndex); + w_value = le16_to_cpu(setup.wValue); + if (le16_to_cpu(setup.wLength) != + urb->transfer_buffer_length) { maybe_set_status (urb, -EOVERFLOW); goto return_urb; } @@ -1182,7 +1349,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); @@ -1203,31 +1370,40 @@ restart: case USB_REQ_SET_ADDRESS: if (setup.bRequestType != Dev_Request) break; - dum->address = setup.wValue; + dum->address = w_value; maybe_set_status (urb, 0); - dev_dbg (dummy_dev(dum), "set_address = %d\n", - setup.wValue); + dev_dbg (udc_dev(dum), "set_address = %d\n", + w_value); value = 0; break; case USB_REQ_SET_FEATURE: if (setup.bRequestType == Dev_Request) { value = 0; - switch (setup.wValue) { + switch (w_value) { case USB_DEVICE_REMOTE_WAKEUP: break; + case USB_DEVICE_B_HNP_ENABLE: + dum->gadget.b_hnp_enable = 1; + break; + case USB_DEVICE_A_HNP_SUPPORT: + dum->gadget.a_hnp_support = 1; + break; + case USB_DEVICE_A_ALT_HNP_SUPPORT: + dum->gadget.a_alt_hnp_support + = 1; + break; default: value = -EOPNOTSUPP; } if (value == 0) { dum->devstatus |= - (1 << setup.wValue); + (1 << w_value); maybe_set_status (urb, 0); } } else if (setup.bRequestType == Ep_Request) { // endpoint halt - ep2 = find_endpoint (dum, - setup.wIndex); + ep2 = find_endpoint (dum, w_index); if (!ep2) { value = -EOPNOTSUPP; break; @@ -1239,7 +1415,7 @@ restart: break; case USB_REQ_CLEAR_FEATURE: if (setup.bRequestType == Dev_Request) { - switch (setup.wValue) { + switch (w_value) { case USB_DEVICE_REMOTE_WAKEUP: dum->devstatus &= ~(1 << USB_DEVICE_REMOTE_WAKEUP); @@ -1252,8 +1428,7 @@ restart: } } else if (setup.bRequestType == Ep_Request) { // endpoint halt - ep2 = find_endpoint (dum, - setup.wIndex); + ep2 = find_endpoint (dum, w_index); if (!ep2) { value = -EOPNOTSUPP; break; @@ -1279,7 +1454,7 @@ restart: if (urb->transfer_buffer_length > 0) { if (setup.bRequestType == Ep_InRequest) { - ep2 = find_endpoint (dum, setup.wIndex); + ep2 = find_endpoint (dum, w_index); if (!ep2) { value = -EOPNOTSUPP; break; @@ -1321,7 +1496,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); @@ -1377,12 +1552,12 @@ return_urb: goto restart; } - /* want a 1 msec delay here */ - if (!list_empty (&dum->urbp_list)) - mod_timer (&dum->timer, jiffies + msecs_to_jiffies(1)); - else { + if (list_empty (&dum->urbp_list)) { usb_put_dev (dum->udev); dum->udev = NULL; + } else if (dum->rh_state == DUMMY_RH_RUNNING) { + /* want a 1 msec delay here */ + mod_timer (&dum->timer, jiffies + msecs_to_jiffies(1)); } spin_unlock_irqrestore (&dum->lock, flags); @@ -1391,29 +1566,39 @@ return_urb: /*-------------------------------------------------------------------------*/ #define PORT_C_MASK \ - ((1 << USB_PORT_FEAT_C_CONNECTION) \ - | (1 << USB_PORT_FEAT_C_ENABLE) \ - | (1 << USB_PORT_FEAT_C_SUSPEND) \ - | (1 << USB_PORT_FEAT_C_OVER_CURRENT) \ - | (1 << USB_PORT_FEAT_C_RESET)) + ((USB_PORT_STAT_C_CONNECTION \ + | USB_PORT_STAT_C_ENABLE \ + | USB_PORT_STAT_C_SUSPEND \ + | USB_PORT_STAT_C_OVERCURRENT \ + | USB_PORT_STAT_C_RESET) << 16) static int dummy_hub_status (struct usb_hcd *hcd, char *buf) { struct dummy *dum; unsigned long flags; - int retval; + int retval = 0; dum = hcd_to_dummy (hcd); spin_lock_irqsave (&dum->lock, flags); - if (!(dum->port_status & PORT_C_MASK)) - retval = 0; - else { + if (hcd->state != HC_STATE_RUNNING) + 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->port_status & PORT_C_MASK) != 0) { *buf = (1 << 1); dev_dbg (dummy_dev(dum), "port status 0x%08x has changes\n", - dum->port_status); + dum->port_status); retval = 1; + if (dum->rh_state == DUMMY_RH_SUSPENDED) + usb_hcd_resume_root_hub (hcd); } +done: spin_unlock_irqrestore (&dum->lock, flags); return retval; } @@ -1424,7 +1609,8 @@ hub_descriptor (struct usb_hub_descriptor *desc) memset (desc, 0, sizeof *desc); desc->bDescriptorType = 0x29; desc->bDescLength = 9; - desc->wHubCharacteristics = __constant_cpu_to_le16 (0x0001); + desc->wHubCharacteristics = (__force __u16) + (__constant_cpu_to_le16 (0x0001)); desc->bNbrPorts = 1; desc->bitmap [0] = 0xff; desc->bitmap [1] = 0xff; @@ -1442,6 +1628,9 @@ static int dummy_hub_control ( int retval = 0; unsigned long flags; + if (hcd->state != HC_STATE_RUNNING) + return -ETIMEDOUT; + dum = hcd_to_dummy (hcd); spin_lock_irqsave (&dum->lock, flags); switch (typeReq) { @@ -1450,27 +1639,27 @@ static int dummy_hub_control ( case ClearPortFeature: switch (wValue) { case USB_PORT_FEAT_SUSPEND: - if (dum->port_status & (1 << USB_PORT_FEAT_SUSPEND)) { + if (dum->port_status & USB_PORT_STAT_SUSPEND) { /* 20msec resume signaling */ dum->resuming = 1; dum->re_timeout = jiffies + - msecs_to_jiffies(20); + msecs_to_jiffies(20); } break; case USB_PORT_FEAT_POWER: - dum->port_status = 0; - dum->resuming = 0; - stop_activity(dum, dum->driver); - break; + if (dum->port_status & USB_PORT_STAT_POWER) + dev_dbg (dummy_dev(dum), "power-off\n"); + /* FALLS THROUGH */ default: dum->port_status &= ~(1 << wValue); + set_link_state (dum); } break; case GetHubDescriptor: hub_descriptor ((struct usb_hub_descriptor *) buf); break; case GetHubStatus: - *(u32 *) buf = __constant_cpu_to_le32 (0); + *(__le32 *) buf = __constant_cpu_to_le32 (0); break; case GetPortStatus: if (wIndex != 1) @@ -1479,23 +1668,16 @@ static int dummy_hub_control ( /* whoever resets or resumes must GetPortStatus to * complete it!! */ - if (dum->resuming && time_after (jiffies, dum->re_timeout)) { - dum->port_status |= (1 << USB_PORT_FEAT_C_SUSPEND); - dum->port_status &= ~(1 << USB_PORT_FEAT_SUSPEND); - dum->resuming = 0; - dum->re_timeout = 0; - if (dum->driver && dum->driver->resume) { - spin_unlock (&dum->lock); - dum->driver->resume (&dum->gadget); - spin_lock (&dum->lock); - } + 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->port_status & (1 << USB_PORT_FEAT_RESET)) != 0 - && time_after (jiffies, dum->re_timeout)) { - dum->port_status |= (1 << USB_PORT_FEAT_C_RESET); - dum->port_status &= ~(1 << USB_PORT_FEAT_RESET); - dum->re_timeout = 0; - if (dum->driver) { + 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; @@ -1516,8 +1698,9 @@ static int dummy_hub_control ( } } } - ((u16 *) buf)[0] = cpu_to_le16 (dum->port_status); - ((u16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16); + set_link_state (dum); + ((__le16 *) buf)[0] = cpu_to_le16 (dum->port_status); + ((__le16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16); break; case SetHubFeature: retval = -EPIPE; @@ -1525,36 +1708,37 @@ static int dummy_hub_control ( 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); - } + if (dum->active) { + dum->port_status |= USB_PORT_STAT_SUSPEND; + + /* HNP would happen here; for now we + * assume b_bus_req is always true. + */ + set_link_state (dum); + if (((1 << USB_DEVICE_B_HNP_ENABLE) + & dum->devstatus) != 0) + dev_dbg (dummy_dev(dum), + "no HNP yet!\n"); } break; + case USB_PORT_FEAT_POWER: + dum->port_status |= USB_PORT_STAT_POWER; + set_link_state (dum); + break; case USB_PORT_FEAT_RESET: - /* if it's already running, disconnect first */ - if (dum->port_status & USB_PORT_STAT_ENABLE) { - dum->port_status &= ~(USB_PORT_STAT_ENABLE - | USB_PORT_STAT_LOW_SPEED - | USB_PORT_STAT_HIGH_SPEED); - if (dum->driver) { - dev_dbg (dummy_dev(dum), - "disconnect\n"); - stop_activity (dum, dum->driver); - } - - /* FIXME test that code path! */ - } + /* if it's already enabled, disable */ + dum->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); - /* FALLTHROUGH */ + /* FALLS THROUGH */ default: - dum->port_status |= (1 << wValue); + if ((dum->port_status & USB_PORT_STAT_POWER) != 0) { + dum->port_status |= (1 << wValue); + set_link_state (dum); + } } break; @@ -1567,9 +1751,35 @@ static int dummy_hub_control ( retval = -EPIPE; } spin_unlock_irqrestore (&dum->lock, flags); + + if ((dum->port_status & PORT_C_MASK) != 0) + usb_hcd_poll_rh_status (hcd); return retval; } +static int dummy_hub_suspend (struct usb_hcd *hcd) +{ + struct dummy *dum = hcd_to_dummy (hcd); + + spin_lock_irq (&dum->lock); + dum->rh_state = DUMMY_RH_SUSPENDED; + set_link_state (dum); + spin_unlock_irq (&dum->lock); + return 0; +} + +static int dummy_hub_resume (struct usb_hcd *hcd) +{ + struct dummy *dum = hcd_to_dummy (hcd); + + spin_lock_irq (&dum->lock); + dum->rh_state = DUMMY_RH_RUNNING; + set_link_state (dum); + if (!list_empty(&dum->urbp_list)) + mod_timer (&dum->timer, jiffies); + spin_unlock_irq (&dum->lock); + return 0; +} /*-------------------------------------------------------------------------*/ @@ -1625,8 +1835,6 @@ static DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL); static int dummy_start (struct usb_hcd *hcd) { struct dummy *dum; - struct usb_device *root; - int retval; dum = hcd_to_dummy (hcd); @@ -1639,38 +1847,22 @@ static int dummy_start (struct usb_hcd *hcd) init_timer (&dum->timer); dum->timer.function = dummy_timer; dum->timer.data = (unsigned long) dum; + dum->rh_state = DUMMY_RH_RUNNING; INIT_LIST_HEAD (&dum->urbp_list); - root = usb_alloc_dev (NULL, &hcd->self, 0); - if (!root) - return -ENOMEM; - - /* root hub enters addressed state... */ - hcd->state = HC_STATE_RUNNING; - root->speed = USB_SPEED_HIGH; - - /* ...then configured, so khubd sees us. */ - if ((retval = usb_hcd_register_root_hub (root, hcd)) != 0) { - goto err1; - } - /* only show a low-power port: just 8mA */ - hub_set_power_budget (root, 8); + hcd->power_budget = 8; + hcd->state = HC_STATE_RUNNING; + hcd->uses_new_polling = 1; - if ((retval = dummy_register_udc (dum)) != 0) - goto err2; +#ifdef CONFIG_USB_OTG + hcd->self.otg_port = 1; +#endif /* FIXME 'urbs' should be a per-device thing, maybe in usbcore */ device_create_file (dummy_dev(dum), &dev_attr_urbs); return 0; - - err2: - usb_disconnect (&hcd->self.root_hub); - err1: - usb_put_dev (root); - hcd->state = HC_STATE_QUIESCING; - return retval; } static void dummy_stop (struct usb_hcd *hcd) @@ -1680,10 +1872,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"); } @@ -1711,9 +1900,11 @@ static const struct hc_driver dummy_hcd = { .hub_status_data = dummy_hub_status, .hub_control = dummy_hub_control, + .hub_suspend = dummy_hub_suspend, + .hub_resume = dummy_hub_resume, }; -static int dummy_probe (struct device *dev) +static int dummy_hcd_probe (struct device *dev) { struct usb_hcd *hcd; int retval; @@ -1733,7 +1924,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; @@ -1741,53 +1932,127 @@ 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) +static int dummy_hcd_suspend (struct device *dev, pm_message_t state, + u32 level) { - int retval; + struct usb_hcd *hcd; - retval = driver_register (&dummy_driver); - if (retval < 0) - return retval; + if (level != SUSPEND_DISABLE) + return 0; + + dev_dbg (dev, "%s\n", __FUNCTION__); + hcd = dev_get_drvdata (dev); - the_pdev.name = "hc"; - the_pdev.dev.driver = &dummy_driver; - the_pdev.dev.release = dummy_pdev_release; +#ifndef CONFIG_USB_SUSPEND + /* Otherwise this would never happen */ + usb_lock_device (hcd->self.root_hub); + dummy_hub_suspend (hcd); + usb_unlock_device (hcd->self.root_hub); +#endif - retval = platform_device_register (&the_pdev); - if (retval < 0) - driver_unregister (&dummy_driver); - return retval; + hcd->state = HC_STATE_SUSPENDED; + return 0; } -static void dummy_pdev_remove (void) +static int dummy_hcd_resume (struct device *dev, u32 level) { - platform_device_unregister (&the_pdev); - driver_unregister (&dummy_driver); + struct usb_hcd *hcd; + + if (level != RESUME_ENABLE) + return 0; + + dev_dbg (dev, "%s\n", __FUNCTION__); + hcd = dev_get_drvdata (dev); + hcd->state = HC_STATE_RUNNING; + +#ifndef CONFIG_USB_SUSPEND + /* Otherwise this would never happen */ + usb_lock_device (hcd->self.root_hub); + dummy_hub_resume (hcd); + usb_unlock_device (hcd->self.root_hub); +#endif + + usb_hcd_poll_rh_status (hcd); + return 0; } +static struct device_driver dummy_hcd_driver = { + .name = (char *) driver_name, + .bus = &platform_bus_type, + .probe = dummy_hcd_probe, + .remove = dummy_hcd_remove, + .suspend = dummy_hcd_suspend, + .resume = dummy_hcd_resume, +}; + /*-------------------------------------------------------------------------*/ +/* 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_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) { int retval; 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); diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 3f783cb..5bb53ae 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -84,18 +84,19 @@ */ #define DRIVER_DESC "Ethernet Gadget" -#define DRIVER_VERSION "Equinox 2004" +#define DRIVER_VERSION "May Day 2005" static const char shortname [] = "ether"; static const char driver_desc [] = DRIVER_DESC; #define RX_EXTRA 20 /* guard against rx overflows */ -#ifdef CONFIG_USB_ETH_RNDIS #include "rndis.h" -#else -#define rndis_init() 0 -#define rndis_exit() do{}while(0) + +#ifndef CONFIG_USB_ETH_RNDIS +#define rndis_uninit(x) do{}while(0) +#define rndis_deregister(c) do{}while(0) +#define rndis_exit() do{}while(0) #endif /* CDC and RNDIS support the same host-chosen outgoing packet filters. */ @@ -140,9 +141,6 @@ struct eth_dev { * It also ASSUMES a self-powered device, without remote wakeup, * although remote wakeup support would make sense. */ -static const char *EP_IN_NAME; -static const char *EP_OUT_NAME; -static const char *EP_STATUS_NAME; /*-------------------------------------------------------------------------*/ @@ -312,6 +310,7 @@ static inline int rndis_active(struct eth_dev *dev) #define FS_BPS (19 * 64 * 1 * 1000 * 8) #ifdef CONFIG_USB_GADGET_DUALSPEED +#define DEVSPEED USB_SPEED_HIGH static unsigned qmult = 5; module_param (qmult, uint, S_IRUGO|S_IWUSR); @@ -330,6 +329,8 @@ static inline int BITRATE(struct usb_gadget *g) } #else /* full speed (low speed doesn't do bulk) */ +#define DEVSPEED USB_SPEED_FULL + #define qlen(gadget) DEFAULT_QLEN static inline int BITRATE(struct usb_gadget *g) @@ -395,7 +396,8 @@ static inline int BITRATE(struct usb_gadget *g) #define STRING_SUBSET 8 #define STRING_RNDIS 9 -#define USB_BUFSIZ 256 /* holds our biggest descriptor */ +/* holds our biggest descriptor (or RNDIS response) */ +#define USB_BUFSIZ 256 /* * This device advertises one configuration, eth_config, unless RNDIS @@ -538,7 +540,7 @@ static const struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor = { .bDataInterface = 0x01, }; -static struct usb_cdc_acm_descriptor acm_descriptor = { +static const struct usb_cdc_acm_descriptor acm_descriptor = { .bLength = sizeof acm_descriptor, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = USB_CDC_ACM_TYPE, @@ -846,7 +848,7 @@ static const struct usb_descriptor_header *hs_rndis_function [] = { #else /* if there's no high speed support, maxpacket doesn't change. */ -#define ep_desc(g,hs,fs) fs +#define ep_desc(g,hs,fs) (((void)(g)), (fs)) static inline void __init hs_subset_descriptors(void) { @@ -946,10 +948,31 @@ config_buf (enum usb_device_speed speed, static void eth_start (struct eth_dev *dev, int gfp_flags); static int alloc_requests (struct eth_dev *dev, unsigned n, int gfp_flags); -#ifdef DEV_CONFIG_CDC -static inline int ether_alt_ep_setup (struct eth_dev *dev, struct usb_ep *ep) +static int +set_ether_config (struct eth_dev *dev, int gfp_flags) { - const struct usb_endpoint_descriptor *d; + int result = 0; + struct usb_gadget *gadget = dev->gadget; + + /* status endpoint used for RNDIS and (optionally) CDC */ + if (!subset_active(dev) && dev->status_ep) { + dev->status = ep_desc (gadget, &hs_status_desc, + &fs_status_desc); + dev->status_ep->driver_data = dev; + + result = usb_ep_enable (dev->status_ep, dev->status); + if (result != 0) { + DEBUG (dev, "enable %s --> %d\n", + dev->status_ep->name, result); + goto done; + } + } + + dev->in = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc); + dev->in_ep->driver_data = dev; + + dev->out = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc); + dev->out_ep->driver_data = dev; /* With CDC, the host isn't allowed to use these two data * endpoints in the default altsetting for the interface. @@ -959,135 +982,33 @@ static inline int ether_alt_ep_setup (struct eth_dev *dev, struct usb_ep *ep) * a side effect of setting a packet filter. Deactivation is * from REMOTE_NDIS_HALT_MSG, reset from REMOTE_NDIS_RESET_MSG. */ - - /* one endpoint writes data back IN to the host */ - if (strcmp (ep->name, EP_IN_NAME) == 0) { - d = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc); - ep->driver_data = dev; - dev->in = d; - - /* one endpoint just reads OUT packets */ - } else if (strcmp (ep->name, EP_OUT_NAME) == 0) { - d = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc); - ep->driver_data = dev; - dev->out = d; - - /* optional status/notification endpoint */ - } else if (EP_STATUS_NAME && - strcmp (ep->name, EP_STATUS_NAME) == 0) { - int result; - - d = ep_desc (dev->gadget, &hs_status_desc, &fs_status_desc); - result = usb_ep_enable (ep, d); - if (result < 0) - return result; - - ep->driver_data = dev; - dev->status = d; - } - return 0; -} -#endif - -#if defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS) -static inline int ether_ep_setup (struct eth_dev *dev, struct usb_ep *ep) -{ - int result; - const struct usb_endpoint_descriptor *d; - - /* CDC subset is simpler: if the device is there, - * it's live with rx and tx endpoints. - * - * Do this as a shortcut for RNDIS too. - */ - - /* one endpoint writes data back IN to the host */ - if (strcmp (ep->name, EP_IN_NAME) == 0) { - d = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc); - result = usb_ep_enable (ep, d); - if (result < 0) - return result; - - ep->driver_data = dev; - dev->in = d; - - /* one endpoint just reads OUT packets */ - } else if (strcmp (ep->name, EP_OUT_NAME) == 0) { - d = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc); - result = usb_ep_enable (ep, d); - if (result < 0) - return result; - - ep->driver_data = dev; - dev->out = d; - } - - return 0; -} -#endif - -static int -set_ether_config (struct eth_dev *dev, int gfp_flags) -{ - int result = 0; - struct usb_ep *ep; - struct usb_gadget *gadget = dev->gadget; - - gadget_for_each_ep (ep, gadget) { -#ifdef DEV_CONFIG_CDC - if (!dev->rndis && dev->cdc) { - result = ether_alt_ep_setup (dev, ep); - if (result == 0) - continue; + if (!cdc_active(dev)) { + result = usb_ep_enable (dev->in_ep, dev->in); + if (result != 0) { + DEBUG(dev, "enable %s --> %d\n", + dev->in_ep->name, result); + goto done; } -#endif - -#ifdef CONFIG_USB_ETH_RNDIS - if (dev->rndis && strcmp (ep->name, EP_STATUS_NAME) == 0) { - const struct usb_endpoint_descriptor *d; - d = ep_desc (gadget, &hs_status_desc, &fs_status_desc); - result = usb_ep_enable (ep, d); - if (result == 0) { - ep->driver_data = dev; - dev->status = d; - continue; - } - } else -#endif - { -#if defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS) - result = ether_ep_setup (dev, ep); - if (result == 0) - continue; -#endif + result = usb_ep_enable (dev->out_ep, dev->out); + if (result != 0) { + DEBUG (dev, "enable %s --> %d\n", + dev->in_ep->name, result); + goto done; } - - /* stop on error */ - ERROR (dev, "can't enable %s, result %d\n", ep->name, result); - break; } - if (!result && (!dev->in_ep || !dev->out_ep)) - result = -ENODEV; +done: if (result == 0) result = alloc_requests (dev, qlen (gadget), gfp_flags); /* on error, disable any endpoints */ if (result < 0) { -#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) - if (dev->status) + if (!subset_active(dev)) (void) usb_ep_disable (dev->status_ep); -#endif dev->status = NULL; -#if defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS) - if (dev->rndis || !dev->cdc) { - if (dev->in) - (void) usb_ep_disable (dev->in_ep); - if (dev->out) - (void) usb_ep_disable (dev->out_ep); - } -#endif + (void) usb_ep_disable (dev->in_ep); + (void) usb_ep_disable (dev->out_ep); dev->in = NULL; dev->out = NULL; } else @@ -1095,8 +1016,7 @@ set_ether_config (struct eth_dev *dev, int gfp_flags) /* activate non-CDC configs right away * this isn't strictly according to the RNDIS spec */ -#if defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS) - if (dev->rndis || !dev->cdc) { + if (!cdc_active (dev)) { netif_carrier_on (dev->net); if (netif_running (dev->net)) { spin_unlock (&dev->lock); @@ -1104,7 +1024,6 @@ set_ether_config (struct eth_dev *dev, int gfp_flags) spin_lock (&dev->lock); } } -#endif if (result == 0) DEBUG (dev, "qlen %d\n", qlen (gadget)); @@ -1124,6 +1043,7 @@ static void eth_reset_config (struct eth_dev *dev) netif_stop_queue (dev->net); netif_carrier_off (dev->net); + rndis_uninit(dev->rndis_config); /* disable endpoints, forcing (synchronous) completion of * pending i/o. then free the requests. @@ -1150,6 +1070,8 @@ static void eth_reset_config (struct eth_dev *dev) if (dev->status) { usb_ep_disable (dev->status_ep); } + dev->rndis = 0; + dev->cdc_filter = 0; dev->config = 0; } @@ -1162,9 +1084,6 @@ eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags) int result = 0; struct usb_gadget *gadget = dev->gadget; - if (number == dev->config) - return 0; - if (gadget_is_sa1100 (gadget) && dev->config && atomic_read (&dev->tx_qlen) != 0) { @@ -1174,12 +1093,8 @@ eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags) } eth_reset_config (dev); - /* default: pass all packets, no multicast filtering */ - dev->cdc_filter = DEFAULT_FILTER; - switch (number) { case DEV_CONFIG_VALUE: - dev->rndis = 0; result = set_ether_config (dev, gfp_flags); break; #ifdef CONFIG_USB_ETH_RNDIS @@ -1218,9 +1133,9 @@ eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags) dev->config = number; INFO (dev, "%s speed config #%d: %d mA, %s, using %s\n", speed, number, power, driver_desc, - dev->rndis + rndis_active(dev) ? "RNDIS" - : (dev->cdc + : (cdc_active(dev) ? "CDC Ethernet" : "CDC Ethernet Subset")); } @@ -1231,6 +1146,13 @@ eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags) #ifdef DEV_CONFIG_CDC +/* The interrupt endpoint is used in CDC networking models (Ethernet, ATM) + * only to notify the host about link status changes (which we support) or + * report completion of some encapsulated command (as used in RNDIS). Since + * we want this CDC Ethernet code to be vendor-neutral, we don't use that + * command mechanism; and only one status request is ever queued. + */ + static void eth_status_complete (struct usb_ep *ep, struct usb_request *req) { struct usb_cdc_notification *event = req->buf; @@ -1259,7 +1181,7 @@ static void eth_status_complete (struct usb_ep *ep, struct usb_request *req) } else if (value != -ECONNRESET) DEBUG (dev, "event %02x --> %d\n", event->bNotificationType, value); - event->bmRequestType = 0xff; + req->context = NULL; } static void issue_start_status (struct eth_dev *dev) @@ -1276,6 +1198,8 @@ static void issue_start_status (struct eth_dev *dev) * a "cancel the whole queue" primitive since any * unlink-one primitive has way too many error modes. * here, we "know" toggle is already clear... + * + * FIXME iff req->context != null just dequeue it */ usb_ep_disable (dev->status_ep); usb_ep_enable (dev->status_ep, dev->status); @@ -1292,6 +1216,8 @@ static void issue_start_status (struct eth_dev *dev) req->length = sizeof *event; req->complete = eth_status_complete; + req->context = dev; + value = usb_ep_queue (dev->status_ep, req, GFP_ATOMIC); if (value < 0) DEBUG (dev, "status buf queue --> %d\n", value); @@ -1351,9 +1277,9 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) struct eth_dev *dev = get_gadget_data (gadget); struct usb_request *req = dev->req; int value = -EOPNOTSUPP; - u16 wIndex = (__force u16) ctrl->wIndex; - u16 wValue = (__force u16) ctrl->wValue; - u16 wLength = (__force u16) ctrl->wLength; + u16 wIndex = le16_to_cpu(ctrl->wIndex); + u16 wValue = le16_to_cpu(ctrl->wValue); + u16 wLength = le16_to_cpu(ctrl->wLength); /* descriptors just go into the pre-allocated ep0 buffer, * while config change events may enable network traffic. @@ -1424,7 +1350,7 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) || !dev->config || wIndex > 1) break; - if (!dev->cdc && wIndex != 0) + if (!cdc_active(dev) && wIndex != 0) break; spin_lock (&dev->lock); @@ -1456,9 +1382,11 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) /* CDC requires the data transfers not be done from * the default interface setting ... also, setting - * the non-default interface clears filters etc. + * the non-default interface resets filters etc. */ if (wValue == 1) { + if (!cdc_active (dev)) + break; usb_ep_enable (dev->in_ep, dev->in); usb_ep_enable (dev->out_ep, dev->out); dev->cdc_filter = DEFAULT_FILTER; @@ -1492,11 +1420,11 @@ done_set_intf: || !dev->config || wIndex > 1) break; - if (!(dev->cdc || dev->rndis) && wIndex != 0) + if (!(cdc_active(dev) || rndis_active(dev)) && wIndex != 0) break; /* for CDC, iff carrier is on, data interface is active. */ - if (dev->rndis || wIndex != 1) + if (rndis_active(dev) || wIndex != 1) *(u8 *)req->buf = 0; else *(u8 *)req->buf = netif_carrier_ok (dev->net) ? 1 : 0; @@ -1509,8 +1437,7 @@ done_set_intf: * wValue = packet filter bitmap */ if (ctrl->bRequestType != (USB_TYPE_CLASS|USB_RECIP_INTERFACE) - || !dev->cdc - || dev->rndis + || !cdc_active(dev) || wLength != 0 || wIndex > 1) break; @@ -1534,7 +1461,7 @@ done_set_intf: */ case USB_CDC_SEND_ENCAPSULATED_COMMAND: if (ctrl->bRequestType != (USB_TYPE_CLASS|USB_RECIP_INTERFACE) - || !dev->rndis + || !rndis_active(dev) || wLength > USB_BUFSIZ || wValue || rndis_control_intf.bInterfaceNumber @@ -1549,7 +1476,7 @@ done_set_intf: case USB_CDC_GET_ENCAPSULATED_RESPONSE: if ((USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_INTERFACE) == ctrl->bRequestType - && dev->rndis + && rndis_active(dev) // && wLength >= 0x0400 && !wValue && rndis_control_intf.bInterfaceNumber @@ -1688,10 +1615,8 @@ rx_submit (struct eth_dev *dev, struct usb_request *req, int gfp_flags) */ size = (sizeof (struct ethhdr) + dev->net->mtu + RX_EXTRA); size += dev->out_ep->maxpacket - 1; -#ifdef CONFIG_USB_ETH_RNDIS - if (dev->rndis) + if (rndis_active(dev)) size += sizeof (struct rndis_packet_msg_type); -#endif size -= size % dev->out_ep->maxpacket; if ((skb = alloc_skb (size + NET_IP_ALIGN, gfp_flags)) == 0) { @@ -1735,11 +1660,9 @@ static void rx_complete (struct usb_ep *ep, struct usb_request *req) /* normal completion */ case 0: skb_put (skb, req->actual); -#ifdef CONFIG_USB_ETH_RNDIS /* we know MaxPacketsPerTransfer == 1 here */ - if (dev->rndis) + if (rndis_active(dev)) status = rndis_rm_hdr (skb); -#endif if (status < 0 || ETH_HLEN > skb->len || skb->len > ETH_FRAME_LEN) { @@ -1859,8 +1782,6 @@ static void rx_fill (struct eth_dev *dev, int gfp_flags) struct usb_request *req; unsigned long flags; - clear_bit (WORK_RX_MEMORY, &dev->todo); - /* fill unused rxq slots with some skb */ spin_lock_irqsave (&dev->lock, flags); while (!list_empty (&dev->rx_reqs)) { @@ -1883,11 +1804,9 @@ static void eth_work (void *_dev) { struct eth_dev *dev = _dev; - if (test_bit (WORK_RX_MEMORY, &dev->todo)) { + if (test_and_clear_bit (WORK_RX_MEMORY, &dev->todo)) { if (netif_running (dev->net)) rx_fill (dev, GFP_KERNEL); - else - clear_bit (WORK_RX_MEMORY, &dev->todo); } if (dev->todo) @@ -1971,8 +1890,7 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) * or the hardware can't use skb buffers. * or there's not enough space for any RNDIS headers we need */ -#ifdef CONFIG_USB_ETH_RNDIS - if (dev->rndis) { + if (rndis_active(dev)) { struct sk_buff *skb_rndis; skb_rndis = skb_realloc_headroom (skb, @@ -1985,7 +1903,6 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) rndis_add_hdr (skb); length = skb->len; } -#endif req->buf = skb->data; req->context = skb; req->complete = tx_complete; @@ -2018,9 +1935,7 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) } if (retval) { -#ifdef CONFIG_USB_ETH_RNDIS drop: -#endif dev->stats.tx_dropped++; dev_kfree_skb_any (skb); spin_lock_irqsave (&dev->lock, flags); @@ -2036,27 +1951,31 @@ drop: #ifdef CONFIG_USB_ETH_RNDIS -static void rndis_send_media_state (struct eth_dev *dev, int connect) -{ - if (!dev) - return; - - if (connect) { - if (rndis_signal_connect (dev->rndis_config)) - return; - } else { - if (rndis_signal_disconnect (dev->rndis_config)) - return; - } -} +/* The interrupt endpoint is used in RNDIS to notify the host when messages + * other than data packets are available ... notably the REMOTE_NDIS_*_CMPLT + * messages, but also REMOTE_NDIS_INDICATE_STATUS_MSG and potentially even + * REMOTE_NDIS_KEEPALIVE_MSG. + * + * The RNDIS control queue is processed by GET_ENCAPSULATED_RESPONSE, and + * normally just one notification will be queued. + */ + +static struct usb_request *eth_req_alloc (struct usb_ep *, unsigned, unsigned); +static void eth_req_free (struct usb_ep *ep, struct usb_request *req); static void rndis_control_ack_complete (struct usb_ep *ep, struct usb_request *req) { + struct eth_dev *dev = ep->driver_data; + if (req->status || req->actual != req->length) - DEBUG ((struct eth_dev *) ep->driver_data, + DEBUG (dev, "rndis control ack complete --> %d, %d/%d\n", req->status, req->actual, req->length); + req->context = NULL; + + if (req != dev->stat_req) + eth_req_free(ep, req); } static int rndis_control_ack (struct net_device *net) @@ -2071,11 +1990,19 @@ static int rndis_control_ack (struct net_device *net) return -ENODEV; } + /* in case queue length > 1 */ + if (resp->context) { + resp = eth_req_alloc (dev->status_ep, 8, GFP_ATOMIC); + if (!resp) + return -ENOMEM; + } + /* Send RNDIS RESPONSE_AVAILABLE notification; * USB_CDC_NOTIFY_RESPONSE_AVAILABLE should work too */ resp->length = 8; resp->complete = rndis_control_ack_complete; + resp->context = dev; *((__le32 *) resp->buf) = __constant_cpu_to_le32 (1); *((__le32 *) resp->buf + 1) = __constant_cpu_to_le32 (0); @@ -2089,6 +2016,10 @@ static int rndis_control_ack (struct net_device *net) return 0; } +#else + +#define rndis_control_ack NULL + #endif /* RNDIS */ static void eth_start (struct eth_dev *dev, int gfp_flags) @@ -2101,14 +2032,12 @@ static void eth_start (struct eth_dev *dev, int gfp_flags) /* and open the tx floodgates */ atomic_set (&dev->tx_qlen, 0); netif_wake_queue (dev->net); -#ifdef CONFIG_USB_ETH_RNDIS - if (dev->rndis) { + if (rndis_active(dev)) { rndis_set_param_medium (dev->rndis_config, NDIS_MEDIUM_802_3, BITRATE(dev->gadget)/100); - rndis_send_media_state (dev, 1); + (void) rndis_signal_connect (dev->rndis_config); } -#endif } static int eth_open (struct net_device *net) @@ -2149,28 +2078,27 @@ static int eth_stop (struct net_device *net) } } -#ifdef CONFIG_USB_ETH_RNDIS - if (dev->rndis) { + if (rndis_active(dev)) { rndis_set_param_medium (dev->rndis_config, NDIS_MEDIUM_802_3, 0); - rndis_send_media_state (dev, 0); + (void) rndis_signal_disconnect (dev->rndis_config); } -#endif return 0; } /*-------------------------------------------------------------------------*/ -static struct usb_request *eth_req_alloc (struct usb_ep *ep, unsigned size) +static struct usb_request * +eth_req_alloc (struct usb_ep *ep, unsigned size, unsigned gfp_flags) { struct usb_request *req; - req = usb_ep_alloc_request (ep, GFP_KERNEL); + req = usb_ep_alloc_request (ep, gfp_flags); if (!req) return NULL; - req->buf = kmalloc (size, GFP_KERNEL); + req->buf = kmalloc (size, gfp_flags); if (!req->buf) { usb_ep_free_request (ep, req); req = NULL; @@ -2192,10 +2120,8 @@ eth_unbind (struct usb_gadget *gadget) struct eth_dev *dev = get_gadget_data (gadget); DEBUG (dev, "unbind\n"); -#ifdef CONFIG_USB_ETH_RNDIS rndis_deregister (dev->rndis_config); rndis_exit (); -#endif /* we've already been disconnected ... no i/o is active */ if (dev->req) { @@ -2368,13 +2294,11 @@ autoconf_fail: gadget->name); return -ENODEV; } - EP_IN_NAME = in_ep->name; in_ep->driver_data = in_ep; /* claim */ out_ep = usb_ep_autoconfig (gadget, &fs_sink_desc); if (!out_ep) goto autoconf_fail; - EP_OUT_NAME = out_ep->name; out_ep->driver_data = out_ep; /* claim */ #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) @@ -2384,7 +2308,6 @@ autoconf_fail: if (cdc || rndis) { status_ep = usb_ep_autoconfig (gadget, &fs_status_desc); if (status_ep) { - EP_STATUS_NAME = status_ep->name; status_ep->driver_data = status_ep; /* claim */ } else if (rndis) { dev_err (&gadget->dev, @@ -2426,7 +2349,7 @@ autoconf_fail: hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) - if (EP_STATUS_NAME) + if (status_ep) hs_status_desc.bEndpointAddress = fs_status_desc.bEndpointAddress; #endif @@ -2499,20 +2422,23 @@ autoconf_fail: SET_ETHTOOL_OPS(net, &ops); /* preallocate control message data and buffer */ - dev->req = eth_req_alloc (gadget->ep0, USB_BUFSIZ); + dev->req = eth_req_alloc (gadget->ep0, USB_BUFSIZ, GFP_KERNEL); if (!dev->req) goto fail; dev->req->complete = eth_setup_complete; /* ... and maybe likewise for status transfer */ +#ifdef DEV_CONFIG_CDC if (dev->status_ep) { dev->stat_req = eth_req_alloc (dev->status_ep, - STATUS_BYTECOUNT); + STATUS_BYTECOUNT, GFP_KERNEL); if (!dev->stat_req) { eth_req_free (gadget->ep0, dev->req); goto fail; } + dev->stat_req->context = NULL; } +#endif /* finish hookup to lower layer ... */ dev->gadget = gadget; @@ -2526,16 +2452,16 @@ autoconf_fail: netif_stop_queue (dev->net); netif_carrier_off (dev->net); - // SET_NETDEV_DEV (dev->net, &gadget->dev); + SET_NETDEV_DEV (dev->net, &gadget->dev); status = register_netdev (dev->net); if (status < 0) goto fail1; INFO (dev, "%s, version: " DRIVER_VERSION "\n", driver_desc); INFO (dev, "using %s, OUT %s IN %s%s%s\n", gadget->name, - EP_OUT_NAME, EP_IN_NAME, - EP_STATUS_NAME ? " STATUS " : "", - EP_STATUS_NAME ? EP_STATUS_NAME : "" + out_ep->name, in_ep->name, + status_ep ? " STATUS " : "", + status_ep ? status_ep->name : "" ); INFO (dev, "MAC %02x:%02x:%02x:%02x:%02x:%02x\n", net->dev_addr [0], net->dev_addr [1], @@ -2548,7 +2474,6 @@ autoconf_fail: dev->host_mac [2], dev->host_mac [3], dev->host_mac [4], dev->host_mac [5]); -#ifdef CONFIG_USB_ETH_RNDIS if (rndis) { u32 vendorID = 0; @@ -2565,7 +2490,7 @@ fail0: /* these set up a lot of the OIDs that RNDIS needs */ rndis_set_host_mac (dev->rndis_config, dev->host_mac); if (rndis_set_param_dev (dev->rndis_config, dev->net, - &dev->stats)) + &dev->stats, &dev->cdc_filter)) goto fail0; if (rndis_set_param_vendor (dev->rndis_config, vendorID, manufacturer)) @@ -2576,7 +2501,6 @@ fail0: goto fail0; INFO (dev, "RNDIS ready\n"); } -#endif return status; @@ -2610,11 +2534,8 @@ eth_resume (struct usb_gadget *gadget) /*-------------------------------------------------------------------------*/ static struct usb_gadget_driver eth_driver = { -#ifdef CONFIG_USB_GADGET_DUALSPEED - .speed = USB_SPEED_HIGH, -#else - .speed = USB_SPEED_FULL, -#endif + .speed = DEVSPEED, + .function = (char *) driver_desc, .bind = eth_bind, .unbind = eth_unbind, diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index a9be851..4f57085 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -81,6 +81,10 @@ * removable Default false, boolean for removable media * luns=N Default N = number of filenames, number of * LUNs to support + * stall Default determined according to the type of + * USB device controller (usually true), + * boolean to permit the driver to halt + * bulk endpoints * transport=XXX Default BBB, transport name (CB, CBI, or BBB) * protocol=YYY Default SCSI, protocol name (RBC, 8020 or * ATAPI, QIC, UFI, 8070, or SCSI; @@ -91,14 +95,10 @@ * buflen=N Default N=16384, buffer size used (will be * rounded down to a multiple of * PAGE_CACHE_SIZE) - * stall Default determined according to the type of - * USB device controller (usually true), - * boolean to permit the driver to halt - * bulk endpoints * * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "ro", - * "removable", and "luns" options are available; default values are used - * for everything else. + * "removable", "luns", and "stall" options are available; default values + * are used for everything else. * * The pathnames of the backing files and the ro settings are available in * the attribute files "file" and "ro" in the lun<n> subdirectory of the @@ -342,14 +342,15 @@ static struct { int num_ros; unsigned int nluns; + int removable; + int can_stall; + char *transport_parm; char *protocol_parm; - int removable; unsigned short vendor; unsigned short product; unsigned short release; unsigned int buflen; - int can_stall; int transport_type; char *transport_name; @@ -360,11 +361,11 @@ static struct { .transport_parm = "BBB", .protocol_parm = "SCSI", .removable = 0, + .can_stall = 1, .vendor = DRIVER_VENDOR_ID, .product = DRIVER_PRODUCT_ID, .release = 0xffff, // Use controller chip type .buflen = 16384, - .can_stall = 1, }; @@ -380,6 +381,9 @@ MODULE_PARM_DESC(luns, "number of LUNs"); module_param_named(removable, mod_data.removable, bool, S_IRUGO); MODULE_PARM_DESC(removable, "true to simulate removable media"); +module_param_named(stall, mod_data.can_stall, bool, S_IRUGO); +MODULE_PARM_DESC(stall, "false to prevent bulk stalls"); + /* In the non-TEST version, only the module parameters listed above * are available. */ @@ -404,9 +408,6 @@ MODULE_PARM_DESC(release, "USB release number"); module_param_named(buflen, mod_data.buflen, uint, S_IRUGO); MODULE_PARM_DESC(buflen, "I/O buffer size"); -module_param_named(stall, mod_data.can_stall, bool, S_IRUGO); -MODULE_PARM_DESC(stall, "false to prevent bulk stalls"); - #endif /* CONFIG_USB_FILE_STORAGE_TEST */ @@ -818,7 +819,7 @@ static void inline put_be32(u8 *buf, u32 val) buf[0] = val >> 24; buf[1] = val >> 16; buf[2] = val >> 8; - buf[3] = val; + buf[3] = val & 0xff; } @@ -1276,8 +1277,8 @@ static int class_setup_req(struct fsg_dev *fsg, { struct usb_request *req = fsg->ep0req; int value = -EOPNOTSUPP; - u16 w_index = ctrl->wIndex; - u16 w_length = ctrl->wLength; + u16 w_index = le16_to_cpu(ctrl->wIndex); + u16 w_length = le16_to_cpu(ctrl->wLength); if (!fsg->config) return value; @@ -1312,7 +1313,7 @@ static int class_setup_req(struct fsg_dev *fsg, } VDBG(fsg, "get max LUN\n"); *(u8 *) req->buf = fsg->nluns - 1; - value = min(w_length, (u16) 1); + value = 1; break; } } @@ -1344,7 +1345,7 @@ static int class_setup_req(struct fsg_dev *fsg, "unknown class-specific control req " "%02x.%02x v%04x i%04x l%u\n", ctrl->bRequestType, ctrl->bRequest, - ctrl->wValue, w_index, w_length); + le16_to_cpu(ctrl->wValue), w_index, w_length); return value; } @@ -1358,9 +1359,8 @@ static int standard_setup_req(struct fsg_dev *fsg, { struct usb_request *req = fsg->ep0req; int value = -EOPNOTSUPP; - u16 w_index = ctrl->wIndex; - u16 w_value = ctrl->wValue; - u16 w_length = ctrl->wLength; + u16 w_index = le16_to_cpu(ctrl->wIndex); + u16 w_value = le16_to_cpu(ctrl->wValue); /* Usually this just stores reply data in the pre-allocated ep0 buffer, * but config change events will also reconfigure hardware. */ @@ -1374,7 +1374,7 @@ static int standard_setup_req(struct fsg_dev *fsg, case USB_DT_DEVICE: VDBG(fsg, "get device descriptor\n"); - value = min(w_length, (u16) sizeof device_desc); + value = sizeof device_desc; memcpy(req->buf, &device_desc, value); break; #ifdef CONFIG_USB_GADGET_DUALSPEED @@ -1382,7 +1382,7 @@ static int standard_setup_req(struct fsg_dev *fsg, VDBG(fsg, "get device qualifier\n"); if (!fsg->gadget->is_dualspeed) break; - value = min(w_length, (u16) sizeof dev_qualifier); + value = sizeof dev_qualifier; memcpy(req->buf, &dev_qualifier, value); break; @@ -1401,8 +1401,6 @@ static int standard_setup_req(struct fsg_dev *fsg, req->buf, w_value >> 8, w_value & 0xff); - if (value >= 0) - value = min(w_length, (u16) value); break; case USB_DT_STRING: @@ -1411,8 +1409,6 @@ static int standard_setup_req(struct fsg_dev *fsg, /* wIndex == language code */ value = usb_gadget_get_string(&stringtab, w_value & 0xff, req->buf); - if (value >= 0) - value = min(w_length, (u16) value); break; } break; @@ -1438,7 +1434,7 @@ static int standard_setup_req(struct fsg_dev *fsg, break; VDBG(fsg, "get configuration\n"); *(u8 *) req->buf = fsg->config; - value = min(w_length, (u16) 1); + value = 1; break; case USB_REQ_SET_INTERFACE: @@ -1466,14 +1462,14 @@ static int standard_setup_req(struct fsg_dev *fsg, } VDBG(fsg, "get interface\n"); *(u8 *) req->buf = 0; - value = min(w_length, (u16) 1); + value = 1; break; default: VDBG(fsg, "unknown control req %02x.%02x v%04x i%04x l%u\n", ctrl->bRequestType, ctrl->bRequest, - w_value, w_index, w_length); + w_value, w_index, le16_to_cpu(ctrl->wLength)); } return value; @@ -1485,6 +1481,7 @@ static int fsg_setup(struct usb_gadget *gadget, { struct fsg_dev *fsg = get_gadget_data(gadget); int rc; + int w_length = le16_to_cpu(ctrl->wLength); ++fsg->ep0_req_tag; // Record arrival of a new request fsg->ep0req->context = NULL; @@ -1498,9 +1495,9 @@ static int fsg_setup(struct usb_gadget *gadget, /* Respond with data/status or defer until later? */ if (rc >= 0 && rc != DELAYED_STATUS) { + rc = min(rc, w_length); fsg->ep0req->length = rc; - fsg->ep0req->zero = (rc < ctrl->wLength && - (rc % gadget->ep0->maxpacket) == 0); + fsg->ep0req->zero = rc < w_length; fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ? "ep0-in" : "ep0-out"); rc = ep0_queue(fsg); @@ -2660,7 +2657,7 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size, } } - /* Check that the LUN values are oonsistent */ + /* Check that the LUN values are consistent */ if (transport_is_bbb()) { if (fsg->lun != lun) DBG(fsg, "using LUN %d from CBW, " diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index 005db7c..ed773a9 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -70,7 +70,7 @@ MODULE_LICENSE("GPL"); * seem to behave quite as expected. Used by default. * * OUT dma documents design problems handling the common "short packet" - * transfer termination policy; it couldn't enabled by default, even + * transfer termination policy; it couldn't be enabled by default, even * if the OUT-dma abort problems had a resolution. */ static unsigned use_dma = 1; @@ -313,7 +313,7 @@ goku_free_request(struct usb_ep *_ep, struct usb_request *_req) #if defined(CONFIG_X86) #define USE_KMALLOC -#elif defined(CONFIG_MIPS) && !defined(CONFIG_NONCOHERENT_IO) +#elif defined(CONFIG_MIPS) && !defined(CONFIG_DMA_NONCOHERENT) #define USE_KMALLOC #elif defined(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE) @@ -1524,9 +1524,12 @@ static void ep0_setup(struct goku_udc *dev) /* read SETUP packet and enter DATA stage */ ctrl.bRequestType = readl(®s->bRequestType); ctrl.bRequest = readl(®s->bRequest); - ctrl.wValue = (readl(®s->wValueH) << 8) | readl(®s->wValueL); - ctrl.wIndex = (readl(®s->wIndexH) << 8) | readl(®s->wIndexL); - ctrl.wLength = (readl(®s->wLengthH) << 8) | readl(®s->wLengthL); + ctrl.wValue = cpu_to_le16((readl(®s->wValueH) << 8) + | readl(®s->wValueL)); + ctrl.wIndex = cpu_to_le16((readl(®s->wIndexH) << 8) + | readl(®s->wIndexL)); + ctrl.wLength = cpu_to_le16((readl(®s->wLengthH) << 8) + | readl(®s->wLengthL)); writel(0, ®s->SetupRecv); nuke(&dev->ep[0], 0); @@ -1548,18 +1551,20 @@ static void ep0_setup(struct goku_udc *dev) case USB_REQ_CLEAR_FEATURE: switch (ctrl.bRequestType) { case USB_RECIP_ENDPOINT: - tmp = ctrl.wIndex & 0x0f; + tmp = le16_to_cpu(ctrl.wIndex) & 0x0f; /* active endpoint */ if (tmp > 3 || (!dev->ep[tmp].desc && tmp != 0)) goto stall; - if (ctrl.wIndex & USB_DIR_IN) { + if (ctrl.wIndex & __constant_cpu_to_le16( + USB_DIR_IN)) { if (!dev->ep[tmp].is_in) goto stall; } else { if (dev->ep[tmp].is_in) goto stall; } - if (ctrl.wValue != USB_ENDPOINT_HALT) + if (ctrl.wValue != __constant_cpu_to_le16( + USB_ENDPOINT_HALT)) goto stall; if (tmp) goku_clear_halt(&dev->ep[tmp]); @@ -1571,7 +1576,7 @@ succeed: return; case USB_RECIP_DEVICE: /* device remote wakeup: always clear */ - if (ctrl.wValue != 1) + if (ctrl.wValue != __constant_cpu_to_le16(1)) goto stall; VDBG(dev, "clear dev remote wakeup\n"); goto succeed; @@ -1589,14 +1594,15 @@ succeed: #ifdef USB_TRACE VDBG(dev, "SETUP %02x.%02x v%04x i%04x l%04x\n", ctrl.bRequestType, ctrl.bRequest, - ctrl.wValue, ctrl.wIndex, ctrl.wLength); + le16_to_cpu(ctrl.wValue), le16_to_cpu(ctrl.wIndex), + le16_to_cpu(ctrl.wLength)); #endif /* hw wants to know when we're configured (or not) */ dev->req_config = (ctrl.bRequest == USB_REQ_SET_CONFIGURATION && ctrl.bRequestType == USB_RECIP_DEVICE); if (unlikely(dev->req_config)) - dev->configured = (ctrl.wValue != 0); + dev->configured = (ctrl.wValue != __constant_cpu_to_le16(0)); /* delegate everything to the gadget driver. * it may respond after this irq handler returns. diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 1e5e6dd..0208153 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -417,8 +417,8 @@ ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) goto free1; value = ep_io (data, kbuf, len); - VDEBUG (data->dev, "%s read %d OUT, status %d\n", - data->name, len, value); + VDEBUG (data->dev, "%s read %zu OUT, status %d\n", + data->name, len, (int) value); if (value >= 0 && copy_to_user (buf, kbuf, value)) value = -EFAULT; @@ -465,8 +465,8 @@ ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) } value = ep_io (data, kbuf, len); - VDEBUG (data->dev, "%s write %d IN, status %d\n", - data->name, len, value); + VDEBUG (data->dev, "%s write %zu IN, status %d\n", + data->name, len, (int) value); free1: up (&data->lock); kfree (kbuf); @@ -1318,8 +1318,8 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) struct usb_request *req = dev->req; int value = -EOPNOTSUPP; struct usb_gadgetfs_event *event; - u16 w_value = ctrl->wValue; - u16 w_length = ctrl->wLength; + u16 w_value = le16_to_cpu(ctrl->wValue); + u16 w_length = le16_to_cpu(ctrl->wLength); spin_lock (&dev->lock); dev->setup_abort = 0; diff --git a/drivers/usb/gadget/ndis.h b/drivers/usb/gadget/ndis.h index c553bbf..09e3ee4 100644 --- a/drivers/usb/gadget/ndis.h +++ b/drivers/usb/gadget/ndis.h @@ -47,17 +47,17 @@ struct NDIS_PM_WAKE_UP_CAPABILITIES { #define NDIS_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE 0x00000004 struct NDIS_PNP_CAPABILITIES { - u32 Flags; + __le32 Flags; struct NDIS_PM_WAKE_UP_CAPABILITIES WakeUpCapabilities; }; struct NDIS_PM_PACKET_PATTERN { - u32 Priority; - u32 Reserved; - u32 MaskSize; - u32 PatternOffset; - u32 PatternSize; - u32 PatternFlags; + __le32 Priority; + __le32 Reserved; + __le32 MaskSize; + __le32 PatternOffset; + __le32 PatternSize; + __le32 PatternFlags; }; diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index e47e398..13a3dbc 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -448,7 +448,7 @@ net2280_free_request (struct usb_ep *_ep, struct usb_request *_req) #elif defined(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE) #define USE_KMALLOC -#elif defined(CONFIG_MIPS) && !defined(CONFIG_NONCOHERENT_IO) +#elif defined(CONFIG_MIPS) && !defined(CONFIG_DMA_NONCOHERENT) #define USE_KMALLOC /* FIXME there are other cases, including an x86-64 one ... */ @@ -1113,7 +1113,7 @@ static void restart_dma (struct net2280_ep *ep) if (ep->in_fifo_validate) dmactl |= (1 << DMA_FIFO_VALIDATE); list_for_each_entry (entry, &ep->queue, queue) { - u32 dmacount; + __le32 dmacount; if (entry == req) continue; @@ -1238,7 +1238,7 @@ static int net2280_dequeue (struct usb_ep *_ep, struct usb_request *_req) &ep->dma->dmadesc); if (req->td->dmacount & dma_done_ie) writel (readl (&ep->dma->dmacount) - | dma_done_ie, + | le32_to_cpu(dma_done_ie), &ep->dma->dmacount); } else { struct net2280_request *prev; @@ -1779,6 +1779,9 @@ static void set_fifo_mode (struct net2280 *dev, int mode) list_add_tail (&dev->ep [6].ep.ep_list, &dev->gadget.ep_list); } +/* just declare this in any driver that really need it */ +extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode); + /** * net2280_set_fifo_mode - change allocation of fifo buffers * @gadget: access to the net2280 device that will be updated @@ -2382,9 +2385,9 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) cpu_to_le32s (&u.raw [0]); cpu_to_le32s (&u.raw [1]); - le16_to_cpus (&u.r.wValue); - le16_to_cpus (&u.r.wIndex); - le16_to_cpus (&u.r.wLength); +#define w_value le16_to_cpup (&u.r.wValue) +#define w_index le16_to_cpup (&u.r.wIndex) +#define w_length le16_to_cpup (&u.r.wLength) /* ack the irq */ writel (1 << SETUP_PACKET_INTERRUPT, &dev->regs->irqstat0); @@ -2413,25 +2416,25 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) switch (u.r.bRequest) { case USB_REQ_GET_STATUS: { struct net2280_ep *e; - u16 status; + __le32 status; /* hw handles device and interface status */ if (u.r.bRequestType != (USB_DIR_IN|USB_RECIP_ENDPOINT)) goto delegate; - if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0 - || u.r.wLength > 2) + if ((e = get_ep_by_addr (dev, w_index)) == 0 + || w_length > 2) goto do_stall; if (readl (&e->regs->ep_rsp) & (1 << SET_ENDPOINT_HALT)) - status = __constant_cpu_to_le16 (1); + status = __constant_cpu_to_le32 (1); else - status = __constant_cpu_to_le16 (0); + status = __constant_cpu_to_le32 (0); /* don't bother with a request object! */ writel (0, &dev->epregs [0].ep_irqenb); - set_fifo_bytecount (ep, u.r.wLength); - writel (status, &dev->epregs [0].ep_data); + set_fifo_bytecount (ep, w_length); + writel ((__force u32)status, &dev->epregs [0].ep_data); allow_status (ep); VDEBUG (dev, "%s stat %02x\n", ep->ep.name, status); goto next_endpoints; @@ -2443,10 +2446,10 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) /* hw handles device features */ if (u.r.bRequestType != USB_RECIP_ENDPOINT) goto delegate; - if (u.r.wValue != USB_ENDPOINT_HALT - || u.r.wLength != 0) + if (w_value != USB_ENDPOINT_HALT + || w_length != 0) goto do_stall; - if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0) + if ((e = get_ep_by_addr (dev, w_index)) == 0) goto do_stall; clear_halt (e); allow_status (ep); @@ -2460,10 +2463,10 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) /* hw handles device features */ if (u.r.bRequestType != USB_RECIP_ENDPOINT) goto delegate; - if (u.r.wValue != USB_ENDPOINT_HALT - || u.r.wLength != 0) + if (w_value != USB_ENDPOINT_HALT + || w_length != 0) goto do_stall; - if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0) + if ((e = get_ep_by_addr (dev, w_index)) == 0) goto do_stall; set_halt (e); allow_status (ep); @@ -2473,10 +2476,10 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) break; default: delegate: - VDEBUG (dev, "setup %02x.%02x v%04x i%04x " + VDEBUG (dev, "setup %02x.%02x v%04x i%04x l%04x" "ep_cfg %08x\n", u.r.bRequestType, u.r.bRequest, - u.r.wValue, u.r.wIndex, + w_value, w_index, w_length, readl (&ep->regs->ep_cfg)); spin_unlock (&dev->lock); tmp = dev->driver->setup (&dev->gadget, &u.r); @@ -2497,6 +2500,10 @@ do_stall: */ } +#undef w_value +#undef w_index +#undef w_length + next_endpoints: /* endpoint data irq ? */ scratch = stat & 0x7f; @@ -2653,7 +2660,7 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) restart_dma (ep); else if (ep->is_in && use_dma_chaining) { struct net2280_request *req; - u32 dmacount; + __le32 dmacount; /* the descriptor at the head of the chain * may still have VALID_BIT clear; that's diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 98cbcbc..a2b812a 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -52,7 +52,6 @@ #include <asm/mach-types.h> #include <asm/arch/dma.h> -#include <asm/arch/mux.h> #include <asm/arch/usb.h> #include "omap_udc.h" @@ -167,7 +166,7 @@ static int omap_ep_enable(struct usb_ep *_ep, maxp = le16_to_cpu (desc->wMaxPacketSize); if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK && maxp != ep->maxpacket) - || desc->wMaxPacketSize > ep->maxpacket + || le16_to_cpu(desc->wMaxPacketSize) > ep->maxpacket || !desc->wMaxPacketSize) { DBG("%s, bad %s maxpacket\n", __FUNCTION__, _ep->name); return -ERANGE; @@ -214,7 +213,7 @@ static int omap_ep_enable(struct usb_ep *_ep, ep->has_dma = 0; ep->lch = -1; use_ep(ep, UDC_EP_SEL); - UDC_CTRL_REG = UDC_RESET_EP; + UDC_CTRL_REG = udc->clr_halt; ep->ackwait = 0; deselect_ep(); @@ -253,7 +252,7 @@ static int omap_ep_disable(struct usb_ep *_ep) } spin_lock_irqsave(&ep->udc->lock, flags); - ep->desc = 0; + ep->desc = NULL; nuke (ep, -ESHUTDOWN); ep->ep.maxpacket = ep->maxpacket; ep->has_dma = 0; @@ -388,8 +387,8 @@ done(struct omap_ep *ep, struct omap_req *req, int status) /*-------------------------------------------------------------------------*/ -#define FIFO_FULL (UDC_NON_ISO_FIFO_FULL | UDC_ISO_FIFO_FULL) -#define FIFO_UNWRITABLE (UDC_EP_HALTED | FIFO_FULL) +#define UDC_FIFO_FULL (UDC_NON_ISO_FIFO_FULL | UDC_ISO_FIFO_FULL) +#define UDC_FIFO_UNWRITABLE (UDC_EP_HALTED | UDC_FIFO_FULL) #define FIFO_EMPTY (UDC_NON_ISO_FIFO_EMPTY | UDC_ISO_FIFO_EMPTY) #define FIFO_UNREADABLE (UDC_EP_HALTED | FIFO_EMPTY) @@ -433,7 +432,7 @@ static int write_fifo(struct omap_ep *ep, struct omap_req *req) /* PIO-IN isn't double buffered except for iso */ ep_stat = UDC_STAT_FLG_REG; - if (ep_stat & FIFO_UNWRITABLE) + if (ep_stat & UDC_FIFO_UNWRITABLE) return 0; count = ep->ep.maxpacket; @@ -504,7 +503,7 @@ static int read_fifo(struct omap_ep *ep, struct omap_req *req) if (ep_stat & UDC_EP_HALTED) break; - if (ep_stat & FIFO_FULL) + if (ep_stat & UDC_FIFO_FULL) avail = ep->ep.maxpacket; else { avail = UDC_RXFSTAT_REG; @@ -538,6 +537,32 @@ static int read_fifo(struct omap_ep *ep, struct omap_req *req) /*-------------------------------------------------------------------------*/ +static inline dma_addr_t dma_csac(unsigned lch) +{ + dma_addr_t csac; + + /* omap 3.2/3.3 erratum: sometimes 0 is returned if CSAC/CDAC is + * read before the DMA controller finished disabling the channel. + */ + csac = omap_readw(OMAP_DMA_CSAC(lch)); + if (csac == 0) + csac = omap_readw(OMAP_DMA_CSAC(lch)); + return csac; +} + +static inline dma_addr_t dma_cdac(unsigned lch) +{ + dma_addr_t cdac; + + /* omap 3.2/3.3 erratum: sometimes 0 is returned if CSAC/CDAC is + * read before the DMA controller finished disabling the channel. + */ + cdac = omap_readw(OMAP_DMA_CDAC(lch)); + if (cdac == 0) + cdac = omap_readw(OMAP_DMA_CDAC(lch)); + return cdac; +} + static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start) { dma_addr_t end; @@ -548,7 +573,7 @@ static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start) if (cpu_is_omap15xx()) return 0; - end = omap_readw(OMAP_DMA_CSAC(ep->lch)); + end = dma_csac(ep->lch); if (end == ep->dma_counter) return 0; @@ -559,14 +584,14 @@ static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start) } #define DMA_DEST_LAST(x) (cpu_is_omap15xx() \ - ? OMAP_DMA_CSAC(x) /* really: CPC */ \ - : OMAP_DMA_CDAC(x)) + ? omap_readw(OMAP_DMA_CSAC(x)) /* really: CPC */ \ + : dma_cdac(x)) static u16 dma_dest_len(struct omap_ep *ep, dma_addr_t start) { dma_addr_t end; - end = omap_readw(DMA_DEST_LAST(ep->lch)); + end = DMA_DEST_LAST(ep->lch); if (end == ep->dma_counter) return 0; @@ -593,7 +618,7 @@ static void next_in_dma(struct omap_ep *ep, struct omap_req *req) : OMAP_DMA_SYNC_ELEMENT; /* measure length in either bytes or packets */ - if ((cpu_is_omap16xx() && length <= (UDC_TXN_TSC + 1)) + if ((cpu_is_omap16xx() && length <= UDC_TXN_TSC) || (cpu_is_omap15xx() && length < ep->maxpacket)) { txdma_ctrl = UDC_TXN_EOT | length; omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8, @@ -602,15 +627,15 @@ static void next_in_dma(struct omap_ep *ep, struct omap_req *req) length = min(length / ep->maxpacket, (unsigned) UDC_TXN_TSC + 1); txdma_ctrl = length; - omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8, - ep->ep.maxpacket, length, sync_mode); + omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16, + ep->ep.maxpacket >> 1, length, sync_mode); length *= ep->maxpacket; } omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_EMIFF, OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual); omap_start_dma(ep->lch); - ep->dma_counter = omap_readw(OMAP_DMA_CSAC(ep->lch)); + ep->dma_counter = dma_csac(ep->lch); UDC_DMA_IRQ_EN_REG |= UDC_TX_DONE_IE(ep->dma_channel); UDC_TXDMA_REG(ep->dma_channel) = UDC_TXN_START | txdma_ctrl; req->dma_bytes = length; @@ -650,12 +675,12 @@ static void next_out_dma(struct omap_ep *ep, struct omap_req *req) packets = (req->req.length - req->req.actual) / ep->ep.maxpacket; packets = min(packets, (unsigned)UDC_RXN_TC + 1); req->dma_bytes = packets * ep->ep.maxpacket; - omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8, - ep->ep.maxpacket, packets, + omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16, + ep->ep.maxpacket >> 1, packets, OMAP_DMA_SYNC_ELEMENT); omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_EMIFF, OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual); - ep->dma_counter = omap_readw(DMA_DEST_LAST(ep->lch)); + ep->dma_counter = DMA_DEST_LAST(ep->lch); UDC_RXDMA_REG(ep->dma_channel) = UDC_RXN_STOP | (packets - 1); UDC_DMA_IRQ_EN_REG |= UDC_RX_EOT_IE(ep->dma_channel); @@ -763,7 +788,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel) reg = UDC_TXDMA_CFG_REG; else reg = UDC_RXDMA_CFG_REG; - reg |= 1 << 12; /* "pulse" activated */ + reg |= UDC_DMA_REQ; /* "pulse" activated */ ep->dma_channel = 0; ep->lch = -1; @@ -787,6 +812,11 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel) ep->ep.name, dma_error, ep, &ep->lch); if (status == 0) { UDC_TXDMA_CFG_REG = reg; + /* EMIFF */ + omap_set_dma_src_burst_mode(ep->lch, + OMAP_DMA_DATA_BURST_4); + omap_set_dma_src_data_pack(ep->lch, 1); + /* TIPB */ omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_TIPB, OMAP_DMA_AMODE_CONSTANT, @@ -797,10 +827,15 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel) ep->ep.name, dma_error, ep, &ep->lch); if (status == 0) { UDC_RXDMA_CFG_REG = reg; + /* TIPB */ omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_TIPB, OMAP_DMA_AMODE_CONSTANT, (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG)); + /* EMIFF */ + omap_set_dma_dest_burst_mode(ep->lch, + OMAP_DMA_DATA_BURST_4); + omap_set_dma_dest_data_pack(ep->lch, 1); } } if (status) @@ -856,7 +891,7 @@ static void dma_channel_release(struct omap_ep *ep) if (!list_empty(&ep->queue)) req = container_of(ep->queue.next, struct omap_req, queue); else - req = 0; + req = NULL; active = ((1 << 7) & omap_readl(OMAP_DMA_CCR(ep->lch))) != 0; @@ -865,9 +900,13 @@ static void dma_channel_release(struct omap_ep *ep) (ep->bEndpointAddress & USB_DIR_IN) ? 't' : 'r', ep->dma_channel - 1, req); + /* NOTE: re-setting RX_REQ/TX_REQ because of a chip bug (before + * OMAP 1710 ES2.0) where reading the DMA_CFG can clear them. + */ + /* wait till current packet DMA finishes, and fifo empties */ if (ep->bEndpointAddress & USB_DIR_IN) { - UDC_TXDMA_CFG_REG &= ~mask; + UDC_TXDMA_CFG_REG = (UDC_TXDMA_CFG_REG & ~mask) | UDC_DMA_REQ; if (req) { finish_in_dma(ep, req, -ECONNRESET); @@ -880,7 +919,7 @@ static void dma_channel_release(struct omap_ep *ep) while (UDC_TXDMA_CFG_REG & mask) udelay(10); } else { - UDC_RXDMA_CFG_REG &= ~mask; + UDC_RXDMA_CFG_REG = (UDC_RXDMA_CFG_REG & ~mask) | UDC_DMA_REQ; /* dma empties the fifo */ while (UDC_RXDMA_CFG_REG & mask) @@ -997,18 +1036,19 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags) UDC_IRQ_EN_REG = irq_en; } - /* STATUS is reverse direction */ - UDC_EP_NUM_REG = is_in - ? UDC_EP_SEL - : (UDC_EP_SEL|UDC_EP_DIR); + /* STATUS for zero length DATA stages is + * always an IN ... even for IN transfers, + * a wierd case which seem to stall OMAP. + */ + UDC_EP_NUM_REG = (UDC_EP_SEL|UDC_EP_DIR); UDC_CTRL_REG = UDC_CLR_EP; UDC_CTRL_REG = UDC_SET_FIFO_EN; - UDC_EP_NUM_REG = udc->ep0_in ? 0 : UDC_EP_DIR; + UDC_EP_NUM_REG = UDC_EP_DIR; /* cleanup */ udc->ep0_pending = 0; done(ep, req, 0); - req = 0; + req = NULL; /* non-empty DATA stage */ } else if (is_in) { @@ -1029,7 +1069,7 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags) (is_in ? next_in_dma : next_out_dma)(ep, req); else if (req) { if ((is_in ? write_fifo : read_fifo)(ep, req) == 1) - req = 0; + req = NULL; deselect_ep(); if (!is_in) { UDC_CTRL_REG = UDC_SET_FIFO_EN; @@ -1041,7 +1081,7 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags) irq_wait: /* irq handler advances the queue */ - if (req != 0) + if (req != NULL) list_add_tail(&req->queue, &ep->queue); spin_unlock_irqrestore(&udc->lock, flags); @@ -1140,7 +1180,7 @@ static int omap_ep_set_halt(struct usb_ep *_ep, int value) dma_channel_claim(ep, channel); } else { use_ep(ep, 0); - UDC_CTRL_REG = UDC_RESET_EP; + UDC_CTRL_REG = ep->udc->clr_halt; ep->ackwait = 0; if (!(ep->bEndpointAddress & USB_DIR_IN)) { UDC_CTRL_REG = UDC_SET_FIFO_EN; @@ -1238,6 +1278,8 @@ static int can_pullup(struct omap_udc *udc) static void pullup_enable(struct omap_udc *udc) { + udc->gadget.dev.parent->power.power_state = PMSG_ON; + udc->gadget.dev.power.power_state = PMSG_ON; UDC_SYSCON1_REG |= UDC_PULLUP_EN; #ifndef CONFIG_USB_OTG if (!cpu_is_omap15xx()) @@ -1382,7 +1424,7 @@ static void update_otg(struct omap_udc *udc) static void ep0_irq(struct omap_udc *udc, u16 irq_src) { struct omap_ep *ep0 = &udc->ep[0]; - struct omap_req *req = 0; + struct omap_req *req = NULL; ep0->irqs++; @@ -1438,7 +1480,7 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src) if (req) done(ep0, req, 0); } - req = 0; + req = NULL; } else if (stat & UDC_STALL) { UDC_CTRL_REG = UDC_CLR_HALT; UDC_EP_NUM_REG = UDC_EP_DIR; @@ -1511,9 +1553,10 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src) u.word[3] = UDC_DATA_REG; UDC_EP_NUM_REG = 0; } while (UDC_IRQ_SRC_REG & UDC_SETUP); - le16_to_cpus (&u.r.wValue); - le16_to_cpus (&u.r.wIndex); - le16_to_cpus (&u.r.wLength); + +#define w_value le16_to_cpup (&u.r.wValue) +#define w_index le16_to_cpup (&u.r.wIndex) +#define w_length le16_to_cpup (&u.r.wLength) /* Delegate almost all control requests to the gadget driver, * except for a handful of ch9 status/feature requests that @@ -1529,11 +1572,11 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src) /* udc needs to know when ep != 0 is valid */ if (u.r.bRequestType != USB_RECIP_DEVICE) goto delegate; - if (u.r.wLength != 0) + if (w_length != 0) goto do_stall; udc->ep0_set_config = 1; - udc->ep0_reset_config = (u.r.wValue == 0); - VDBG("set config %d\n", u.r.wValue); + udc->ep0_reset_config = (w_value == 0); + VDBG("set config %d\n", w_value); /* update udc NOW since gadget driver may start * queueing requests immediately; clear config @@ -1549,23 +1592,28 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src) /* clear endpoint halt */ if (u.r.bRequestType != USB_RECIP_ENDPOINT) goto delegate; - if (u.r.wValue != USB_ENDPOINT_HALT - || u.r.wLength != 0) + if (w_value != USB_ENDPOINT_HALT + || w_length != 0) goto do_stall; - ep = &udc->ep[u.r.wIndex & 0xf]; + ep = &udc->ep[w_index & 0xf]; if (ep != ep0) { - if (u.r.wIndex & USB_DIR_IN) + if (w_index & USB_DIR_IN) ep += 16; if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC || !ep->desc) goto do_stall; use_ep(ep, 0); - UDC_CTRL_REG = UDC_RESET_EP; + UDC_CTRL_REG = udc->clr_halt; ep->ackwait = 0; if (!(ep->bEndpointAddress & USB_DIR_IN)) { UDC_CTRL_REG = UDC_SET_FIFO_EN; ep->ackwait = 1 + ep->double_buf; } + /* NOTE: assumes the host behaves sanely, + * only clearing real halts. Else we may + * need to kill pending transfers and then + * restart the queue... very messy for DMA! + */ } VDBG("%s halt cleared by host\n", ep->name); goto ep0out_status_stage; @@ -1573,11 +1621,11 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src) /* set endpoint halt */ if (u.r.bRequestType != USB_RECIP_ENDPOINT) goto delegate; - if (u.r.wValue != USB_ENDPOINT_HALT - || u.r.wLength != 0) + if (w_value != USB_ENDPOINT_HALT + || w_length != 0) goto do_stall; - ep = &udc->ep[u.r.wIndex & 0xf]; - if (u.r.wIndex & USB_DIR_IN) + ep = &udc->ep[w_index & 0xf]; + if (w_index & USB_DIR_IN) ep += 16; if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC || ep == ep0 || !ep->desc) @@ -1615,13 +1663,13 @@ ep0out_status_stage: UDC_CTRL_REG = UDC_SET_FIFO_EN; UDC_EP_NUM_REG = UDC_EP_DIR; status = 0; - VDBG("GET_STATUS, interface %d\n", u.r.wIndex); + VDBG("GET_STATUS, interface %d\n", w_index); /* next, status stage */ break; default: delegate: /* activate the ep0out fifo right away */ - if (!udc->ep0_in && u.r.wLength) { + if (!udc->ep0_in && w_length) { UDC_EP_NUM_REG = 0; UDC_CTRL_REG = UDC_SET_FIFO_EN; } @@ -1632,7 +1680,11 @@ delegate: */ VDBG("SETUP %02x.%02x v%04x i%04x l%04x\n", u.r.bRequestType, u.r.bRequest, - u.r.wValue, u.r.wIndex, u.r.wLength); + w_value, w_index, w_length); + +#undef w_value +#undef w_index +#undef w_length /* The gadget driver may return an error here, * causing an immediate protocol stall. @@ -2013,7 +2065,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) udc->softconnect = 1; /* hook up the driver */ - driver->driver.bus = 0; + driver->driver.bus = NULL; udc->driver = driver; udc->gadget.dev.driver = &driver->driver; spin_unlock_irqrestore(&udc->lock, flags); @@ -2021,8 +2073,8 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) status = driver->bind (&udc->gadget); if (status) { DBG("bind to %s --> %d\n", driver->driver.name, status); - udc->gadget.dev.driver = 0; - udc->driver = 0; + udc->gadget.dev.driver = NULL; + udc->driver = NULL; goto done; } DBG("bound to driver %s\n", driver->driver.name); @@ -2035,8 +2087,8 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) if (status < 0) { ERR("can't bind to transceiver\n"); driver->unbind (&udc->gadget); - udc->gadget.dev.driver = 0; - udc->driver = 0; + udc->gadget.dev.driver = NULL; + udc->driver = NULL; goto done; } } else { @@ -2071,7 +2123,7 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) omap_vbus_session(&udc->gadget, 0); if (udc->transceiver) - (void) otg_set_peripheral(udc->transceiver, 0); + (void) otg_set_peripheral(udc->transceiver, NULL); else pullup_disable(udc); @@ -2080,9 +2132,8 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) spin_unlock_irqrestore(&udc->lock, flags); driver->unbind(&udc->gadget); - udc->gadget.dev.driver = 0; - udc->driver = 0; - + udc->gadget.dev.driver = NULL; + udc->driver = NULL; DBG("unregistered driver '%s'\n", driver->driver.name); return status; @@ -2178,14 +2229,14 @@ static int proc_otg_show(struct seq_file *s) tmp = OTG_REV_REG; trans = USB_TRANSCEIVER_CTRL_REG; - seq_printf(s, "OTG rev %d.%d, transceiver_ctrl %03x\n", + seq_printf(s, "\nOTG rev %d.%d, transceiver_ctrl %05x\n", tmp >> 4, tmp & 0xf, trans); tmp = OTG_SYSCON_1_REG; seq_printf(s, "otg_syscon1 %08x usb2 %s, usb1 %s, usb0 %s," FOURBITS "\n", tmp, trx_mode(USB2_TRX_MODE(tmp), trans & CONF_USB2_UNI_R), trx_mode(USB1_TRX_MODE(tmp), trans & CONF_USB1_UNI_R), - (USB0_TRX_MODE(tmp) == 0) + (USB0_TRX_MODE(tmp) == 0 && !cpu_is_omap1710()) ? "internal" : trx_mode(USB0_TRX_MODE(tmp), 1), (tmp & OTG_IDLE_EN) ? " !otg" : "", @@ -2235,6 +2286,7 @@ static int proc_otg_show(struct seq_file *s) seq_printf(s, "otg_outctrl %04x" "\n", tmp); tmp = OTG_TEST_REG; seq_printf(s, "otg_test %04x" "\n", tmp); + return 0; } static int proc_udc_show(struct seq_file *s, void *_) @@ -2378,7 +2430,7 @@ static int proc_udc_show(struct seq_file *s, void *_) static int proc_udc_open(struct inode *inode, struct file *file) { - return single_open(file, proc_udc_show, 0); + return single_open(file, proc_udc_show, NULL); } static struct file_operations proc_ops = { @@ -2399,7 +2451,7 @@ static void create_proc_file(void) static void remove_proc_file(void) { - remove_proc_entry(proc_filename, 0); + remove_proc_entry(proc_filename, NULL); } #else @@ -2414,6 +2466,10 @@ static inline void remove_proc_file(void) {} /* Before this controller can enumerate, we need to pick an endpoint * configuration, or "fifo_mode" That involves allocating 2KB of packet * buffer space among the endpoints we'll be operating. + * + * NOTE: as of OMAP 1710 ES2.0, writing a new endpoint config when + * UDC_SYSCON_1_REG.CFG_LOCK is set can now work. We won't use that + * capability yet though. */ static unsigned __init omap_ep_setup(char *name, u8 addr, u8 type, @@ -2505,7 +2561,7 @@ static void omap_udc_release(struct device *dev) { complete(udc->done); kfree (udc); - udc = 0; + udc = NULL; } static int __init @@ -2577,23 +2633,33 @@ omap_udc_setup(struct platform_device *odev, struct otg_transceiver *xceiv) case 1: OMAP_BULK_EP("ep1in", USB_DIR_IN | 1); OMAP_BULK_EP("ep2out", USB_DIR_OUT | 2); + OMAP_INT_EP("ep9in", USB_DIR_IN | 9, 16); + OMAP_BULK_EP("ep3in", USB_DIR_IN | 3); OMAP_BULK_EP("ep4out", USB_DIR_OUT | 4); + OMAP_INT_EP("ep10in", USB_DIR_IN | 10, 16); OMAP_BULK_EP("ep5in", USB_DIR_IN | 5); OMAP_BULK_EP("ep5out", USB_DIR_OUT | 5); + OMAP_INT_EP("ep11in", USB_DIR_IN | 11, 16); + OMAP_BULK_EP("ep6in", USB_DIR_IN | 6); OMAP_BULK_EP("ep6out", USB_DIR_OUT | 6); + OMAP_INT_EP("ep12in", USB_DIR_IN | 12, 16); OMAP_BULK_EP("ep7in", USB_DIR_IN | 7); OMAP_BULK_EP("ep7out", USB_DIR_OUT | 7); + OMAP_INT_EP("ep13in", USB_DIR_IN | 13, 16); + OMAP_INT_EP("ep13out", USB_DIR_OUT | 13, 16); + OMAP_BULK_EP("ep8in", USB_DIR_IN | 8); OMAP_BULK_EP("ep8out", USB_DIR_OUT | 8); + OMAP_INT_EP("ep14in", USB_DIR_IN | 14, 16); + OMAP_INT_EP("ep14out", USB_DIR_OUT | 14, 16); + + OMAP_BULK_EP("ep15in", USB_DIR_IN | 15); + OMAP_BULK_EP("ep15out", USB_DIR_OUT | 15); - OMAP_INT_EP("ep9in", USB_DIR_IN | 9, 16); - OMAP_INT_EP("ep10out", USB_DIR_IN | 10, 16); - OMAP_INT_EP("ep11in", USB_DIR_IN | 9, 16); - OMAP_INT_EP("ep12out", USB_DIR_IN | 10, 16); break; #ifdef USE_ISO @@ -2640,8 +2706,8 @@ static int __init omap_udc_probe(struct device *dev) struct platform_device *odev = to_platform_device(dev); int status = -ENODEV; int hmc; - struct otg_transceiver *xceiv = 0; - const char *type = 0; + struct otg_transceiver *xceiv = NULL; + const char *type = NULL; struct omap_usb_config *config = dev->platform_data; /* NOTE: "knows" the order of the resources! */ @@ -2676,54 +2742,78 @@ static int __init omap_udc_probe(struct device *dev) FUNC_MUX_CTRL_0_REG = tmp; } } else { + /* The transceiver may package some GPIO logic or handle + * loopback and/or transceiverless setup; if we find one, + * use it. Except for OTG, we don't _need_ to talk to one; + * but not having one probably means no VBUS detection. + */ + xceiv = otg_get_transceiver(); + if (xceiv) + type = xceiv->label; + else if (config->otg) { + DBG("OTG requires external transceiver!\n"); + goto cleanup0; + } + hmc = HMC_1610; switch (hmc) { + case 0: /* POWERUP DEFAULT == 0 */ + case 4: + case 12: + case 20: + if (!cpu_is_omap1710()) { + type = "integrated"; + break; + } + /* FALL THROUGH */ case 3: case 11: case 16: case 19: case 25: - xceiv = otg_get_transceiver(); if (!xceiv) { DBG("external transceiver not registered!\n"); - if (config->otg) - goto cleanup0; - type = "(unknown external)"; - } else - type = xceiv->label; - break; - case 0: /* POWERUP DEFAULT == 0 */ - case 4: - case 12: - case 20: - type = "INTEGRATED"; + type = "unknown"; + } break; case 21: /* internal loopback */ - type = "(loopback)"; + type = "loopback"; break; case 14: /* transceiverless */ - type = "(none)"; + if (cpu_is_omap1710()) + goto bad_on_1710; + /* FALL THROUGH */ + case 13: + case 15: + type = "no"; break; default: +bad_on_1710: ERR("unrecognized UDC HMC mode %d\n", hmc); - return -ENODEV; + goto cleanup0; } } - INFO("hmc mode %d, transceiver %s\n", hmc, type); + INFO("hmc mode %d, %s transceiver\n", hmc, type); /* a "gadget" abstracts/virtualizes the controller */ status = omap_udc_setup(odev, xceiv); if (status) { goto cleanup0; } - xceiv = 0; + xceiv = NULL; // "udc" is now valid pullup_disable(udc); #if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) udc->gadget.is_otg = (config->otg != 0); #endif + /* starting with omap1710 es2.0, clear toggle is a separate bit */ + if (UDC_REV_REG >= 0x61) + udc->clr_halt = UDC_RESET_EP | UDC_CLRDATA_TOGGLE; + else + udc->clr_halt = UDC_RESET_EP; + /* USB general purpose IRQ: ep0, state changes, dma, etc */ status = request_irq(odev->resource[1].start, omap_udc_irq, SA_SAMPLE_RANDOM, driver_name, udc); @@ -2765,7 +2855,7 @@ cleanup2: cleanup1: kfree (udc); - udc = 0; + udc = NULL; cleanup0: if (xceiv) @@ -2788,7 +2878,7 @@ static int __exit omap_udc_remove(struct device *dev) pullup_disable(udc); if (udc->transceiver) { put_device(udc->transceiver->dev); - udc->transceiver = 0; + udc->transceiver = NULL; } UDC_SYSCON1_REG = 0; @@ -2809,13 +2899,32 @@ static int __exit omap_udc_remove(struct device *dev) return 0; } -static int omap_udc_suspend(struct device *dev, pm_message_t state, u32 level) +/* suspend/resume/wakeup from sysfs (echo > power/state) or when the + * system is forced into deep sleep + * + * REVISIT we should probably reject suspend requests when there's a host + * session active, rather than disconnecting, at least on boards that can + * report VBUS irqs (UDC_DEVSTAT_REG.UDC_ATT). And in any case, we need to + * make host resumes and VBUS detection trigger OMAP wakeup events; that + * may involve talking to an external transceiver (e.g. isp1301). + */ +static int omap_udc_suspend(struct device *dev, pm_message_t message, u32 level) { - if (level != 0) + u32 devstat; + + if (level != SUSPEND_POWER_DOWN) return 0; + devstat = UDC_DEVSTAT_REG; + + /* we're requesting 48 MHz clock if the pullup is enabled + * (== we're attached to the host) and we're not suspended, + * which would prevent entry to deep sleep... + */ + if ((devstat & UDC_ATT) != 0 && (devstat & UDC_SUS) == 0) { + WARN("session active; suspend requires disconnect\n"); + omap_pullup(&udc->gadget, 0); + } - DBG("suspend, state %d\n", state); - omap_pullup(&udc->gadget, 0); udc->gadget.dev.power.power_state = PMSG_SUSPEND; udc->gadget.dev.parent->power.power_state = PMSG_SUSPEND; return 0; @@ -2823,7 +2932,7 @@ static int omap_udc_suspend(struct device *dev, pm_message_t state, u32 level) static int omap_udc_resume(struct device *dev, u32 level) { - if (level != 0) + if (level != RESUME_POWER_ON) return 0; DBG("resume + wakeup/SRP\n"); diff --git a/drivers/usb/gadget/omap_udc.h b/drivers/usb/gadget/omap_udc.h index c9e6854..652ee46 100644 --- a/drivers/usb/gadget/omap_udc.h +++ b/drivers/usb/gadget/omap_udc.h @@ -20,6 +20,7 @@ #define UDC_CTRL_REG UDC_REG(0x0C) /* Endpoint control */ # define UDC_CLR_HALT (1 << 7) # define UDC_SET_HALT (1 << 6) +# define UDC_CLRDATA_TOGGLE (1 << 3) # define UDC_SET_FIFO_EN (1 << 2) # define UDC_CLR_EP (1 << 1) # define UDC_RESET_EP (1 << 0) @@ -99,6 +100,7 @@ /* DMA configuration registers: up to three channels in each direction. */ #define UDC_RXDMA_CFG_REG UDC_REG(0x40) /* 3 eps for RX DMA */ +# define UDC_DMA_REQ (1 << 12) #define UDC_TXDMA_CFG_REG UDC_REG(0x44) /* 3 eps for TX DMA */ #define UDC_DATA_DMA_REG UDC_REG(0x48) /* rx/tx fifo addr */ @@ -162,6 +164,7 @@ struct omap_udc { spinlock_t lock; struct omap_ep ep[32]; u16 devstat; + u16 clr_halt; struct otg_transceiver *transceiver; struct list_head iso; unsigned softconnect:1; @@ -171,7 +174,6 @@ struct omap_udc { unsigned ep0_set_config:1; unsigned ep0_reset_config:1; unsigned ep0_setup:1; - struct completion *done; }; diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index b8b4524..6a0b957 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -1,6 +1,6 @@ /* * linux/drivers/usb/gadget/pxa2xx_udc.c - * Intel PXA2xx and IXP4xx on-chip full speed USB device controllers + * Intel PXA25x and IXP4xx on-chip full speed USB device controllers * * Copyright (C) 2002 Intrinsyc, Inc. (Frank Becker) * Copyright (C) 2003 Robert Schwebel, Pengutronix @@ -63,7 +63,7 @@ /* - * This driver handles the USB Device Controller (UDC) in Intel's PXA 2xx + * This driver handles the USB Device Controller (UDC) in Intel's PXA 25x * series processors. The UDC for the IXP 4xx series is very similar. * There are fifteen endpoints, in addition to ep0. * @@ -79,8 +79,8 @@ * pxa250 a0/a1 b0/b1/b2 sure act like they're still there. */ -#define DRIVER_VERSION "14-Dec-2003" -#define DRIVER_DESC "PXA 2xx USB Device Controller driver" +#define DRIVER_VERSION "4-May-2005" +#define DRIVER_DESC "PXA 25x USB Device Controller driver" static const char driver_name [] = "pxa2xx_udc"; @@ -290,6 +290,7 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep, static int pxa2xx_ep_disable (struct usb_ep *_ep) { struct pxa2xx_ep *ep; + unsigned long flags; ep = container_of (_ep, struct pxa2xx_ep, ep); if (!_ep || !ep->desc) { @@ -297,6 +298,8 @@ static int pxa2xx_ep_disable (struct usb_ep *_ep) _ep ? ep->ep.name : NULL); return -EINVAL; } + local_irq_save(flags); + nuke (ep, -ESHUTDOWN); #ifdef USE_DMA @@ -313,6 +316,7 @@ static int pxa2xx_ep_disable (struct usb_ep *_ep) ep->desc = NULL; ep->stopped = 1; + local_irq_restore(flags); DBG(DBG_VERBOSE, "%s disabled\n", _ep->name); return 0; } @@ -971,10 +975,10 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags) kick_dma(ep, req); #endif /* can the FIFO can satisfy the request immediately? */ - } else if ((ep->bEndpointAddress & USB_DIR_IN) != 0 - && (*ep->reg_udccs & UDCCS_BI_TFS) != 0 - && write_fifo(ep, req)) { - req = NULL; + } else if ((ep->bEndpointAddress & USB_DIR_IN) != 0) { + if ((*ep->reg_udccs & UDCCS_BI_TFS) != 0 + && write_fifo(ep, req)) + req = NULL; } else if ((*ep->reg_udccs & UDCCS_BO_RFS) != 0 && read_fifo(ep, req)) { req = NULL; @@ -1290,7 +1294,7 @@ udc_proc_read(char *page, char **start, off_t off, int count, "%s version: %s\nGadget driver: %s\nHost %s\n\n", driver_name, DRIVER_VERSION SIZE_STR DMASTR, dev->driver ? dev->driver->driver.name : "(none)", - is_usb_connected() ? "full speed" : "disconnected"); + is_vbus_present() ? "full speed" : "disconnected"); size -= t; next += t; @@ -1339,7 +1343,7 @@ udc_proc_read(char *page, char **start, off_t off, int count, next += t; } - if (!is_usb_connected() || !dev->driver) + if (!is_vbus_present() || !dev->driver) goto done; t = scnprintf(next, size, "ep0 IN %lu/%lu, OUT %lu/%lu\nirqs %lu\n\n", @@ -1454,7 +1458,7 @@ static void udc_disable(struct pxa2xx_udc *dev) UFNRH = UFNRH_SIM; /* if hardware supports it, disconnect from usb */ - make_usb_disappear(); + pullup_off(); udc_clear_mask_UDCCR(UDCCR_UDE); @@ -1567,7 +1571,7 @@ static void udc_enable (struct pxa2xx_udc *dev) UICR0 &= ~UICR0_IM0; /* if hardware supports it, pullup D+ and wait for reset */ - let_usb_appear(); + pullup_on(); } @@ -2052,10 +2056,10 @@ pxa2xx_udc_irq(int irq, void *_dev, struct pt_regs *r) if (unlikely(udccr & UDCCR_SUSIR)) { udc_ack_int_UDCCR(UDCCR_SUSIR); handled = 1; - DBG(DBG_VERBOSE, "USB suspend%s\n", is_usb_connected() + DBG(DBG_VERBOSE, "USB suspend%s\n", is_vbus_present() ? "" : "+disconnect"); - if (!is_usb_connected()) + if (!is_vbus_present()) stop_activity(dev, dev->driver); else if (dev->gadget.speed != USB_SPEED_UNKNOWN && dev->driver @@ -2073,7 +2077,7 @@ pxa2xx_udc_irq(int irq, void *_dev, struct pt_regs *r) if (dev->gadget.speed != USB_SPEED_UNKNOWN && dev->driver && dev->driver->resume - && is_usb_connected()) + && is_vbus_present()) dev->driver->resume(&dev->gadget); } @@ -2509,7 +2513,7 @@ static int __init pxa2xx_udc_probe(struct device *_dev) udc_disable(dev); udc_reinit(dev); - dev->vbus = is_usb_connected(); + dev->vbus = is_vbus_present(); /* irq setup after old hardware state is cleaned up */ retval = request_irq(IRQ_USB, pxa2xx_udc_irq, @@ -2555,6 +2559,12 @@ lubbock_fail0: return 0; } + +static void pxa2xx_udc_shutdown(struct device *_dev) +{ + pullup_off(); +} + static int __exit pxa2xx_udc_remove(struct device *_dev) { struct pxa2xx_udc *dev = dev_get_drvdata(_dev); @@ -2624,6 +2634,7 @@ static struct device_driver udc_driver = { .name = "pxa2xx-udc", .bus = &platform_bus_type, .probe = pxa2xx_udc_probe, + .shutdown = pxa2xx_udc_shutdown, .remove = __exit_p(pxa2xx_udc_remove), .suspend = pxa2xx_udc_suspend, .resume = pxa2xx_udc_resume, diff --git a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h index 1f3a7d9..d0bc396 100644 --- a/drivers/usb/gadget/pxa2xx_udc.h +++ b/drivers/usb/gadget/pxa2xx_udc.h @@ -177,23 +177,23 @@ struct pxa2xx_udc { static struct pxa2xx_udc *the_controller; -/* one GPIO should be used to detect host disconnect */ -static inline int is_usb_connected(void) +/* one GPIO should be used to detect VBUS from the host */ +static inline int is_vbus_present(void) { if (!the_controller->mach->udc_is_connected) return 1; return the_controller->mach->udc_is_connected(); } -/* one GPIO should force the host to see this device (or not) */ -static inline void make_usb_disappear(void) +/* one GPIO should control a D+ pullup, so host sees this device (or not) */ +static inline void pullup_off(void) { if (!the_controller->mach->udc_command) return; the_controller->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT); } -static inline void let_usb_appear(void) +static inline void pullup_on(void) { if (!the_controller->mach->udc_command) return; diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index 7457268..06b6eba 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -41,6 +41,7 @@ #undef RNDIS_PM +#undef RNDIS_WAKEUP #undef VERBOSE #include "rndis.h" @@ -60,7 +61,7 @@ } while (0) static int rndis_debug = 0; -module_param (rndis_debug, bool, 0); +module_param (rndis_debug, int, 0); MODULE_PARM_DESC (rndis_debug, "enable debugging"); #else @@ -78,22 +79,103 @@ static rndis_params rndis_per_dev_params [RNDIS_MAX_CONFIGS]; static const __le32 rndis_driver_version = __constant_cpu_to_le32 (1); /* Function Prototypes */ -static int rndis_init_response (int configNr, rndis_init_msg_type *buf); -static int rndis_query_response (int configNr, rndis_query_msg_type *buf); -static int rndis_set_response (int configNr, rndis_set_msg_type *buf); -static int rndis_reset_response (int configNr, rndis_reset_msg_type *buf); -static int rndis_keepalive_response (int configNr, - rndis_keepalive_msg_type *buf); - static rndis_resp_t *rndis_add_response (int configNr, u32 length); +/* supported OIDs */ +static const u32 oid_supported_list [] = +{ + /* the general stuff */ + OID_GEN_SUPPORTED_LIST, + OID_GEN_HARDWARE_STATUS, + OID_GEN_MEDIA_SUPPORTED, + OID_GEN_MEDIA_IN_USE, + OID_GEN_MAXIMUM_FRAME_SIZE, + OID_GEN_LINK_SPEED, + OID_GEN_TRANSMIT_BLOCK_SIZE, + OID_GEN_RECEIVE_BLOCK_SIZE, + OID_GEN_VENDOR_ID, + OID_GEN_VENDOR_DESCRIPTION, + OID_GEN_VENDOR_DRIVER_VERSION, + OID_GEN_CURRENT_PACKET_FILTER, + OID_GEN_MAXIMUM_TOTAL_SIZE, + OID_GEN_MEDIA_CONNECT_STATUS, + OID_GEN_PHYSICAL_MEDIUM, +#if 0 + OID_GEN_RNDIS_CONFIG_PARAMETER, +#endif + + /* the statistical stuff */ + OID_GEN_XMIT_OK, + OID_GEN_RCV_OK, + OID_GEN_XMIT_ERROR, + OID_GEN_RCV_ERROR, + OID_GEN_RCV_NO_BUFFER, +#ifdef RNDIS_OPTIONAL_STATS + OID_GEN_DIRECTED_BYTES_XMIT, + OID_GEN_DIRECTED_FRAMES_XMIT, + OID_GEN_MULTICAST_BYTES_XMIT, + OID_GEN_MULTICAST_FRAMES_XMIT, + OID_GEN_BROADCAST_BYTES_XMIT, + OID_GEN_BROADCAST_FRAMES_XMIT, + OID_GEN_DIRECTED_BYTES_RCV, + OID_GEN_DIRECTED_FRAMES_RCV, + OID_GEN_MULTICAST_BYTES_RCV, + OID_GEN_MULTICAST_FRAMES_RCV, + OID_GEN_BROADCAST_BYTES_RCV, + OID_GEN_BROADCAST_FRAMES_RCV, + OID_GEN_RCV_CRC_ERROR, + OID_GEN_TRANSMIT_QUEUE_LENGTH, +#endif /* RNDIS_OPTIONAL_STATS */ + + /* mandatory 802.3 */ + /* the general stuff */ + OID_802_3_PERMANENT_ADDRESS, + OID_802_3_CURRENT_ADDRESS, + OID_802_3_MULTICAST_LIST, + OID_802_3_MAC_OPTIONS, + OID_802_3_MAXIMUM_LIST_SIZE, + + /* the statistical stuff */ + OID_802_3_RCV_ERROR_ALIGNMENT, + OID_802_3_XMIT_ONE_COLLISION, + OID_802_3_XMIT_MORE_COLLISIONS, +#ifdef RNDIS_OPTIONAL_STATS + OID_802_3_XMIT_DEFERRED, + OID_802_3_XMIT_MAX_COLLISIONS, + OID_802_3_RCV_OVERRUN, + OID_802_3_XMIT_UNDERRUN, + OID_802_3_XMIT_HEARTBEAT_FAILURE, + OID_802_3_XMIT_TIMES_CRS_LOST, + OID_802_3_XMIT_LATE_COLLISIONS, +#endif /* RNDIS_OPTIONAL_STATS */ + +#ifdef RNDIS_PM + /* PM and wakeup are mandatory for USB: */ + + /* power management */ + OID_PNP_CAPABILITIES, + OID_PNP_QUERY_POWER, + OID_PNP_SET_POWER, + +#ifdef RNDIS_WAKEUP + /* wake up host */ + OID_PNP_ENABLE_WAKE_UP, + OID_PNP_ADD_WAKE_UP_PATTERN, + OID_PNP_REMOVE_WAKE_UP_PATTERN, +#endif /* RNDIS_WAKEUP */ +#endif /* RNDIS_PM */ +}; + + /* NDIS Functions */ -static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) +static int +gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, + rndis_resp_t *r) { int retval = -ENOTSUPP; - u32 length = 0; - __le32 *tmp; + u32 length = 4; /* usually */ + __le32 *outbuf; int i, count; rndis_query_cmplt_type *resp; @@ -101,7 +183,22 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) resp = (rndis_query_cmplt_type *) r->buf; if (!resp) return -ENOMEM; - + + if (buf_len && rndis_debug > 1) { + DEBUG("query OID %08x value, len %d:\n", OID, buf_len); + for (i = 0; i < buf_len; i += 16) { + DEBUG ("%03d: %08x %08x %08x %08x\n", i, + le32_to_cpup((__le32 *)&buf[i]), + le32_to_cpup((__le32 *)&buf[i + 4]), + le32_to_cpup((__le32 *)&buf[i + 8]), + le32_to_cpup((__le32 *)&buf[i + 12])); + } + } + + /* response goes here, right after the header */ + outbuf = (__le32 *) &resp[1]; + resp->InformationBufferOffset = __constant_cpu_to_le32 (16); + switch (OID) { /* general oids (table 4-1) */ @@ -111,42 +208,36 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) DEBUG ("%s: OID_GEN_SUPPORTED_LIST\n", __FUNCTION__); length = sizeof (oid_supported_list); count = length / sizeof (u32); - tmp = (__le32 *) ((u8 *)resp + 24); for (i = 0; i < count; i++) - tmp[i] = cpu_to_le32 (oid_supported_list[i]); + outbuf[i] = cpu_to_le32 (oid_supported_list[i]); retval = 0; break; /* mandatory */ case OID_GEN_HARDWARE_STATUS: DEBUG("%s: OID_GEN_HARDWARE_STATUS\n", __FUNCTION__); - length = 4; /* Bogus question! * Hardware must be ready to receive high level protocols. * BTW: * reddite ergo quae sunt Caesaris Caesari * et quae sunt Dei Deo! */ - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); + *outbuf = __constant_cpu_to_le32 (0); retval = 0; break; /* mandatory */ case OID_GEN_MEDIA_SUPPORTED: DEBUG("%s: OID_GEN_MEDIA_SUPPORTED\n", __FUNCTION__); - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr].medium); + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium); retval = 0; break; /* mandatory */ case OID_GEN_MEDIA_IN_USE: DEBUG("%s: OID_GEN_MEDIA_IN_USE\n", __FUNCTION__); - length = 4; /* one medium, one transport... (maybe you do it better) */ - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr].medium); + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium); retval = 0; break; @@ -154,25 +245,21 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) case OID_GEN_MAXIMUM_FRAME_SIZE: DEBUG("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __FUNCTION__); if (rndis_per_dev_params [configNr].dev) { - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( + *outbuf = cpu_to_le32 ( rndis_per_dev_params [configNr].dev->mtu); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; /* mandatory */ case OID_GEN_LINK_SPEED: -// DEBUG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__); - length = 4; + if (rndis_debug > 1) + DEBUG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__); if (rndis_per_dev_params [configNr].media_state - == NDIS_MEDIA_STATE_DISCONNECTED) - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); + == NDIS_MEDIA_STATE_DISCONNECTED) + *outbuf = __constant_cpu_to_le32 (0); else - *((__le32 *) resp + 6) = cpu_to_le32 ( + *outbuf = cpu_to_le32 ( rndis_per_dev_params [configNr].speed); retval = 0; break; @@ -181,8 +268,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) case OID_GEN_TRANSMIT_BLOCK_SIZE: DEBUG("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __FUNCTION__); if (rndis_per_dev_params [configNr].dev) { - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( + *outbuf = cpu_to_le32 ( rndis_per_dev_params [configNr].dev->mtu); retval = 0; } @@ -192,8 +278,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) case OID_GEN_RECEIVE_BLOCK_SIZE: DEBUG("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __FUNCTION__); if (rndis_per_dev_params [configNr].dev) { - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( + *outbuf = cpu_to_le32 ( rndis_per_dev_params [configNr].dev->mtu); retval = 0; } @@ -202,8 +287,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) /* mandatory */ case OID_GEN_VENDOR_ID: DEBUG("%s: OID_GEN_VENDOR_ID\n", __FUNCTION__); - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( + *outbuf = cpu_to_le32 ( rndis_per_dev_params [configNr].vendorID); retval = 0; break; @@ -212,51 +296,44 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) case OID_GEN_VENDOR_DESCRIPTION: DEBUG("%s: OID_GEN_VENDOR_DESCRIPTION\n", __FUNCTION__); length = strlen (rndis_per_dev_params [configNr].vendorDescr); - memcpy ((u8 *) resp + 24, + memcpy (outbuf, rndis_per_dev_params [configNr].vendorDescr, length); retval = 0; break; case OID_GEN_VENDOR_DRIVER_VERSION: DEBUG("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __FUNCTION__); - length = 4; /* Created as LE */ - *((__le32 *) resp + 6) = rndis_driver_version; + *outbuf = rndis_driver_version; retval = 0; break; /* mandatory */ case OID_GEN_CURRENT_PACKET_FILTER: DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __FUNCTION__); - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params[configNr].filter); + *outbuf = cpu_to_le32 (*rndis_per_dev_params[configNr].filter); retval = 0; break; /* mandatory */ case OID_GEN_MAXIMUM_TOTAL_SIZE: DEBUG("%s: OID_GEN_MAXIMUM_TOTAL_SIZE\n", __FUNCTION__); - length = 4; - *((__le32 *) resp + 6) = __constant_cpu_to_le32( - RNDIS_MAX_TOTAL_SIZE); + *outbuf = __constant_cpu_to_le32(RNDIS_MAX_TOTAL_SIZE); retval = 0; break; /* mandatory */ case OID_GEN_MEDIA_CONNECT_STATUS: - DEBUG("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __FUNCTION__); - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + if (rndis_debug > 1) + DEBUG("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __FUNCTION__); + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .media_state); retval = 0; break; case OID_GEN_PHYSICAL_MEDIUM: DEBUG("%s: OID_GEN_PHYSICAL_MEDIUM\n", __FUNCTION__); - length = 4; - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); + *outbuf = __constant_cpu_to_le32 (0); retval = 0; break; @@ -266,8 +343,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) */ case OID_GEN_MAC_OPTIONS: /* from WinME */ DEBUG("%s: OID_GEN_MAC_OPTIONS\n", __FUNCTION__); - length = 4; - *((__le32 *) resp + 6) = __constant_cpu_to_le32( + *outbuf = __constant_cpu_to_le32( NDIS_MAC_OPTION_RECEIVE_SERIALIZED | NDIS_MAC_OPTION_FULL_DUPLEX); retval = 0; @@ -277,62 +353,49 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) /* mandatory */ case OID_GEN_XMIT_OK: - DEBUG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__); + if (rndis_debug > 1) + DEBUG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( + *outbuf = cpu_to_le32 ( rndis_per_dev_params [configNr].stats->tx_packets - rndis_per_dev_params [configNr].stats->tx_errors - rndis_per_dev_params [configNr].stats->tx_dropped); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; /* mandatory */ case OID_GEN_RCV_OK: - DEBUG("%s: OID_GEN_RCV_OK\n", __FUNCTION__); + if (rndis_debug > 1) + DEBUG("%s: OID_GEN_RCV_OK\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( + *outbuf = cpu_to_le32 ( rndis_per_dev_params [configNr].stats->rx_packets - rndis_per_dev_params [configNr].stats->rx_errors - rndis_per_dev_params [configNr].stats->rx_dropped); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; /* mandatory */ case OID_GEN_XMIT_ERROR: - DEBUG("%s: OID_GEN_XMIT_ERROR\n", __FUNCTION__); + if (rndis_debug > 1) + DEBUG("%s: OID_GEN_XMIT_ERROR\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->tx_errors); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; /* mandatory */ case OID_GEN_RCV_ERROR: - DEBUG("%s: OID_GEN_RCV_ERROR\n", __FUNCTION__); + if (rndis_debug > 1) + DEBUG("%s: OID_GEN_RCV_ERROR\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->rx_errors); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; @@ -340,13 +403,9 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) case OID_GEN_RCV_NO_BUFFER: DEBUG("%s: OID_GEN_RCV_NO_BUFFER\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->rx_dropped); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; @@ -359,8 +418,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) * divided by weight of Alpha Centauri */ if (rndis_per_dev_params [configNr].stats) { - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( + *outbuf = cpu_to_le32 ( (rndis_per_dev_params [configNr] .stats->tx_packets - rndis_per_dev_params [configNr] @@ -369,9 +427,6 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) .stats->tx_dropped) * 123); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; @@ -379,8 +434,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) DEBUG("%s: OID_GEN_DIRECTED_FRAMES_XMIT\n", __FUNCTION__); /* dito */ if (rndis_per_dev_params [configNr].stats) { - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( + *outbuf = cpu_to_le32 ( (rndis_per_dev_params [configNr] .stats->tx_packets - rndis_per_dev_params [configNr] @@ -389,144 +443,105 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) .stats->tx_dropped) / 123); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; case OID_GEN_MULTICAST_BYTES_XMIT: DEBUG("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->multicast*1234); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; case OID_GEN_MULTICAST_FRAMES_XMIT: DEBUG("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->multicast); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; case OID_GEN_BROADCAST_BYTES_XMIT: DEBUG("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->tx_packets/42*255); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; case OID_GEN_BROADCAST_FRAMES_XMIT: DEBUG("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->tx_packets/42); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; case OID_GEN_DIRECTED_BYTES_RCV: DEBUG("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __FUNCTION__); - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); + *outbuf = __constant_cpu_to_le32 (0); retval = 0; break; case OID_GEN_DIRECTED_FRAMES_RCV: DEBUG("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __FUNCTION__); - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); + *outbuf = __constant_cpu_to_le32 (0); retval = 0; break; case OID_GEN_MULTICAST_BYTES_RCV: DEBUG("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->multicast * 1111); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; case OID_GEN_MULTICAST_FRAMES_RCV: DEBUG("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->multicast); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; case OID_GEN_BROADCAST_BYTES_RCV: DEBUG("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->rx_packets/42*255); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; case OID_GEN_BROADCAST_FRAMES_RCV: DEBUG("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->rx_packets/42); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; case OID_GEN_RCV_CRC_ERROR: DEBUG("%s: OID_GEN_RCV_CRC_ERROR\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->rx_crc_errors); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; case OID_GEN_TRANSMIT_QUEUE_LENGTH: DEBUG("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __FUNCTION__); - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); + *outbuf = __constant_cpu_to_le32 (0); retval = 0; break; #endif /* RNDIS_OPTIONAL_STATS */ @@ -538,13 +553,10 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) DEBUG("%s: OID_802_3_PERMANENT_ADDRESS\n", __FUNCTION__); if (rndis_per_dev_params [configNr].dev) { length = ETH_ALEN; - memcpy ((u8 *) resp + 24, + memcpy (outbuf, rndis_per_dev_params [configNr].host_mac, length); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; @@ -553,7 +565,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) DEBUG("%s: OID_802_3_CURRENT_ADDRESS\n", __FUNCTION__); if (rndis_per_dev_params [configNr].dev) { length = ETH_ALEN; - memcpy ((u8 *) resp + 24, + memcpy (outbuf, rndis_per_dev_params [configNr].host_mac, length); retval = 0; @@ -563,18 +575,16 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) /* mandatory */ case OID_802_3_MULTICAST_LIST: DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__); - length = 4; /* Multicast base address only */ - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0xE0000000); + *outbuf = __constant_cpu_to_le32 (0xE0000000); retval = 0; break; /* mandatory */ case OID_802_3_MAXIMUM_LIST_SIZE: DEBUG("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __FUNCTION__); - length = 4; /* Multicast base address only */ - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (1); + *outbuf = __constant_cpu_to_le32 (1); retval = 0; break; @@ -587,11 +597,8 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) /* mandatory */ case OID_802_3_RCV_ERROR_ALIGNMENT: DEBUG("%s: OID_802_3_RCV_ERROR_ALIGNMENT\n", __FUNCTION__); - if (rndis_per_dev_params [configNr].stats) - { - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + if (rndis_per_dev_params [configNr].stats) { + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->rx_frame_errors); retval = 0; } @@ -600,16 +607,14 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) /* mandatory */ case OID_802_3_XMIT_ONE_COLLISION: DEBUG("%s: OID_802_3_XMIT_ONE_COLLISION\n", __FUNCTION__); - length = 4; - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); + *outbuf = __constant_cpu_to_le32 (0); retval = 0; break; /* mandatory */ case OID_802_3_XMIT_MORE_COLLISIONS: DEBUG("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __FUNCTION__); - length = 4; - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); + *outbuf = __constant_cpu_to_le32 (0); retval = 0; break; @@ -655,27 +660,18 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) case OID_PNP_CAPABILITIES: DEBUG("%s: OID_PNP_CAPABILITIES\n", __FUNCTION__); - /* just PM, and remote wakeup on link status change - * (not magic packet or pattern match) - */ + /* for now, no wakeup capabilities */ length = sizeof (struct NDIS_PNP_CAPABILITIES); - memset (resp, 0, length); - { - struct NDIS_PNP_CAPABILITIES *caps = (void *) resp; - - caps->Flags = NDIS_DEVICE_WAKE_UP_ENABLE; - caps->WakeUpCapabilities.MinLinkChangeWakeUp - = NdisDeviceStateD3; - - /* FIXME then use usb_gadget_wakeup(), and - * set USB_CONFIG_ATT_WAKEUP in config desc - */ - } + memset(outbuf, 0, length); retval = 0; break; case OID_PNP_QUERY_POWER: - DEBUG("%s: OID_PNP_QUERY_POWER\n", __FUNCTION__); - /* sure, handle any power state that maps to USB suspend */ + DEBUG("%s: OID_PNP_QUERY_POWER D%d\n", __FUNCTION__, + le32_to_cpup((__le32 *) buf) - 1); + /* only suspend is a real power state, and + * it can't be entered by OID_PNP_SET_POWER... + */ + length = 0; retval = 0; break; #endif @@ -684,11 +680,12 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) printk (KERN_WARNING "%s: query unknown OID 0x%08X\n", __FUNCTION__, OID); } + if (retval < 0) + length = 0; - resp->InformationBufferOffset = __constant_cpu_to_le32 (16); resp->InformationBufferLength = cpu_to_le32 (length); - resp->MessageLength = cpu_to_le32 (24 + length); - r->length = 24 + length; + r->length = length + sizeof *resp; + resp->MessageLength = cpu_to_le32 (r->length); return retval; } @@ -705,45 +702,40 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len, if (!resp) return -ENOMEM; - DEBUG("set OID %08x value, len %d:\n", OID, buf_len); - for (i = 0; i < buf_len; i += 16) { - DEBUG ("%03d: " - " %02x %02x %02x %02x" - " %02x %02x %02x %02x" - " %02x %02x %02x %02x" - " %02x %02x %02x %02x" - "\n", - i, - buf[i], buf [i+1], - buf[i+2], buf[i+3], - buf[i+4], buf [i+5], - buf[i+6], buf[i+7], - buf[i+8], buf [i+9], - buf[i+10], buf[i+11], - buf[i+12], buf [i+13], - buf[i+14], buf[i+15]); + if (buf_len && rndis_debug > 1) { + DEBUG("set OID %08x value, len %d:\n", OID, buf_len); + for (i = 0; i < buf_len; i += 16) { + DEBUG ("%03d: %08x %08x %08x %08x\n", i, + le32_to_cpup((__le32 *)&buf[i]), + le32_to_cpup((__le32 *)&buf[i + 4]), + le32_to_cpup((__le32 *)&buf[i + 8]), + le32_to_cpup((__le32 *)&buf[i + 12])); + } } + params = &rndis_per_dev_params [configNr]; switch (OID) { case OID_GEN_CURRENT_PACKET_FILTER: - params = &rndis_per_dev_params [configNr]; - retval = 0; - /* FIXME use these NDIS_PACKET_TYPE_* bitflags to - * set the cdc_filter; it's not RNDIS-specific + /* these NDIS_PACKET_TYPE_* bitflags are shared with + * cdc_filter; it's not RNDIS-specific * NDIS_PACKET_TYPE_x == USB_CDC_PACKET_TYPE_x for x in: * PROMISCUOUS, DIRECTED, * MULTICAST, ALL_MULTICAST, BROADCAST */ - params->filter = le32_to_cpup((__le32 *)buf); + *params->filter = (u16) le32_to_cpup((__le32 *)buf); DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n", - __FUNCTION__, params->filter); + __FUNCTION__, *params->filter); /* this call has a significant side effect: it's * what makes the packet flow start and stop, like * activating the CDC Ethernet altsetting. */ - if (params->filter) { +#ifdef RNDIS_PM +update_linkstate: +#endif + retval = 0; + if (*params->filter) { params->state = RNDIS_DATA_INITIALIZED; netif_carrier_on(params->dev); if (netif_running(params->dev)) @@ -776,21 +768,34 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len, #ifdef RNDIS_PM case OID_PNP_SET_POWER: - DEBUG ("OID_PNP_SET_POWER\n"); - /* sure, handle any power state that maps to USB suspend */ - retval = 0; - break; - - case OID_PNP_ENABLE_WAKE_UP: - /* always-connected ... */ - DEBUG ("OID_PNP_ENABLE_WAKE_UP\n"); - retval = 0; + /* The only real power state is USB suspend, and RNDIS requests + * can't enter it; this one isn't really about power. After + * resuming, Windows forces a reset, and then SET_POWER D0. + * FIXME ... then things go batty; Windows wedges itself. + */ + i = le32_to_cpup((__force __le32 *)buf); + DEBUG("%s: OID_PNP_SET_POWER D%d\n", __FUNCTION__, i - 1); + switch (i) { + case NdisDeviceStateD0: + *params->filter = params->saved_filter; + goto update_linkstate; + case NdisDeviceStateD3: + case NdisDeviceStateD2: + case NdisDeviceStateD1: + params->saved_filter = *params->filter; + retval = 0; + break; + } break; - // no PM resume patterns supported (specified where?) - // so OID_PNP_{ADD,REMOVE}_WAKE_UP_PATTERN always fails +#ifdef RNDIS_WAKEUP + // no wakeup support advertised, so wakeup OIDs always fail: + // - OID_PNP_ENABLE_WAKE_UP + // - OID_PNP_{ADD,REMOVE}_WAKE_UP_PATTERN #endif +#endif /* RNDIS_PM */ + default: printk (KERN_WARNING "%s: set unknown OID 0x%08X, size %d\n", __FUNCTION__, OID, buf_len); @@ -811,13 +816,10 @@ static int rndis_init_response (int configNr, rndis_init_msg_type *buf) if (!rndis_per_dev_params [configNr].dev) return -ENOTSUPP; r = rndis_add_response (configNr, sizeof (rndis_init_cmplt_type)); - - if (!r) return -ENOMEM; - + if (!r) + return -ENOMEM; resp = (rndis_init_cmplt_type *) r->buf; - if (!resp) return -ENOMEM; - resp->MessageType = __constant_cpu_to_le32 ( REMOTE_NDIS_INITIALIZE_CMPLT); resp->MessageLength = __constant_cpu_to_le32 (52); @@ -857,20 +859,22 @@ static int rndis_query_response (int configNr, rndis_query_msg_type *buf) * oid_supported_list is the largest answer */ r = rndis_add_response (configNr, sizeof (oid_supported_list)); - - if (!r) return -ENOMEM; + if (!r) + return -ENOMEM; resp = (rndis_query_cmplt_type *) r->buf; - if (!resp) return -ENOMEM; - resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_QUERY_CMPLT); - resp->MessageLength = __constant_cpu_to_le32 (24); resp->RequestID = buf->RequestID; /* Still LE in msg buffer */ - - if (gen_ndis_query_resp (configNr, le32_to_cpu (buf->OID), r)) { + + if (gen_ndis_query_resp (configNr, le32_to_cpu (buf->OID), + le32_to_cpu(buf->InformationBufferOffset) + + 8 + (u8 *) buf, + le32_to_cpu(buf->InformationBufferLength), + r)) { /* OID not supported */ resp->Status = __constant_cpu_to_le32 ( RNDIS_STATUS_NOT_SUPPORTED); + resp->MessageLength = __constant_cpu_to_le32 (sizeof *resp); resp->InformationBufferLength = __constant_cpu_to_le32 (0); resp->InformationBufferOffset = __constant_cpu_to_le32 (0); } else @@ -889,10 +893,9 @@ static int rndis_set_response (int configNr, rndis_set_msg_type *buf) rndis_resp_t *r; r = rndis_add_response (configNr, sizeof (rndis_set_cmplt_type)); - - if (!r) return -ENOMEM; + if (!r) + return -ENOMEM; resp = (rndis_set_cmplt_type *) r->buf; - if (!resp) return -ENOMEM; BufLength = le32_to_cpu (buf->InformationBufferLength); BufOffset = le32_to_cpu (buf->InformationBufferOffset); @@ -930,10 +933,9 @@ static int rndis_reset_response (int configNr, rndis_reset_msg_type *buf) rndis_resp_t *r; r = rndis_add_response (configNr, sizeof (rndis_reset_cmplt_type)); - - if (!r) return -ENOMEM; + if (!r) + return -ENOMEM; resp = (rndis_reset_cmplt_type *) r->buf; - if (!resp) return -ENOMEM; resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_RESET_CMPLT); resp->MessageLength = __constant_cpu_to_le32 (16); @@ -957,8 +959,9 @@ static int rndis_keepalive_response (int configNr, /* host "should" check only in RNDIS_DATA_INITIALIZED state */ r = rndis_add_response (configNr, sizeof (rndis_keepalive_cmplt_type)); + if (!r) + return -ENOMEM; resp = (rndis_keepalive_cmplt_type *) r->buf; - if (!resp) return -ENOMEM; resp->MessageType = __constant_cpu_to_le32 ( REMOTE_NDIS_KEEPALIVE_CMPLT); @@ -987,10 +990,9 @@ static int rndis_indicate_status_msg (int configNr, u32 status) r = rndis_add_response (configNr, sizeof (rndis_indicate_status_msg_type)); - if (!r) return -ENOMEM; - + if (!r) + return -ENOMEM; resp = (rndis_indicate_status_msg_type *) r->buf; - if (!resp) return -ENOMEM; resp->MessageType = __constant_cpu_to_le32 ( REMOTE_NDIS_INDICATE_STATUS_MSG); @@ -1021,6 +1023,21 @@ int rndis_signal_disconnect (int configNr) RNDIS_STATUS_MEDIA_DISCONNECT); } +void rndis_uninit (int configNr) +{ + u8 *buf; + u32 length; + + if (configNr >= RNDIS_MAX_CONFIGS) + return; + rndis_per_dev_params [configNr].used = 0; + rndis_per_dev_params [configNr].state = RNDIS_UNINITIALIZED; + + /* drain the response queue */ + while ((buf = rndis_get_next_response(configNr, &length))) + rndis_free_response(configNr, buf); +} + void rndis_set_host_mac (int configNr, const u8 *addr) { rndis_per_dev_params [configNr].host_mac = addr; @@ -1046,9 +1063,13 @@ int rndis_msg_parser (u8 configNr, u8 *buf) return -ENOTSUPP; params = &rndis_per_dev_params [configNr]; + /* NOTE: RNDIS is *EXTREMELY* chatty ... Windows constantly polls for + * rx/tx statistics and link status, in addition to KEEPALIVE traffic + * and normal HC level polling to see if there's any IN traffic. + */ + /* For USB: responses may take up to 10 seconds */ - switch (MsgType) - { + switch (MsgType) { case REMOTE_NDIS_INITIALIZE_MSG: DEBUG("%s: REMOTE_NDIS_INITIALIZE_MSG\n", __FUNCTION__ ); @@ -1082,10 +1103,9 @@ int rndis_msg_parser (u8 configNr, u8 *buf) case REMOTE_NDIS_KEEPALIVE_MSG: /* For USB: host does this every 5 seconds */ -#ifdef VERBOSE - DEBUG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n", - __FUNCTION__ ); -#endif + if (rndis_debug > 1) + DEBUG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n", + __FUNCTION__ ); return rndis_keepalive_response (configNr, (rndis_keepalive_msg_type *) buf); @@ -1152,7 +1172,8 @@ void rndis_deregister (int configNr) } int rndis_set_param_dev (u8 configNr, struct net_device *dev, - struct net_device_stats *stats) + struct net_device_stats *stats, + u16 *cdc_filter) { DEBUG("%s:\n", __FUNCTION__ ); if (!dev || !stats) return -1; @@ -1160,6 +1181,7 @@ int rndis_set_param_dev (u8 configNr, struct net_device *dev, rndis_per_dev_params [configNr].dev = dev; rndis_per_dev_params [configNr].stats = stats; + rndis_per_dev_params [configNr].filter = cdc_filter; return 0; } @@ -1178,7 +1200,7 @@ int rndis_set_param_vendor (u8 configNr, u32 vendorID, const char *vendorDescr) int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed) { - DEBUG("%s:\n", __FUNCTION__ ); + DEBUG("%s: %u %u\n", __FUNCTION__, medium, speed); if (configNr >= RNDIS_MAX_CONFIGS) return -1; rndis_per_dev_params [configNr].medium = medium; @@ -1242,6 +1264,7 @@ static rndis_resp_t *rndis_add_response (int configNr, u32 length) { rndis_resp_t *r; + /* NOTE: this gets copied into ether.c USB_BUFSIZ bytes ... */ r = kmalloc (sizeof (rndis_resp_t) + length, GFP_ATOMIC); if (!r) return NULL; diff --git a/drivers/usb/gadget/rndis.h b/drivers/usb/gadget/rndis.h index 2b5b55d..95b4c63 100644 --- a/drivers/usb/gadget/rndis.h +++ b/drivers/usb/gadget/rndis.h @@ -69,90 +69,6 @@ #define OID_PNP_ENABLE_WAKE_UP 0xFD010106 -/* supported OIDs */ -static const u32 oid_supported_list [] = -{ - /* the general stuff */ - OID_GEN_SUPPORTED_LIST, - OID_GEN_HARDWARE_STATUS, - OID_GEN_MEDIA_SUPPORTED, - OID_GEN_MEDIA_IN_USE, - OID_GEN_MAXIMUM_FRAME_SIZE, - OID_GEN_LINK_SPEED, - OID_GEN_TRANSMIT_BLOCK_SIZE, - OID_GEN_RECEIVE_BLOCK_SIZE, - OID_GEN_VENDOR_ID, - OID_GEN_VENDOR_DESCRIPTION, - OID_GEN_VENDOR_DRIVER_VERSION, - OID_GEN_CURRENT_PACKET_FILTER, - OID_GEN_MAXIMUM_TOTAL_SIZE, - OID_GEN_MEDIA_CONNECT_STATUS, - OID_GEN_PHYSICAL_MEDIUM, -#if 0 - OID_GEN_RNDIS_CONFIG_PARAMETER, -#endif - - /* the statistical stuff */ - OID_GEN_XMIT_OK, - OID_GEN_RCV_OK, - OID_GEN_XMIT_ERROR, - OID_GEN_RCV_ERROR, - OID_GEN_RCV_NO_BUFFER, -#ifdef RNDIS_OPTIONAL_STATS - OID_GEN_DIRECTED_BYTES_XMIT, - OID_GEN_DIRECTED_FRAMES_XMIT, - OID_GEN_MULTICAST_BYTES_XMIT, - OID_GEN_MULTICAST_FRAMES_XMIT, - OID_GEN_BROADCAST_BYTES_XMIT, - OID_GEN_BROADCAST_FRAMES_XMIT, - OID_GEN_DIRECTED_BYTES_RCV, - OID_GEN_DIRECTED_FRAMES_RCV, - OID_GEN_MULTICAST_BYTES_RCV, - OID_GEN_MULTICAST_FRAMES_RCV, - OID_GEN_BROADCAST_BYTES_RCV, - OID_GEN_BROADCAST_FRAMES_RCV, - OID_GEN_RCV_CRC_ERROR, - OID_GEN_TRANSMIT_QUEUE_LENGTH, -#endif /* RNDIS_OPTIONAL_STATS */ - - /* mandatory 802.3 */ - /* the general stuff */ - OID_802_3_PERMANENT_ADDRESS, - OID_802_3_CURRENT_ADDRESS, - OID_802_3_MULTICAST_LIST, - OID_802_3_MAC_OPTIONS, - OID_802_3_MAXIMUM_LIST_SIZE, - - /* the statistical stuff */ - OID_802_3_RCV_ERROR_ALIGNMENT, - OID_802_3_XMIT_ONE_COLLISION, - OID_802_3_XMIT_MORE_COLLISIONS, -#ifdef RNDIS_OPTIONAL_STATS - OID_802_3_XMIT_DEFERRED, - OID_802_3_XMIT_MAX_COLLISIONS, - OID_802_3_RCV_OVERRUN, - OID_802_3_XMIT_UNDERRUN, - OID_802_3_XMIT_HEARTBEAT_FAILURE, - OID_802_3_XMIT_TIMES_CRS_LOST, - OID_802_3_XMIT_LATE_COLLISIONS, -#endif /* RNDIS_OPTIONAL_STATS */ - -#ifdef RNDIS_PM - /* PM and wakeup are mandatory for USB: */ - - /* power management */ - OID_PNP_CAPABILITIES, - OID_PNP_QUERY_POWER, - OID_PNP_SET_POWER, - - /* wake up host */ - OID_PNP_ENABLE_WAKE_UP, - OID_PNP_ADD_WAKE_UP_PATTERN, - OID_PNP_REMOVE_WAKE_UP_PATTERN, -#endif -}; - - typedef struct rndis_init_msg_type { __le32 MessageType; @@ -309,15 +225,18 @@ typedef struct rndis_resp_t typedef struct rndis_params { u8 confignr; - int used; + u8 used; + u16 saved_filter; enum rndis_state state; - u32 filter; u32 medium; u32 speed; u32 media_state; + const u8 *host_mac; + u16 *filter; struct net_device *dev; struct net_device_stats *stats; + u32 vendorID; const char *vendorDescr; int (*ack) (struct net_device *); @@ -329,7 +248,8 @@ int rndis_msg_parser (u8 configNr, u8 *buf); int rndis_register (int (*rndis_control_ack) (struct net_device *)); void rndis_deregister (int configNr); int rndis_set_param_dev (u8 configNr, struct net_device *dev, - struct net_device_stats *stats); + struct net_device_stats *stats, + u16 *cdc_filter); int rndis_set_param_vendor (u8 configNr, u32 vendorID, const char *vendorDescr); int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed); @@ -338,6 +258,7 @@ int rndis_rm_hdr (struct sk_buff *skb); u8 *rndis_get_next_response (int configNr, u32 *length); void rndis_free_response (int configNr, u8 *buf); +void rndis_uninit (int configNr); int rndis_signal_connect (int configNr); int rndis_signal_disconnect (int configNr); int rndis_state (int configNr); diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index 4d591c7..9e4f1c6 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -300,18 +300,18 @@ static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed, u8 type, unsigned int index, int is_otg); static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len, - int kmalloc_flags); + unsigned kmalloc_flags); static void gs_free_req(struct usb_ep *ep, struct usb_request *req); static struct gs_req_entry *gs_alloc_req_entry(struct usb_ep *ep, unsigned len, - int kmalloc_flags); + unsigned kmalloc_flags); static void gs_free_req_entry(struct usb_ep *ep, struct gs_req_entry *req); -static int gs_alloc_ports(struct gs_dev *dev, int kmalloc_flags); +static int gs_alloc_ports(struct gs_dev *dev, unsigned kmalloc_flags); static void gs_free_ports(struct gs_dev *dev); /* circular buffer */ -static struct gs_buf *gs_buf_alloc(unsigned int size, int kmalloc_flags); +static struct gs_buf *gs_buf_alloc(unsigned int size, unsigned kmalloc_flags); static void gs_buf_free(struct gs_buf *gb); static void gs_buf_clear(struct gs_buf *gb); static unsigned int gs_buf_data_avail(struct gs_buf *gb); @@ -1607,9 +1607,9 @@ static int gs_setup(struct usb_gadget *gadget, int ret = -EOPNOTSUPP; struct gs_dev *dev = get_gadget_data(gadget); struct usb_request *req = dev->dev_ctrl_req; - u16 wIndex = ctrl->wIndex; - u16 wValue = ctrl->wValue; - u16 wLength = ctrl->wLength; + u16 wIndex = le16_to_cpu(ctrl->wIndex); + u16 wValue = le16_to_cpu(ctrl->wValue); + u16 wLength = le16_to_cpu(ctrl->wLength); switch (ctrl->bRequestType & USB_TYPE_MASK) { case USB_TYPE_STANDARD: @@ -1651,9 +1651,9 @@ static int gs_setup_standard(struct usb_gadget *gadget, int ret = -EOPNOTSUPP; struct gs_dev *dev = get_gadget_data(gadget); struct usb_request *req = dev->dev_ctrl_req; - u16 wIndex = ctrl->wIndex; - u16 wValue = ctrl->wValue; - u16 wLength = ctrl->wLength; + u16 wIndex = le16_to_cpu(ctrl->wIndex); + u16 wValue = le16_to_cpu(ctrl->wValue); + u16 wLength = le16_to_cpu(ctrl->wLength); switch (ctrl->bRequest) { case USB_REQ_GET_DESCRIPTOR: @@ -1782,9 +1782,9 @@ static int gs_setup_class(struct usb_gadget *gadget, struct gs_dev *dev = get_gadget_data(gadget); struct gs_port *port = dev->dev_port[0]; /* ACM only has one port */ struct usb_request *req = dev->dev_ctrl_req; - u16 wIndex = ctrl->wIndex; - u16 wValue = ctrl->wValue; - u16 wLength = ctrl->wLength; + u16 wIndex = le16_to_cpu(ctrl->wIndex); + u16 wValue = le16_to_cpu(ctrl->wValue); + u16 wLength = le16_to_cpu(ctrl->wLength); switch (ctrl->bRequest) { case USB_CDC_REQ_SET_LINE_CODING: @@ -2119,7 +2119,8 @@ static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed, * Allocate a usb_request and its buffer. Returns a pointer to the * usb_request or NULL if there is an error. */ -static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len, int kmalloc_flags) +static struct usb_request * +gs_alloc_req(struct usb_ep *ep, unsigned int len, unsigned kmalloc_flags) { struct usb_request *req; @@ -2159,7 +2160,8 @@ static void gs_free_req(struct usb_ep *ep, struct usb_request *req) * Allocates a request and its buffer, using the given * endpoint, buffer len, and kmalloc flags. */ -static struct gs_req_entry *gs_alloc_req_entry(struct usb_ep *ep, unsigned len, int kmalloc_flags) +static struct gs_req_entry * +gs_alloc_req_entry(struct usb_ep *ep, unsigned len, unsigned kmalloc_flags) { struct gs_req_entry *req; @@ -2200,7 +2202,7 @@ static void gs_free_req_entry(struct usb_ep *ep, struct gs_req_entry *req) * * The device lock is normally held when calling this function. */ -static int gs_alloc_ports(struct gs_dev *dev, int kmalloc_flags) +static int gs_alloc_ports(struct gs_dev *dev, unsigned kmalloc_flags) { int i; struct gs_port *port; @@ -2282,7 +2284,7 @@ static void gs_free_ports(struct gs_dev *dev) * * Allocate a circular buffer and all associated memory. */ -static struct gs_buf *gs_buf_alloc(unsigned int size, int kmalloc_flags) +static struct gs_buf *gs_buf_alloc(unsigned int size, unsigned kmalloc_flags) { struct gs_buf *gb; diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 6e49432..a6e035e 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -919,9 +919,9 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) struct zero_dev *dev = get_gadget_data (gadget); struct usb_request *req = dev->req; int value = -EOPNOTSUPP; - u16 w_index = ctrl->wIndex; - u16 w_value = ctrl->wValue; - u16 w_length = ctrl->wLength; + u16 w_index = le16_to_cpu(ctrl->wIndex); + u16 w_value = le16_to_cpu(ctrl->wValue); + u16 w_length = le16_to_cpu(ctrl->wLength); /* usually this stores reply data in the pre-allocated ep0 buffer, * but config change events will reconfigure hardware. |