summaryrefslogtreecommitdiff
path: root/drivers/usb/gadget
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r--drivers/usb/gadget/Kconfig11
-rw-r--r--drivers/usb/gadget/dummy_hcd.c745
-rw-r--r--drivers/usb/gadget/ether.c353
-rw-r--r--drivers/usb/gadget/file_storage.c61
-rw-r--r--drivers/usb/gadget/goku_udc.c28
-rw-r--r--drivers/usb/gadget/inode.c12
-rw-r--r--drivers/usb/gadget/ndis.h14
-rw-r--r--drivers/usb/gadget/net2280.c51
-rw-r--r--drivers/usb/gadget/omap_udc.c301
-rw-r--r--drivers/usb/gadget/omap_udc.h4
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.c43
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.h10
-rw-r--r--drivers/usb/gadget/rndis.c515
-rw-r--r--drivers/usb/gadget/rndis.h95
-rw-r--r--drivers/usb/gadget/serial.c36
-rw-r--r--drivers/usb/gadget/zero.c6
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(&regs->bRequestType);
ctrl.bRequest = readl(&regs->bRequest);
- ctrl.wValue = (readl(&regs->wValueH) << 8) | readl(&regs->wValueL);
- ctrl.wIndex = (readl(&regs->wIndexH) << 8) | readl(&regs->wIndexL);
- ctrl.wLength = (readl(&regs->wLengthH) << 8) | readl(&regs->wLengthL);
+ ctrl.wValue = cpu_to_le16((readl(&regs->wValueH) << 8)
+ | readl(&regs->wValueL));
+ ctrl.wIndex = cpu_to_le16((readl(&regs->wIndexH) << 8)
+ | readl(&regs->wIndexL));
+ ctrl.wLength = cpu_to_le16((readl(&regs->wLengthH) << 8)
+ | readl(&regs->wLengthL));
writel(0, &regs->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.