Commit 662c60e7 authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

[PATCH] USB: usbnet updates (new devices)

[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.
parent deb7db4f
...@@ -254,13 +254,14 @@ config USB_AX8817X ...@@ -254,13 +254,14 @@ config USB_AX8817X
10/100 Ethernet devices. 10/100 Ethernet devices.
This driver should work with at least the following devices: This driver should work with at least the following devices:
* Aten UC210T
* ASIX AX88172 * ASIX AX88172
* D-Link DUB-E100 * D-Link DUB-E100
* Hawking UF200 * Hawking UF200
* Linksys USB200M * Linksys USB200M
* Netgear FA120 * Netgear FA120
* Intellinet * Intellinet USB 2.0 Ethernet
* ST Lab USB Ethernet * ST Lab USB 2.0 Ethernet
* TrendNet TU2-ET100 * TrendNet TU2-ET100
This driver creates an interface named "ethX", where X depends on This driver creates an interface named "ethX", where X depends on
......
...@@ -222,6 +222,7 @@ struct driver_info { ...@@ -222,6 +222,7 @@ struct driver_info {
#define FLAG_FRAMING_NC 0x0001 /* guard against device dropouts */ #define FLAG_FRAMING_NC 0x0001 /* guard against device dropouts */
#define FLAG_FRAMING_GL 0x0002 /* genelink batches packets */ #define FLAG_FRAMING_GL 0x0002 /* genelink batches packets */
#define FLAG_FRAMING_Z 0x0004 /* zaurus adds a trailer */ #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_NO_SETINT 0x0010 /* device can't set_interface() */
#define FLAG_ETHER 0x0020 /* maybe use "eth%d" names */ #define FLAG_ETHER 0x0020 /* maybe use "eth%d" names */
...@@ -300,7 +301,6 @@ MODULE_PARM_DESC (msg_level, "Initial message level (default = 1)"); ...@@ -300,7 +301,6 @@ MODULE_PARM_DESC (msg_level, "Initial message level (default = 1)");
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static struct ethtool_ops usbnet_ethtool_ops;
static void usbnet_get_drvinfo (struct net_device *, struct ethtool_drvinfo *); static void usbnet_get_drvinfo (struct net_device *, struct ethtool_drvinfo *);
static u32 usbnet_get_link (struct net_device *); static u32 usbnet_get_link (struct net_device *);
static u32 usbnet_get_msglevel (struct net_device *); static u32 usbnet_get_msglevel (struct net_device *);
...@@ -364,6 +364,25 @@ get_endpoints (struct usbnet *dev, struct usb_interface *intf) ...@@ -364,6 +364,25 @@ get_endpoints (struct usbnet *dev, struct usb_interface *intf)
return 0; 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 #ifdef CONFIG_USB_AN2720
#define HAVE_HARDWARE #define HAVE_HARDWARE
...@@ -818,23 +837,30 @@ static const struct driver_info belkin_info = { ...@@ -818,23 +837,30 @@ static const struct driver_info belkin_info = {
#if defined (CONFIG_USB_CDCETHER) || defined (CONFIG_USB_ZAURUS)
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* Communications Device Class, Ethernet Control model * Communications Device Class declarations.
* * Used by CDC Ethernet, and some CDC variants
* 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.
* *
*-------------------------------------------------------------------------*/ *-------------------------------------------------------------------------*/
#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 */ /* "Header Functional Descriptor" from CDC spec 5.2.3.1 */
struct header_desc { struct header_desc {
u8 bLength; u8 bLength;
...@@ -876,43 +902,21 @@ struct cdc_state { ...@@ -876,43 +902,21 @@ struct cdc_state {
struct usb_interface *data; 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 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; u8 *buf = intf->altsetting->extra;
int len = intf->altsetting->extralen; int len = intf->altsetting->extralen;
struct usb_interface_descriptor *d; struct usb_interface_descriptor *d;
struct cdc_state *info = (void *) &dev->data; struct cdc_state *info = (void *) &dev->data;
int status; int status;
int rndis;
if (sizeof dev->data < sizeof *info) if (sizeof dev->data < sizeof *info)
return -EDOM; return -EDOM;
...@@ -931,14 +935,23 @@ static int cdc_bind (struct usbnet *dev, struct usb_interface *intf) ...@@ -931,14 +935,23 @@ static int cdc_bind (struct usbnet *dev, struct usb_interface *intf)
"CDC descriptors on config\n"); "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); memset (info, 0, sizeof *info);
info->control = intf; info->control = intf;
while (len > 3) { while (len > 3) {
if (buf [1] != USB_DT_CS_INTERFACE) if (buf [1] != USB_DT_CS_INTERFACE)
goto next_desc; goto next_desc;
/* bDescriptorSubType identifies three "must have" descriptors; /* use bDescriptorSubType to identify the CDC descriptors.
* save them for later. * 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]) { switch (buf [2]) {
case 0x00: /* Header, mostly useless */ case 0x00: /* Header, mostly useless */
...@@ -1001,8 +1014,6 @@ static int cdc_bind (struct usbnet *dev, struct usb_interface *intf) ...@@ -1001,8 +1014,6 @@ static int cdc_bind (struct usbnet *dev, struct usb_interface *intf)
d->bInterfaceClass); d->bInterfaceClass);
goto bad_desc; goto bad_desc;
} }
if (usb_interface_claimed (info->data))
return -EBUSY;
break; break;
case 0x0F: /* Ethernet Networking */ case 0x0F: /* Ethernet Networking */
if (info->ether) { if (info->ether) {
...@@ -1015,13 +1026,20 @@ static int cdc_bind (struct usbnet *dev, struct usb_interface *intf) ...@@ -1015,13 +1026,20 @@ static int cdc_bind (struct usbnet *dev, struct usb_interface *intf)
info->u->bLength); info->u->bLength);
goto bad_desc; 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; break;
} }
next_desc: next_desc:
len -= buf [0]; /* bLength */ len -= buf [0]; /* bLength */
buf += buf [0]; 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", dev_dbg (&intf->dev, "missing cdc %s%s%sdescriptor\n",
info->header ? "" : "header ", info->header ? "" : "header ",
info->u ? "" : "union ", info->u ? "" : "union ",
...@@ -1029,18 +1047,6 @@ static int cdc_bind (struct usbnet *dev, struct usb_interface *intf) ...@@ -1029,18 +1047,6 @@ static int cdc_bind (struct usbnet *dev, struct usb_interface *intf)
goto bad_desc; 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. /* claim data interface and set it up ... with side effects.
* network traffic can't flow until an altsetting is enabled. * network traffic can't flow until an altsetting is enabled.
*/ */
...@@ -1049,16 +1055,11 @@ static int cdc_bind (struct usbnet *dev, struct usb_interface *intf) ...@@ -1049,16 +1055,11 @@ static int cdc_bind (struct usbnet *dev, struct usb_interface *intf)
return status; return status;
status = get_endpoints (dev, info->data); status = get_endpoints (dev, info->data);
if (status < 0) { if (status < 0) {
/* ensure immediate exit from usbnet_disconnect */
usb_set_intfdata(info->data, NULL);
usb_driver_release_interface (&usbnet_driver, info->data); usb_driver_release_interface (&usbnet_driver, info->data);
return status; 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; return 0;
bad_desc: bad_desc:
...@@ -1072,24 +1073,89 @@ static void cdc_unbind (struct usbnet *dev, struct usb_interface *intf) ...@@ -1072,24 +1073,89 @@ static void cdc_unbind (struct usbnet *dev, struct usb_interface *intf)
/* disconnect master --> disconnect slave */ /* disconnect master --> disconnect slave */
if (intf == info->control && info->data) { 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); usb_driver_release_interface (&usbnet_driver, info->data);
info->data = 0; info->data = 0;
} }
/* and vice versa (just in case) */ /* and vice versa (just in case) */
else if (intf == info->data && info->control) { 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); usb_driver_release_interface (&usbnet_driver, info->control);
info->control = 0; info->control = 0;
} }
} }
#endif /* CONFIG_USB_ZAURUS || CONFIG_USB_CDCETHER */ #endif /* NEED_GENERIC_CDC */
#ifdef CONFIG_USB_CDCETHER #ifdef CONFIG_USB_CDCETHER
#define HAVE_HARDWARE #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 = { static const struct driver_info cdc_info = {
.description = "CDC Ethernet Device", .description = "CDC Ethernet Device",
.flags = FLAG_ETHER, .flags = FLAG_ETHER,
...@@ -1337,7 +1403,6 @@ static int genelink_rx_fixup (struct usbnet *dev, struct sk_buff *skb) ...@@ -1337,7 +1403,6 @@ static int genelink_rx_fixup (struct usbnet *dev, struct sk_buff *skb)
struct gl_header *header; struct gl_header *header;
struct gl_packet *packet; struct gl_packet *packet;
struct sk_buff *gl_skb; struct sk_buff *gl_skb;
int status;
u32 size; u32 size;
header = (struct gl_header *) skb->data; header = (struct gl_header *) skb->data;
...@@ -1373,17 +1438,7 @@ static int genelink_rx_fixup (struct usbnet *dev, struct sk_buff *skb) ...@@ -1373,17 +1438,7 @@ static int genelink_rx_fixup (struct usbnet *dev, struct sk_buff *skb)
// copy the packet data to the new skb // copy the packet data to the new skb
memcpy(skb_put(gl_skb, size), packet->packet_data, size); memcpy(skb_put(gl_skb, size), packet->packet_data, size);
gl_skb->dev = dev->net; skb_return (dev, skb);
// 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);
} }
// advance to the next packet // advance to the next packet
...@@ -2141,7 +2196,7 @@ static const struct driver_info zaurus_sl5x00_info = { ...@@ -2141,7 +2196,7 @@ static const struct driver_info zaurus_sl5x00_info = {
.description = "Sharp Zaurus SL-5x00", .description = "Sharp Zaurus SL-5x00",
.flags = FLAG_FRAMING_Z, .flags = FLAG_FRAMING_Z,
.check_connect = always_connected, .check_connect = always_connected,
.bind = cdc_bind, .bind = generic_cdc_bind,
.unbind = cdc_unbind, .unbind = cdc_unbind,
.tx_fixup = zaurus_tx_fixup, .tx_fixup = zaurus_tx_fixup,
}; };
...@@ -2255,6 +2310,11 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, int flags) ...@@ -2255,6 +2310,11 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, int flags)
if (dev->driver_info->flags & FLAG_FRAMING_Z) if (dev->driver_info->flags & FLAG_FRAMING_Z)
size = 6 + (sizeof (struct ethhdr) + dev->net->mtu); size = 6 + (sizeof (struct ethhdr) + dev->net->mtu);
else else
#endif
#ifdef CONFIG_USB_RNDIS
if (dev->driver_info->flags & FLAG_FRAMING_RN)
size = RNDIS_MAX_TRANSFER;
else
#endif #endif
size = (sizeof (struct ethhdr) + dev->net->mtu); size = (sizeof (struct ethhdr) + dev->net->mtu);
...@@ -2319,23 +2379,9 @@ static inline void rx_process (struct usbnet *dev, struct sk_buff *skb) ...@@ -2319,23 +2379,9 @@ static inline void rx_process (struct usbnet *dev, struct sk_buff *skb)
goto error; goto error;
// else network stack removes extra byte if we forced a short packet // else network stack removes extra byte if we forced a short packet
if (skb->len) { if (skb->len)
int status; skb_return (dev, skb);
else {
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 {
devdbg (dev, "drop"); devdbg (dev, "drop");
error: error:
dev->stats.rx_errors++; dev->stats.rx_errors++;
...@@ -2544,6 +2590,8 @@ static int usbnet_open (struct net_device *net) ...@@ -2544,6 +2590,8 @@ static int usbnet_open (struct net_device *net)
framing = "GeneSys"; framing = "GeneSys";
else if (dev->driver_info->flags & FLAG_FRAMING_Z) else if (dev->driver_info->flags & FLAG_FRAMING_Z)
framing = "Zaurus"; framing = "Zaurus";
else if (dev->driver_info->flags & FLAG_FRAMING_RN)
framing = "RNDIS";
else else
framing = "simple"; framing = "simple";
...@@ -2941,6 +2989,8 @@ static void usbnet_disconnect (struct usb_interface *intf) ...@@ -2941,6 +2989,8 @@ static void usbnet_disconnect (struct usb_interface *intf)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static struct ethtool_ops usbnet_ethtool_ops;
// precondition: never called in_interrupt // precondition: never called in_interrupt
int int
...@@ -3127,7 +3177,11 @@ static const struct usb_device_id products [] = { ...@@ -3127,7 +3177,11 @@ static const struct usb_device_id products [] = {
// Hawking UF200, TrendNet TU2-ET100 // Hawking UF200, TrendNet TU2-ET100
USB_DEVICE (0x07b8, 0x420a), USB_DEVICE (0x07b8, 0x420a),
.driver_info = (unsigned long) &hawking_uf200_info, .driver_info = (unsigned long) &hawking_uf200_info,
}, }, {
// ATEN UC210T
USB_DEVICE (0x0557, 0x2009),
.driver_info = (unsigned long) &ax8817x_info,
},
#endif #endif
#ifdef CONFIG_USB_EPSON2888 #ifdef CONFIG_USB_EPSON2888
...@@ -3167,6 +3221,14 @@ static const struct usb_device_id products [] = { ...@@ -3167,6 +3221,14 @@ static const struct usb_device_id products [] = {
}, },
#endif #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 #ifdef CONFIG_USB_ARMLINUX
/* /*
* SA-1100 using standard ARM Linux kernels, or compatible. * SA-1100 using standard ARM Linux kernels, or compatible.
...@@ -3238,7 +3300,16 @@ static const struct usb_device_id products [] = { ...@@ -3238,7 +3300,16 @@ static const struct usb_device_id products [] = {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE, | USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD, .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, .bInterfaceClass = 0x02,
.bInterfaceSubClass = 0x0a, .bInterfaceSubClass = 0x0a,
.bInterfaceProtocol = 0x00, .bInterfaceProtocol = 0x00,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment