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

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 *) &ether_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 *) &ether_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, &eth_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, &ether_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 (&eth_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)