- Dave
[USB] usbnet updates: new devices, cleanups New devices: Aten UC210T, Zaurus SL-6000
Cleanup, factoring out shared CDC glue for Ethernet, Zaurus,
and eventually RNDIS.
--- a/drivers/usb/net/Kconfig Wed Feb 4 20:30:57 2004
+++ b/drivers/usb/net/Kconfig Wed Feb 4 20:30:57 2004
@@ -254,13 +254,14 @@
10/100 Ethernet devices.
This driver should work with at least the following devices:
+ * Aten UC210T
* ASIX AX88172
* D-Link DUB-E100
* Hawking UF200
* Linksys USB200M
* Netgear FA120
- * Intellinet
- * ST Lab USB Ethernet
+ * Intellinet USB 2.0 Ethernet
+ * ST Lab USB 2.0 Ethernet
* TrendNet TU2-ET100
This driver creates an interface named "ethX", where X depends on
--- a/drivers/usb/net/usbnet.c Wed Feb 4 20:30:57 2004
+++ b/drivers/usb/net/usbnet.c Wed Feb 4 20:30:57 2004
@@ -222,6 +222,7 @@
#define FLAG_FRAMING_NC 0x0001 /* guard against device dropouts */
#define FLAG_FRAMING_GL 0x0002 /* genelink batches packets */
#define FLAG_FRAMING_Z 0x0004 /* zaurus adds a trailer */
+#define FLAG_FRAMING_RN 0x0008 /* RNDIS batches, plus huge header */
#define FLAG_NO_SETINT 0x0010 /* device can't set_interface() */
#define FLAG_ETHER 0x0020 /* maybe use "eth%d" names */
@@ -300,7 +301,6 @@
/*-------------------------------------------------------------------------*/
-static struct ethtool_ops usbnet_ethtool_ops;
static void usbnet_get_drvinfo (struct net_device *, struct ethtool_drvinfo *);
static u32 usbnet_get_link (struct net_device *);
static u32 usbnet_get_msglevel (struct net_device *);
@@ -364,6 +364,25 @@
return 0;
}
+static void skb_return (struct usbnet *dev, struct sk_buff *skb)
+{
+ int status;
+
+ skb->dev = dev->net;
+ skb->protocol = eth_type_trans (skb, dev->net);
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += skb->len;
+
+#ifdef VERBOSE
+ devdbg (dev, "< rx, len %d, type 0x%x",
+ skb->len + sizeof (struct ethhdr), skb->protocol);
+#endif
+ memset (skb->cb, 0, sizeof (struct skb_data));
+ status = netif_rx (skb);
+ if (status != NET_RX_SUCCESS)
+ devdbg (dev, "netif_rx status %d", status);
+}
+
#ifdef CONFIG_USB_AN2720
#define HAVE_HARDWARE
@@ -818,23 +837,30 @@
-#if defined (CONFIG_USB_CDCETHER) || defined (CONFIG_USB_ZAURUS)
-
/*-------------------------------------------------------------------------
*
- * Communications Device Class, Ethernet Control model
- *
- * Takes two interfaces. The DATA interface is inactive till an altsetting
- * is selected. Configuration data includes class descriptors.
- *
- * Zaurus uses nonstandard framing, and doesn't uniquify its Ethernet
- * addresses, but is otherwise CDC Ether.
- *
- * This should interop with whatever the 2.4 "CDCEther.c" driver
- * (by Brad Hards) talked with.
+ * Communications Device Class declarations.
+ * Used by CDC Ethernet, and some CDC variants
*
*-------------------------------------------------------------------------*/
+#ifdef CONFIG_USB_CDCETHER
+#define NEED_GENERIC_CDC
+#endif
+
+#ifdef CONFIG_USB_ZAURUS
+/* Ethernet variant uses funky framing, broken ethernet addressing */
+#define NEED_GENERIC_CDC
+#endif
+
+#ifdef CONFIG_USB_RNDIS
+/* ACM variant uses even funkier framing, complex control RPC scheme */
+#define NEED_GENERIC_CDC
+#endif
+
+
+#ifdef NEED_GENERIC_CDC
+
/* "Header Functional Descriptor" from CDC spec 5.2.3.1 */
struct header_desc {
u8 bLength;
@@ -876,43 +902,21 @@
struct usb_interface *data;
};
-#include <linux/ctype.h>
-
-static u8 nibble (unsigned char c)
-{
- if (likely (isdigit (c)))
- return c - '0';
- c = toupper (c);
- if (likely (isxdigit (c)))
- return 10 + c - 'A';
- return 0;
-}
-
-static inline int get_ethernet_addr (struct usbnet *dev, struct ether_desc *e)
-{
- int tmp, i;
- unsigned char buf [13];
-
- tmp = usb_string (dev->udev, e->iMACAddress, buf, sizeof buf);
- if (tmp < 0)
- return tmp;
- else if (tmp != 12)
- return -EINVAL;
- for (i = tmp = 0; i < 6; i++, tmp += 2)
- dev->net->dev_addr [i] =
- (nibble (buf [tmp]) << 4) + nibble (buf [tmp + 1]);
- return 0;
-}
-
static struct usb_driver usbnet_driver;
-static int cdc_bind (struct usbnet *dev, struct usb_interface *intf)
+/*
+ * probes control interface, claims data interface, collects the bulk
+ * endpoints, activates data interface (if needed), maybe sets MTU.
+ * all pure cdc, except for certain firmware workarounds.
+ */
+static int generic_cdc_bind (struct usbnet *dev, struct usb_interface *intf)
{
u8 *buf = intf->altsetting->extra;
int len = intf->altsetting->extralen;
struct usb_interface_descriptor *d;
struct cdc_state *info = (void *) &dev->data;
int status;
+ int rndis;
if (sizeof dev->data < sizeof *info)
return -EDOM;
@@ -931,14 +935,23 @@
"CDC descriptors on config\n");
}
+ /* this assumes that if there's a non-RNDIS vendor variant
+ * of cdc-acm, it'll fail RNDIS requests cleanly.
+ */
+ rndis = (intf->altsetting->desc.bInterfaceProtocol == 0xff);
+
memset (info, 0, sizeof *info);
info->control = intf;
while (len > 3) {
if (buf [1] != USB_DT_CS_INTERFACE)
goto next_desc;
- /* bDescriptorSubType identifies three "must have" descriptors;
- * save them for later.
+ /* use bDescriptorSubType to identify the CDC descriptors.
+ * We expect devices with CDC header and union descriptors.
+ * For CDC Ethernet we need the ethernet descriptor.
+ * For RNDIS, ignore two (pointless) CDC modem descriptors
+ * in favor of a complicated OID-based RPC scheme doing what
+ * CDC Ethernet achieves with a simple descriptor.
*/
switch (buf [2]) {
case 0x00: /* Header, mostly useless */
@@ -1001,8 +1014,6 @@
d->bInterfaceClass);
goto bad_desc;
}
- if (usb_interface_claimed (info->data))
- return -EBUSY;
break;
case 0x0F: /* Ethernet Networking */
if (info->ether) {
@@ -1015,13 +1026,20 @@
info->u->bLength);
goto bad_desc;
}
+ dev->net->mtu = cpu_to_le16p (
+ &info->ether->wMaxSegmentSize)
+ - ETH_HLEN;
+ /* because of Zaurus, we may be ignoring the host
+ * side link address we were given.
+ */
break;
}
next_desc:
len -= buf [0]; /* bLength */
buf += buf [0];
}
- if (!info->header || !info ->u || !info->ether) {
+
+ if (!info->header || !info->u || (!rndis && !info->ether)) {
dev_dbg (&intf->dev, "missing cdc %s%s%sdescriptor\n",
info->header ? "" : "header ",
info->u ? "" : "union ",
@@ -1029,18 +1047,6 @@
goto bad_desc;
}
-#ifdef CONFIG_USB_ZAURUS
- /* Zaurus ethernet addresses aren't unique ... */
- if ((dev->driver_info->flags & FLAG_FRAMING_Z) != 0)
- /* ignore */ ;
- else
-#endif
- {
- status = get_ethernet_addr (dev, info->ether);
- if (status < 0)
- return status;
- }
-
/* claim data interface and set it up ... with side effects.
* network traffic can't flow until an altsetting is enabled.
*/
@@ -1049,16 +1055,11 @@
return status;
status = get_endpoints (dev, info->data);
if (status < 0) {
+ /* ensure immediate exit from usbnet_disconnect */
+ usb_set_intfdata(info->data, NULL);
usb_driver_release_interface (&usbnet_driver, info->data);
return status;
}
-
- /* FIXME cdc-ether has some multicast code too, though it complains
- * in routine cases. info->ether describes the multicast support.
- */
-
- dev->net->mtu = cpu_to_le16p (&info->ether->wMaxSegmentSize)
- - ETH_HLEN;
return 0;
bad_desc:
@@ -1072,24 +1073,89 @@
/* disconnect master --> disconnect slave */
if (intf == info->control && info->data) {
+ /* ensure immediate exit from usbnet_disconnect */
+ usb_set_intfdata(info->data, NULL);
usb_driver_release_interface (&usbnet_driver, info->data);
info->data = 0;
}
/* and vice versa (just in case) */
else if (intf == info->data && info->control) {
+ /* ensure immediate exit from usbnet_disconnect */
+ usb_set_intfdata(info->control, NULL);
usb_driver_release_interface (&usbnet_driver, info->control);
info->control = 0;
}
-
}
-#endif /* CONFIG_USB_ZAURUS || CONFIG_USB_CDCETHER */
-
+#endif /* NEED_GENERIC_CDC */
+
#ifdef CONFIG_USB_CDCETHER
#define HAVE_HARDWARE
+/*-------------------------------------------------------------------------
+ *
+ * Communications Device Class, Ethernet Control model
+ *
+ * Takes two interfaces. The DATA interface is inactive till an altsetting
+ * is selected. Configuration data includes class descriptors.
+ *
+ * This should interop with whatever the 2.4 "CDCEther.c" driver
+ * (by Brad Hards) talked with.
+ *
+ *-------------------------------------------------------------------------*/
+
+#include <linux/ctype.h>
+
+static u8 nibble (unsigned char c)
+{
+ if (likely (isdigit (c)))
+ return c - '0';
+ c = toupper (c);
+ if (likely (isxdigit (c)))
+ return 10 + c - 'A';
+ return 0;
+}
+
+static inline int
+get_ethernet_addr (struct usbnet *dev, struct ether_desc *e)
+{
+ int tmp, i;
+ unsigned char buf [13];
+
+ tmp = usb_string (dev->udev, e->iMACAddress, buf, sizeof buf);
+ if (tmp < 0)
+ return tmp;
+ else if (tmp != 12)
+ return -EINVAL;
+ for (i = tmp = 0; i < 6; i++, tmp += 2)
+ dev->net->dev_addr [i] =
+ (nibble (buf [tmp]) << 4) + nibble (buf [tmp + 1]);
+ return 0;
+}
+
+static int cdc_bind (struct usbnet *dev, struct usb_interface *intf)
+{
+ int status;
+ struct cdc_state *info = (void *) &dev->data;
+
+ status = generic_cdc_bind (dev, intf);
+ if (status < 0)
+ return status;
+
+ status = get_ethernet_addr (dev, info->ether);
+ if (status < 0) {
+ usb_driver_release_interface (&usbnet_driver, info->data);
+ return status;
+ }
+
+ /* FIXME cdc-ether has some multicast code too, though it complains
+ * in routine cases. info->ether describes the multicast support.
+ */
+ return 0;
+}
+
static const struct driver_info cdc_info = {
.description = "CDC Ethernet Device",
.flags = FLAG_ETHER,
@@ -1337,7 +1403,6 @@
struct gl_header *header;
struct gl_packet *packet;
struct sk_buff *gl_skb;
- int status;
u32 size;
header = (struct gl_header *) skb->data;
@@ -1373,17 +1438,7 @@
// copy the packet data to the new skb
memcpy(skb_put(gl_skb, size), packet->packet_data, size);
- gl_skb->dev = dev->net;
-
- // determine the packet's protocol ID
- gl_skb->protocol = eth_type_trans (gl_skb, dev->net);
-
- // update the status
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += size;
-
- // notify os of the received packet
- status = netif_rx (gl_skb);
+ skb_return (dev, skb);
}
// advance to the next packet
@@ -2141,7 +2196,7 @@
.description = "Sharp Zaurus SL-5x00",
.flags = FLAG_FRAMING_Z,
.check_connect = always_connected,
- .bind = cdc_bind,
+ .bind = generic_cdc_bind,
.unbind = cdc_unbind,
.tx_fixup = zaurus_tx_fixup,
};
@@ -2256,6 +2311,11 @@
size = 6 + (sizeof (struct ethhdr) + dev->net->mtu);
else
#endif
+#ifdef CONFIG_USB_RNDIS
+ if (dev->driver_info->flags & FLAG_FRAMING_RN)
+ size = RNDIS_MAX_TRANSFER;
+ else
+#endif
size = (sizeof (struct ethhdr) + dev->net->mtu);
if ((skb = alloc_skb (size, flags)) == 0) {
@@ -2319,23 +2379,9 @@
goto error;
// else network stack removes extra byte if we forced a short packet
- if (skb->len) {
- int status;
-
- skb->dev = dev->net;
- skb->protocol = eth_type_trans (skb, dev->net);
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += skb->len;
-
-#ifdef VERBOSE
- devdbg (dev, "< rx, len %d, type 0x%x",
- skb->len + sizeof (struct ethhdr), skb->protocol);
-#endif
- memset (skb->cb, 0, sizeof (struct skb_data));
- status = netif_rx (skb);
- if (status != NET_RX_SUCCESS)
- devdbg (dev, "netif_rx status %d", status);
- } else {
+ if (skb->len)
+ skb_return (dev, skb);
+ else {
devdbg (dev, "drop");
error:
dev->stats.rx_errors++;
@@ -2544,6 +2590,8 @@
framing = "GeneSys";
else if (dev->driver_info->flags & FLAG_FRAMING_Z)
framing = "Zaurus";
+ else if (dev->driver_info->flags & FLAG_FRAMING_RN)
+ framing = "RNDIS";
else
framing = "simple";
@@ -2941,6 +2989,8 @@
/*-------------------------------------------------------------------------*/
+static struct ethtool_ops usbnet_ethtool_ops;
+
// precondition: never called in_interrupt
int
@@ -3127,7 +3177,11 @@
// Hawking UF200, TrendNet TU2-ET100
USB_DEVICE (0x07b8, 0x420a),
.driver_info = (unsigned long) &hawking_uf200_info,
-},
+}, {
+ // ATEN UC210T
+ USB_DEVICE (0x0557, 0x2009),
+ .driver_info = (unsigned long) &ax8817x_info,
+},
#endif
#ifdef CONFIG_USB_EPSON2888
@@ -3167,6 +3221,14 @@
},
#endif
+#ifdef CONFIG_USB_RNDIS
+{
+ /* RNDIS is MSFT's un-official variant of CDC ACM */
+ USB_INTERFACE_INFO (USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
+ .driver_info = (unsigned long) &rndis_info,
+},
+#endif
+
#ifdef CONFIG_USB_ARMLINUX
/*
* SA-1100 using standard ARM Linux kernels, or compatible.
@@ -3238,7 +3300,16 @@
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
- .idProduct = 0x9031, /* C-750 */
+ .idProduct = 0x9031, /* C-750 C-760 */
+ .bInterfaceClass = 0x02,
+ .bInterfaceSubClass = 0x0a,
+ .bInterfaceProtocol = 0x00,
+ .driver_info = (unsigned long) &zaurus_pxa_info,
+}, {
+ .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
+ | USB_DEVICE_ID_MATCH_DEVICE,
+ .idVendor = 0x04DD,
+ .idProduct = 0x9032, /* SL-6000 */
.bInterfaceClass = 0x02,
.bInterfaceSubClass = 0x0a,
.bInterfaceProtocol = 0x00,
