patch-2.4.26 linux-2.4.26/drivers/usb/gadget/ether.c
Next file: linux-2.4.26/drivers/usb/gadget/gadget_chips.h
Previous file: linux-2.4.26/drivers/usb/gadget/config.c
Back to the patch index
Back to the overall index
- Lines: 406
- Date:
2004-04-14 06:05:32.000000000 -0700
- Orig file:
linux-2.4.25/drivers/usb/gadget/ether.c
- Orig date:
2004-02-18 05:36:31.000000000 -0800
diff -urN linux-2.4.25/drivers/usb/gadget/ether.c linux-2.4.26/drivers/usb/gadget/ether.c
@@ -19,7 +19,7 @@
*/
-#define DEBUG 1
+// #define DEBUG 1
// #define VERBOSE
#include <linux/config.h>
@@ -136,7 +136,6 @@
* DRIVER_VERSION_NUM ... alerts the host side driver to differences
* EP_*_NAME ... which endpoints do we use for which purpose?
* EP_*_NUM ... numbers for them (often limited by hardware)
- * HIGHSPEED ... define if ep0 and descriptors need high speed support
* WAKEUP ... if hardware supports remote wakeup AND we will issue the
* usb_gadget_wakeup() call to initiate it, USB_CONFIG_ATT_WAKEUP
*
@@ -174,7 +173,6 @@
#define EP_IN_NUM 2
static const char EP_STATUS_NAME [] = "ep-f";
#define EP_STATUS_NUM 3
-#define HIGHSPEED
/* supports remote wakeup, but this driver doesn't */
extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode);
@@ -323,7 +321,7 @@
#define DEFAULT_QLEN 2 /* double buffering by default */
#endif
-#ifdef HIGHSPEED
+#ifdef CONFIG_USB_GADGET_DUALSPEED
static unsigned qmult = 5;
MODULE_PARM (qmult, "i");
@@ -336,7 +334,7 @@
/* also defer IRQs on highspeed TX */
#define TX_DELAY DEFAULT_QLEN
-#else /* !HIGHSPEED ... full speed: */
+#else /* full speed (low speed doesn't do bulk) */
#define qlen(gadget) DEFAULT_QLEN
#endif
@@ -619,7 +617,26 @@
.wMaxPacketSize = __constant_cpu_to_le16 (64),
};
-#ifdef HIGHSPEED
+static const struct usb_descriptor_header *fs_function [] = {
+#ifdef DEV_CONFIG_CDC
+ /* "cdc" mode descriptors */
+ (struct usb_descriptor_header *) &control_intf,
+ (struct usb_descriptor_header *) &header_desc,
+ (struct usb_descriptor_header *) &union_desc,
+ (struct usb_descriptor_header *) ðer_desc,
+#ifdef EP_STATUS_NUM
+ (struct usb_descriptor_header *) &fs_status_desc,
+#endif
+ (struct usb_descriptor_header *) &data_nop_intf,
+#endif /* DEV_CONFIG_CDC */
+ /* minimalist core */
+ (struct usb_descriptor_header *) &data_intf,
+ (struct usb_descriptor_header *) &fs_source_desc,
+ (struct usb_descriptor_header *) &fs_sink_desc,
+ 0,
+};
+
+#ifdef CONFIG_USB_GADGET_DUALSPEED
/*
* usb 2.0 devices need to expose both high speed and full speed
@@ -672,6 +689,25 @@
.bNumConfigurations = 1,
};
+static const struct usb_descriptor_header *hs_function [] = {
+#ifdef DEV_CONFIG_CDC
+ /* "cdc" mode descriptors */
+ (struct usb_descriptor_header *) &control_intf,
+ (struct usb_descriptor_header *) &header_desc,
+ (struct usb_descriptor_header *) &union_desc,
+ (struct usb_descriptor_header *) ðer_desc,
+#ifdef EP_STATUS_NUM
+ (struct usb_descriptor_header *) &hs_status_desc,
+#endif
+ (struct usb_descriptor_header *) &data_nop_intf,
+#endif /* DEV_CONFIG_CDC */
+ /* minimalist core */
+ (struct usb_descriptor_header *) &data_intf,
+ (struct usb_descriptor_header *) &hs_source_desc,
+ (struct usb_descriptor_header *) &hs_sink_desc,
+ 0,
+};
+
/* maxpacket and other transfer characteristics vary by speed. */
#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
@@ -681,7 +717,7 @@
/* if there's no high speed support, maxpacket doesn't change. */
#define ep_desc(g,hs,fs) fs
-#endif /* !HIGHSPEED */
+#endif /* !CONFIG_USB_GADGET_DUALSPEED */
/*-------------------------------------------------------------------------*/
@@ -716,86 +752,25 @@
static int
config_buf (enum usb_device_speed speed, u8 *buf, u8 type, unsigned index)
{
- const unsigned config_len = USB_DT_CONFIG_SIZE
-#ifdef DEV_CONFIG_CDC
- + 2 * USB_DT_INTERFACE_SIZE
- + sizeof header_desc
- + sizeof union_desc
- + sizeof ether_desc
-#ifdef EP_STATUS_NUM
- + USB_DT_ENDPOINT_SIZE
-#endif
-#endif /* DEV_CONFIG_CDC */
- + USB_DT_INTERFACE_SIZE
- + 2 * USB_DT_ENDPOINT_SIZE;
+ int len;
+ const struct usb_descriptor_header **function = fs_function;
+#ifdef CONFIG_USB_GADGET_DUALSPEED
+ int hs = (speed == USB_SPEED_HIGH);
-#ifdef HIGHSPEED
- int hs;
-#endif
- /* a single configuration must always be index 0 */
- if (index > 0)
- return -EINVAL;
- if (config_len > USB_BUFSIZ)
- return -EDOM;
-
- /* config (or other speed config) */
- memcpy (buf, ð_config, USB_DT_CONFIG_SIZE);
- buf [1] = type;
- ((struct usb_config_descriptor *) buf)->wTotalLength
- = __constant_cpu_to_le16 (config_len);
- buf += USB_DT_CONFIG_SIZE;
-#ifdef HIGHSPEED
- hs = (speed == USB_SPEED_HIGH);
if (type == USB_DT_OTHER_SPEED_CONFIG)
hs = !hs;
-#endif
-
-#ifdef DEV_CONFIG_CDC
- /* control interface, class descriptors, optional status endpoint */
- memcpy (buf, &control_intf, USB_DT_INTERFACE_SIZE);
- buf += USB_DT_INTERFACE_SIZE;
-
- memcpy (buf, &header_desc, sizeof header_desc);
- buf += sizeof header_desc;
- memcpy (buf, &union_desc, sizeof union_desc);
- buf += sizeof union_desc;
- memcpy (buf, ðer_desc, sizeof ether_desc);
- buf += sizeof ether_desc;
-
-#ifdef EP_STATUS_NUM
-#ifdef HIGHSPEED
if (hs)
- memcpy (buf, &hs_status_desc, USB_DT_ENDPOINT_SIZE);
- else
-#endif /* HIGHSPEED */
- memcpy (buf, &fs_status_desc, USB_DT_ENDPOINT_SIZE);
- buf += USB_DT_ENDPOINT_SIZE;
-#endif /* EP_STATUS_NUM */
-
- /* default data altsetting has no endpoints */
- memcpy (buf, &data_nop_intf, USB_DT_INTERFACE_SIZE);
- buf += USB_DT_INTERFACE_SIZE;
-#endif /* DEV_CONFIG_CDC */
-
- /* the "real" data interface has two endpoints */
- memcpy (buf, &data_intf, USB_DT_INTERFACE_SIZE);
- buf += USB_DT_INTERFACE_SIZE;
-#ifdef HIGHSPEED
- if (hs) {
- memcpy (buf, &hs_source_desc, USB_DT_ENDPOINT_SIZE);
- buf += USB_DT_ENDPOINT_SIZE;
- memcpy (buf, &hs_sink_desc, USB_DT_ENDPOINT_SIZE);
- buf += USB_DT_ENDPOINT_SIZE;
- } else
+ function = hs_function;
#endif
- {
- memcpy (buf, &fs_source_desc, USB_DT_ENDPOINT_SIZE);
- buf += USB_DT_ENDPOINT_SIZE;
- memcpy (buf, &fs_sink_desc, USB_DT_ENDPOINT_SIZE);
- buf += USB_DT_ENDPOINT_SIZE;
- }
- return config_len;
+ /* a single configuration must always be index 0 */
+ if (index > 0)
+ return -EINVAL;
+ len = usb_gadget_config_buf (ð_config, buf, USB_BUFSIZ, function);
+ if (len < 0)
+ return len;
+ ((struct usb_config_descriptor *) buf)->bDescriptorType = type;
+ return len;
}
/*-------------------------------------------------------------------------*/
@@ -897,8 +872,11 @@
#ifndef DEV_CONFIG_CDC
if (result == 0) {
netif_carrier_on (dev->net);
- if (netif_running (dev->net))
+ if (netif_running (dev->net)) {
+ spin_unlock (&dev->lock);
eth_start (dev, GFP_ATOMIC);
+ spin_lock (&dev->lock);
+ }
} else {
(void) usb_ep_disable (dev->in_ep);
dev->in_ep = 0;
@@ -1001,7 +979,7 @@
switch (gadget->speed) {
case USB_SPEED_FULL: speed = "full"; break;
-#ifdef HIGHSPEED
+#ifdef CONFIG_USB_GADGET_DUALSPEED
case USB_SPEED_HIGH: speed = "high"; break;
#endif
default: speed = "?"; break;
@@ -1172,15 +1150,19 @@
value = min (ctrl->wLength, (u16) sizeof device_desc);
memcpy (req->buf, &device_desc, value);
break;
-#ifdef HIGHSPEED
+#ifdef CONFIG_USB_GADGET_DUALSPEED
case USB_DT_DEVICE_QUALIFIER:
+ if (!gadget->is_dualspeed)
+ break;
value = min (ctrl->wLength, (u16) sizeof dev_qualifier);
memcpy (req->buf, &dev_qualifier, value);
break;
case USB_DT_OTHER_SPEED_CONFIG:
+ if (!gadget->is_dualspeed)
+ break;
// FALLTHROUGH
-#endif /* HIGHSPEED */
+#endif /* CONFIG_USB_GADGET_DUALSPEED */
case USB_DT_CONFIG:
value = config_buf (gadget->speed, req->buf,
ctrl->wValue >> 8,
@@ -1258,8 +1240,11 @@
#ifdef EP_STATUS_NUM
issue_start_status (dev);
#endif
- if (netif_running (dev->net))
+ if (netif_running (dev->net)) {
+ spin_unlock (&dev->lock);
eth_start (dev, GFP_ATOMIC);
+ spin_lock (&dev->lock);
+ }
} else {
netif_stop_queue (dev->net);
netif_carrier_off (dev->net);
@@ -1426,16 +1411,14 @@
rx_submit (struct eth_dev *dev, struct usb_request *req, int gfp_flags)
{
struct sk_buff *skb;
- int retval = 0;
+ int retval = -ENOMEM;
size_t size;
size = (sizeof (struct ethhdr) + dev->net->mtu + RX_EXTRA);
if ((skb = alloc_skb (size, gfp_flags)) == 0) {
DEBUG (dev, "no rx skb\n");
- defer_kevent (dev, WORK_RX_MEMORY);
- list_add (&req->list, &dev->rx_reqs);
- return -ENOMEM;
+ goto enomem;
}
req->buf = skb->data;
@@ -1445,11 +1428,14 @@
retval = usb_ep_queue (dev->out_ep, req, gfp_flags);
if (retval == -ENOMEM)
+enomem:
defer_kevent (dev, WORK_RX_MEMORY);
if (retval) {
DEBUG (dev, "rx submit --> %d\n", retval);
dev_kfree_skb_any (skb);
+ spin_lock (&dev->lock);
list_add (&req->list, &dev->rx_reqs);
+ spin_unlock (&dev->lock);
}
return retval;
}
@@ -1514,6 +1500,7 @@
dev_kfree_skb_any (skb);
if (!netif_running (dev->net)) {
clean:
+ /* nobody reading rx_reqs, so no dev->lock */
list_add (&req->list, &dev->rx_reqs);
req = 0;
}
@@ -1580,19 +1567,26 @@
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)) {
req = container_of (dev->rx_reqs.next,
struct usb_request, list);
list_del_init (&req->list);
+ spin_unlock_irqrestore (&dev->lock, flags);
+
if (rx_submit (dev, req, gfp_flags) < 0) {
defer_kevent (dev, WORK_RX_MEMORY);
return;
}
+
+ spin_lock_irqsave (&dev->lock, flags);
}
+ spin_unlock_irqrestore (&dev->lock, flags);
}
static void eth_work (void *_dev)
@@ -1628,7 +1622,9 @@
}
dev->stats.tx_packets++;
+ spin_lock (&dev->lock);
list_add (&req->list, &dev->tx_reqs);
+ spin_unlock (&dev->lock);
dev_kfree_skb_any (skb);
atomic_dec (&dev->tx_qlen);
@@ -1642,11 +1638,14 @@
int length = skb->len;
int retval;
struct usb_request *req = 0;
+ unsigned long flags;
+ spin_lock_irqsave (&dev->lock, flags);
req = container_of (dev->tx_reqs.next, struct usb_request, list);
list_del (&req->list);
if (list_empty (&dev->tx_reqs))
netif_stop_queue (net);
+ spin_unlock_irqrestore (&dev->lock, flags);
/* no buffer copies needed, unless the network stack did it
* or the hardware can't use skb buffers.
@@ -1667,7 +1666,7 @@
#endif
req->length = length;
-#ifdef HIGHSPEED
+#ifdef CONFIG_USB_GADGET_DUALSPEED
/* throttle highspeed IRQ rate back slightly */
req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
? ((atomic_read (&dev->tx_qlen) % TX_DELAY) != 0)
@@ -1687,9 +1686,11 @@
if (retval) {
dev->stats.tx_dropped++;
dev_kfree_skb_any (skb);
+ spin_lock_irqsave (&dev->lock, flags);
if (list_empty (&dev->tx_reqs))
netif_start_queue (net);
list_add (&req->list, &dev->tx_reqs);
+ spin_unlock_irqrestore (&dev->lock, flags);
}
return 0;
}
@@ -1788,7 +1789,7 @@
#endif
device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
-#ifdef HIGHSPEED
+#ifdef CONFIG_USB_GADGET_DUALSPEED
/* assumes ep0 uses the same value for both speeds ... */
dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
#endif
@@ -1810,9 +1811,7 @@
/* network device setup */
dev->net = net;
SET_MODULE_OWNER (net);
- net->priv = dev;
strcpy (net->name, "usb%d");
- ether_setup (net);
/* one random address for the gadget device ... both of these could
* reasonably come from an id prom or a module parameter.
@@ -1886,7 +1885,7 @@
/*-------------------------------------------------------------------------*/
static struct usb_gadget_driver eth_driver = {
-#ifdef HIGHSPEED
+#ifdef CONFIG_USB_GADGET_DUALSPEED
.speed = USB_SPEED_HIGH,
#else
.speed = USB_SPEED_FULL,
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)