]> err.no Git - linux-2.6/commitdiff
[PATCH] USB: usbnet (7/9) module for CDC Ethernet
authorDavid Brownell <david-b@pacbell.net>
Wed, 31 Aug 2005 16:54:20 +0000 (09:54 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Thu, 8 Sep 2005 23:28:32 +0000 (16:28 -0700)
Makes the CDC Ethernet support live in a separate driver module.
This module is a bit special since it exports utility functions
that are reused by the the Zaurus and RNDIS drivers, but it's
not "core" like usbnet itself.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/net/Kconfig
drivers/usb/net/Makefile
drivers/usb/net/cdc_ether.c [new file with mode: 0644]
drivers/usb/net/usbnet.c

index 20de10916a4e21ae0519bd55ca64b529ae15cd55..4921101d93d0d0becfa204be118501c349497393 100644 (file)
@@ -137,35 +137,6 @@ config USB_PL2301
          Choose this option if you're using a host-to-host cable
          with one of these chips.
 
-comment "Intelligent USB Devices/Gadgets"
-       depends on USB_USBNET
-
-config USB_CDCETHER
-       boolean "CDC Ethernet support (smart devices such as cable modems)"
-       depends on USB_USBNET
-       default y
-       help
-         This option supports devices conforming to the Communication Device
-         Class (CDC) Ethernet Control Model, a specification that's easy to
-         implement in device firmware.  The CDC specifications are available
-         from <http://www.usb.org/>.
-         
-         CDC Ethernet is an implementation option for DOCSIS cable modems
-         that support USB connectivity, used for non-Microsoft USB hosts.
-         The Linux-USB CDC Ethernet Gadget driver is an open implementation.
-         This driver should work with at least the following devices:
-
-           * Ericsson PipeRider (all variants)
-           * Motorola (DM100 and SB4100)
-           * Broadcom Cable Modem (reference design)
-           * Toshiba PCX1100U
-           * ...
-
-         This driver creates an interface named "ethX", where X depends on
-         what other networking devices you have in use.  However, if the
-         IEEE 802 "local assignment" bit is set in the address, a "usbX"
-         name is used instead.
-
 comment "Drivers built using the usbnet core"
 
 config USB_NET_AX8817X
@@ -197,6 +168,32 @@ config USB_NET_AX8817X
          what other networking devices you have in use.
 
 
+config USB_NET_CDCETHER
+       tristate "CDC Ethernet support (smart devices such as cable modems)"
+       depends on USB_USBNET
+       default y
+       help
+         This option supports devices conforming to the Communication Device
+         Class (CDC) Ethernet Control Model, a specification that's easy to
+         implement in device firmware.  The CDC specifications are available
+         from <http://www.usb.org/>.
+
+         CDC Ethernet is an implementation option for DOCSIS cable modems
+         that support USB connectivity, used for non-Microsoft USB hosts.
+         The Linux-USB CDC Ethernet Gadget driver is an open implementation.
+         This driver should work with at least the following devices:
+
+           * Ericsson PipeRider (all variants)
+           * Motorola (DM100 and SB4100)
+           * Broadcom Cable Modem (reference design)
+           * Toshiba PCX1100U
+           * ...
+
+         This driver creates an interface named "ethX", where X depends on
+         what other networking devices you have in use.  However, if the
+         IEEE 802 "local assignment" bit is set in the address, a "usbX"
+         name is used instead.
+
 config USB_NET_GL620A
        tristate "GeneSys GL620USB-A based cables"
        depends on USB_USBNET
@@ -280,6 +277,7 @@ config USB_EPSON2888
 config USB_NET_ZAURUS
        tristate "Sharp Zaurus (stock ROMs) and compatible"
        depends on USB_USBNET
+       select USB_NET_CDCETHER
        select CRC32
        default y
        help
index e13d7af3114b3bb2884cd5eb24968008954fe06e..697eb1913208402c2c207cb370979aa8d7452b73 100644 (file)
@@ -7,6 +7,7 @@ obj-$(CONFIG_USB_KAWETH)        += kaweth.o
 obj-$(CONFIG_USB_PEGASUS)      += pegasus.o
 obj-$(CONFIG_USB_RTL8150)      += rtl8150.o
 obj-$(CONFIG_USB_NET_AX8817X)  += asix.o
+obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o
 obj-$(CONFIG_USB_NET_GL620A)   += gl620a.o
 obj-$(CONFIG_USB_NET_NET1080)  += net1080.o
 obj-$(CONFIG_USB_NET_CDC_SUBSET)       += cdc_subset.o
diff --git a/drivers/usb/net/cdc_ether.c b/drivers/usb/net/cdc_ether.c
new file mode 100644 (file)
index 0000000..652b04b
--- /dev/null
@@ -0,0 +1,509 @@
+/*
+ * CDC Ethernet based networking peripherals
+ * Copyright (C) 2003-2005 by David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+// #define     DEBUG                   // error path messages, extra info
+// #define     VERBOSE                 // more; success messages
+
+#include <linux/config.h>
+#ifdef CONFIG_USB_DEBUG
+#   define DEBUG
+#endif
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ctype.h>
+#include <linux/ethtool.h>
+#include <linux/workqueue.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/usb_cdc.h>
+
+#include "usbnet.h"
+
+
+/*
+ * 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, and knowing
+ * that rndis uses one different rule.
+ */
+int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+       u8                              *buf = intf->cur_altsetting->extra;
+       int                             len = intf->cur_altsetting->extralen;
+       struct usb_interface_descriptor *d;
+       struct cdc_state                *info = (void *) &dev->data;
+       int                             status;
+       int                             rndis;
+       struct usb_driver               *driver = driver_of(intf);
+
+       if (sizeof dev->data < sizeof *info)
+               return -EDOM;
+
+       /* expect strict spec conformance for the descriptors, but
+        * cope with firmware which stores them in the wrong place
+        */
+       if (len == 0 && dev->udev->actconfig->extralen) {
+               /* Motorola SB4100 (and others: Brad Hards says it's
+                * from a Broadcom design) put CDC descriptors here
+                */
+               buf = dev->udev->actconfig->extra;
+               len = dev->udev->actconfig->extralen;
+               if (len)
+                       dev_dbg(&intf->dev,
+                               "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->cur_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;
+
+               /* 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 USB_CDC_HEADER_TYPE:
+                       if (info->header) {
+                               dev_dbg(&intf->dev, "extra CDC header\n");
+                               goto bad_desc;
+                       }
+                       info->header = (void *) buf;
+                       if (info->header->bLength != sizeof *info->header) {
+                               dev_dbg(&intf->dev, "CDC header len %u\n",
+                                       info->header->bLength);
+                               goto bad_desc;
+                       }
+                       break;
+               case USB_CDC_UNION_TYPE:
+                       if (info->u) {
+                               dev_dbg(&intf->dev, "extra CDC union\n");
+                               goto bad_desc;
+                       }
+                       info->u = (void *) buf;
+                       if (info->u->bLength != sizeof *info->u) {
+                               dev_dbg(&intf->dev, "CDC union len %u\n",
+                                       info->u->bLength);
+                               goto bad_desc;
+                       }
+
+                       /* we need a master/control interface (what we're
+                        * probed with) and a slave/data interface; union
+                        * descriptors sort this all out.
+                        */
+                       info->control = usb_ifnum_to_if(dev->udev,
+                                               info->u->bMasterInterface0);
+                       info->data = usb_ifnum_to_if(dev->udev,
+                                               info->u->bSlaveInterface0);
+                       if (!info->control || !info->data) {
+                               dev_dbg(&intf->dev,
+                                       "master #%u/%p slave #%u/%p\n",
+                                       info->u->bMasterInterface0,
+                                       info->control,
+                                       info->u->bSlaveInterface0,
+                                       info->data);
+                               goto bad_desc;
+                       }
+                       if (info->control != intf) {
+                               dev_dbg(&intf->dev, "bogus CDC Union\n");
+                               /* Ambit USB Cable Modem (and maybe others)
+                                * interchanges master and slave interface.
+                                */
+                               if (info->data == intf) {
+                                       info->data = info->control;
+                                       info->control = intf;
+                               } else
+                                       goto bad_desc;
+                       }
+
+                       /* a data interface altsetting does the real i/o */
+                       d = &info->data->cur_altsetting->desc;
+                       if (d->bInterfaceClass != USB_CLASS_CDC_DATA) {
+                               dev_dbg(&intf->dev, "slave class %u\n",
+                                       d->bInterfaceClass);
+                               goto bad_desc;
+                       }
+                       break;
+               case USB_CDC_ETHERNET_TYPE:
+                       if (info->ether) {
+                               dev_dbg(&intf->dev, "extra CDC ether\n");
+                               goto bad_desc;
+                       }
+                       info->ether = (void *) buf;
+                       if (info->ether->bLength != sizeof *info->ether) {
+                               dev_dbg(&intf->dev, "CDC ether len %u\n",
+                                       info->ether->bLength);
+                               goto bad_desc;
+                       }
+                       dev->hard_mtu = le16_to_cpu(
+                                               info->ether->wMaxSegmentSize);
+                       /* 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 || (!rndis && !info->ether)) {
+               dev_dbg(&intf->dev, "missing cdc %s%s%sdescriptor\n",
+                       info->header ? "" : "header ",
+                       info->u ? "" : "union ",
+                       info->ether ? "" : "ether ");
+               goto bad_desc;
+       }
+
+       /* claim data interface and set it up ... with side effects.
+        * network traffic can't flow until an altsetting is enabled.
+        */
+       status = usb_driver_claim_interface(driver, info->data, dev);
+       if (status < 0)
+               return status;
+       status = usbnet_get_endpoints(dev, info->data);
+       if (status < 0) {
+               /* ensure immediate exit from usbnet_disconnect */
+               usb_set_intfdata(info->data, NULL);
+               usb_driver_release_interface(driver, info->data);
+               return status;
+       }
+
+       /* status endpoint: optional for CDC Ethernet, not RNDIS (or ACM) */
+       dev->status = NULL;
+       if (info->control->cur_altsetting->desc.bNumEndpoints == 1) {
+               struct usb_endpoint_descriptor  *desc;
+
+               dev->status = &info->control->cur_altsetting->endpoint [0];
+               desc = &dev->status->desc;
+               if (desc->bmAttributes != USB_ENDPOINT_XFER_INT
+                               || !(desc->bEndpointAddress & USB_DIR_IN)
+                               || (le16_to_cpu(desc->wMaxPacketSize)
+                                       < sizeof(struct usb_cdc_notification))
+                               || !desc->bInterval) {
+                       dev_dbg(&intf->dev, "bad notification endpoint\n");
+                       dev->status = NULL;
+               }
+       }
+       if (rndis && !dev->status) {
+               dev_dbg(&intf->dev, "missing RNDIS status endpoint\n");
+               usb_set_intfdata(info->data, NULL);
+               usb_driver_release_interface(driver, info->data);
+               return -ENODEV;
+       }
+       return 0;
+
+bad_desc:
+       dev_info(&dev->udev->dev, "bad CDC descriptors\n");
+       return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(usbnet_generic_cdc_bind);
+
+void usbnet_cdc_unbind(struct usbnet *dev, struct usb_interface *intf)
+{
+       struct cdc_state                *info = (void *) &dev->data;
+       struct usb_driver               *driver = driver_of(intf);
+
+       /* 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(driver, info->data);
+               info->data = NULL;
+       }
+
+       /* 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(driver, info->control);
+               info->control = NULL;
+       }
+}
+EXPORT_SYMBOL_GPL(usbnet_cdc_unbind);
+
+\f
+/*-------------------------------------------------------------------------
+ *
+ * Communications Device Class, Ethernet Control model
+ *
+ * Takes two interfaces.  The DATA interface is inactive till an altsetting
+ * is selected.  Configuration data includes class descriptors.  There's
+ * an optional status endpoint on the control interface.
+ *
+ * This should interop with whatever the 2.4 "CDCEther.c" driver
+ * (by Brad Hards) talked with, with more functionality.
+ *
+ *-------------------------------------------------------------------------*/
+
+static void dumpspeed(struct usbnet *dev, __le32 *speeds)
+{
+       if (netif_msg_timer(dev))
+               devinfo(dev, "link speeds: %u kbps up, %u kbps down",
+                       __le32_to_cpu(speeds[0]) / 1000,
+               __le32_to_cpu(speeds[1]) / 1000);
+}
+
+static void cdc_status(struct usbnet *dev, struct urb *urb)
+{
+       struct usb_cdc_notification     *event;
+
+       if (urb->actual_length < sizeof *event)
+               return;
+
+       /* SPEED_CHANGE can get split into two 8-byte packets */
+       if (test_and_clear_bit(EVENT_STS_SPLIT, &dev->flags)) {
+               dumpspeed(dev, (__le32 *) urb->transfer_buffer);
+               return;
+       }
+
+       event = urb->transfer_buffer;
+       switch (event->bNotificationType) {
+       case USB_CDC_NOTIFY_NETWORK_CONNECTION:
+               if (netif_msg_timer(dev))
+                       devdbg(dev, "CDC: carrier %s",
+                                       event->wValue ? "on" : "off");
+               if (event->wValue)
+                       netif_carrier_on(dev->net);
+               else
+                       netif_carrier_off(dev->net);
+               break;
+       case USB_CDC_NOTIFY_SPEED_CHANGE:       /* tx/rx rates */
+               if (netif_msg_timer(dev))
+                       devdbg(dev, "CDC: speed change (len %d)",
+                                       urb->actual_length);
+               if (urb->actual_length != (sizeof *event + 8))
+                       set_bit(EVENT_STS_SPLIT, &dev->flags);
+               else
+                       dumpspeed(dev, (__le32 *) &event[1]);
+               break;
+       /* USB_CDC_NOTIFY_RESPONSE_AVAILABLE can happen too (e.g. RNDIS),
+        * but there are no standard formats for the response data.
+        */
+       default:
+               deverr(dev, "CDC: unexpected notification %02x!",
+                                event->bNotificationType);
+               break;
+       }
+}
+
+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 usb_cdc_ether_desc *e)
+{
+       int             tmp, i;
+       unsigned char   buf [13];
+
+       tmp = usb_string(dev->udev, e->iMACAddress, buf, sizeof buf);
+       if (tmp != 12) {
+               dev_dbg(&dev->udev->dev,
+                       "bad MAC string %d fetch, %d\n", e->iMACAddress, tmp);
+               if (tmp >= 0)
+                       tmp = -EINVAL;
+               return tmp;
+       }
+       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 = usbnet_generic_cdc_bind(dev, intf);
+       if (status < 0)
+               return status;
+
+       status = get_ethernet_addr(dev, info->ether);
+       if (status < 0) {
+               usb_set_intfdata(info->data, NULL);
+               usb_driver_release_interface(driver_of(intf), info->data);
+               return status;
+       }
+
+       /* FIXME cdc-ether has some multicast code too, though it complains
+        * in routine cases.  info->ether describes the multicast support.
+        * Implement that here, manipulating the cdc filter as needed.
+        */
+       return 0;
+}
+
+static const struct driver_info        cdc_info = {
+       .description =  "CDC Ethernet Device",
+       .flags =        FLAG_ETHER,
+       // .check_connect = cdc_check_connect,
+       .bind =         cdc_bind,
+       .unbind =       usbnet_cdc_unbind,
+       .status =       cdc_status,
+};
+
+/*-------------------------------------------------------------------------*/
+
+
+static const struct usb_device_id      products [] = {
+/*
+ * BLACKLIST !!
+ *
+ * First blacklist any products that are egregiously nonconformant
+ * with the CDC Ethernet specs.  Minor braindamage we cope with; when
+ * they're not even trying, needing a separate driver is only the first
+ * of the differences to show up.
+ */
+
+#define        ZAURUS_MASTER_INTERFACE \
+       .bInterfaceClass        = USB_CLASS_COMM, \
+       .bInterfaceSubClass     = USB_CDC_SUBCLASS_ETHERNET, \
+       .bInterfaceProtocol     = USB_CDC_PROTO_NONE
+
+/* SA-1100 based Sharp Zaurus ("collie"), or compatible;
+ * wire-incompatible with true CDC Ethernet implementations.
+ * (And, it seems, needlessly so...)
+ */
+{
+       .match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+                         | USB_DEVICE_ID_MATCH_DEVICE,
+       .idVendor               = 0x04DD,
+       .idProduct              = 0x8004,
+       ZAURUS_MASTER_INTERFACE,
+       .driver_info            = 0,
+},
+
+/* PXA-25x based Sharp Zaurii.  Note that it seems some of these
+ * (later models especially) may have shipped only with firmware
+ * advertising false "CDC MDLM" compatibility ... but we're not
+ * clear which models did that, so for now let's assume the worst.
+ */
+{
+       .match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+                         | USB_DEVICE_ID_MATCH_DEVICE,
+       .idVendor               = 0x04DD,
+       .idProduct              = 0x8005,       /* A-300 */
+       ZAURUS_MASTER_INTERFACE,
+       .driver_info            = 0,
+}, {
+       .match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+                         | USB_DEVICE_ID_MATCH_DEVICE,
+       .idVendor               = 0x04DD,
+       .idProduct              = 0x8006,       /* B-500/SL-5600 */
+       ZAURUS_MASTER_INTERFACE,
+       .driver_info            = 0,
+}, {
+       .match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+                 | USB_DEVICE_ID_MATCH_DEVICE,
+       .idVendor               = 0x04DD,
+       .idProduct              = 0x8007,       /* C-700 */
+       ZAURUS_MASTER_INTERFACE,
+       .driver_info            = 0,
+}, {
+       .match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+                | USB_DEVICE_ID_MATCH_DEVICE,
+       .idVendor               = 0x04DD,
+       .idProduct              = 0x9031,       /* C-750 C-760 */
+       ZAURUS_MASTER_INTERFACE,
+       .driver_info            = 0,
+}, {
+       .match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+                | USB_DEVICE_ID_MATCH_DEVICE,
+       .idVendor               = 0x04DD,
+       .idProduct              = 0x9032,       /* SL-6000 */
+       ZAURUS_MASTER_INTERFACE,
+       .driver_info            = 0,
+}, {
+       .match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+                | USB_DEVICE_ID_MATCH_DEVICE,
+       .idVendor               = 0x04DD,
+       /* reported with some C860 units */
+       .idProduct              = 0x9050,       /* C-860 */
+       ZAURUS_MASTER_INTERFACE,
+       .driver_info            = 0,
+},
+
+/*
+ * WHITELIST!!!
+ *
+ * CDC Ether uses two interfaces, not necessarily consecutive.
+ * We match the main interface, ignoring the optional device
+ * class so we could handle devices that aren't exclusively
+ * CDC ether.
+ *
+ * NOTE:  this match must come AFTER entries blacklisting devices
+ * because of bugs/quirks in a given product (like Zaurus, above).
+ */
+{
+       USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET,
+                       USB_CDC_PROTO_NONE),
+       .driver_info = (unsigned long) &cdc_info,
+},
+       { },            // END
+};
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver cdc_driver = {
+       .owner =        THIS_MODULE,
+       .name =         "cdc_ether",
+       .id_table =     products,
+       .probe =        usbnet_probe,
+       .disconnect =   usbnet_disconnect,
+       .suspend =      usbnet_suspend,
+       .resume =       usbnet_resume,
+};
+
+
+static int __init cdc_init(void)
+{
+       BUG_ON((sizeof(((struct usbnet *)0)->data)
+                       < sizeof(struct cdc_state)));
+
+       return usb_register(&cdc_driver);
+}
+module_init(cdc_init);
+
+static void __exit cdc_exit(void)
+{
+       usb_deregister(&cdc_driver);
+}
+module_exit(cdc_exit);
+
+MODULE_AUTHOR("David Brownell");
+MODULE_DESCRIPTION("USB CDC Ethernet devices");
+MODULE_LICENSE("GPL");
index 75a05ab0a642788b9c630a4ae11d1a1e74fa182b..7703725327d2560388fbd8b11751268493a33de9 100644 (file)
@@ -300,377 +300,6 @@ void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb)
 }
 EXPORT_SYMBOL_GPL(usbnet_skb_return);
 
-\f
-/*-------------------------------------------------------------------------
- *
- * Communications Device Class declarations.
- * Used by CDC Ethernet, and some CDC variants
- *
- *-------------------------------------------------------------------------*/
-
-#ifdef CONFIG_USB_CDCETHER
-#define NEED_GENERIC_CDC
-#endif
-
-#if defined(CONFIG_USB_ZAURUS) || defined(CONFIG_USB_ZAURUS_MODULE)
-/* 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
-
-#include <linux/usb_cdc.h>
-
-static struct usb_driver usbnet_driver;
-
-/*
- * 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.
- */
-int usbnet_generic_cdc_bind (struct usbnet *dev, struct usb_interface *intf)
-{
-       u8                              *buf = intf->cur_altsetting->extra;
-       int                             len = intf->cur_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;
-
-       /* expect strict spec conformance for the descriptors, but
-        * cope with firmware which stores them in the wrong place
-        */
-       if (len == 0 && dev->udev->actconfig->extralen) {
-               /* Motorola SB4100 (and others: Brad Hards says it's
-                * from a Broadcom design) put CDC descriptors here
-                */
-               buf = dev->udev->actconfig->extra;
-               len = dev->udev->actconfig->extralen;
-               if (len)
-                       dev_dbg (&intf->dev,
-                               "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->cur_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;
-
-               /* 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 USB_CDC_HEADER_TYPE:
-                       if (info->header) {
-                               dev_dbg (&intf->dev, "extra CDC header\n");
-                               goto bad_desc;
-                       }
-                       info->header = (void *) buf;
-                       if (info->header->bLength != sizeof *info->header) {
-                               dev_dbg (&intf->dev, "CDC header len %u\n",
-                                       info->header->bLength);
-                               goto bad_desc;
-                       }
-                       break;
-               case USB_CDC_UNION_TYPE:
-                       if (info->u) {
-                               dev_dbg (&intf->dev, "extra CDC union\n");
-                               goto bad_desc;
-                       }
-                       info->u = (void *) buf;
-                       if (info->u->bLength != sizeof *info->u) {
-                               dev_dbg (&intf->dev, "CDC union len %u\n",
-                                       info->u->bLength);
-                               goto bad_desc;
-                       }
-
-                       /* we need a master/control interface (what we're
-                        * probed with) and a slave/data interface; union
-                        * descriptors sort this all out.
-                        */
-                       info->control = usb_ifnum_to_if(dev->udev,
-                                               info->u->bMasterInterface0);
-                       info->data = usb_ifnum_to_if(dev->udev,
-                                               info->u->bSlaveInterface0);
-                       if (!info->control || !info->data) {
-                               dev_dbg (&intf->dev,
-                                       "master #%u/%p slave #%u/%p\n",
-                                       info->u->bMasterInterface0,
-                                       info->control,
-                                       info->u->bSlaveInterface0,
-                                       info->data);
-                               goto bad_desc;
-                       }
-                       if (info->control != intf) {
-                               dev_dbg (&intf->dev, "bogus CDC Union\n");
-                               /* Ambit USB Cable Modem (and maybe others)
-                                * interchanges master and slave interface.
-                                */
-                               if (info->data == intf) {
-                                       info->data = info->control;
-                                       info->control = intf;
-                               } else
-                                       goto bad_desc;
-                       }
-
-                       /* a data interface altsetting does the real i/o */
-                       d = &info->data->cur_altsetting->desc;
-                       if (d->bInterfaceClass != USB_CLASS_CDC_DATA) {
-                               dev_dbg (&intf->dev, "slave class %u\n",
-                                       d->bInterfaceClass);
-                               goto bad_desc;
-                       }
-                       break;
-               case USB_CDC_ETHERNET_TYPE:
-                       if (info->ether) {
-                               dev_dbg (&intf->dev, "extra CDC ether\n");
-                               goto bad_desc;
-                       }
-                       info->ether = (void *) buf;
-                       if (info->ether->bLength != sizeof *info->ether) {
-                               dev_dbg (&intf->dev, "CDC ether len %u\n",
-                                       info->ether->bLength);
-                               goto bad_desc;
-                       }
-                       dev->hard_mtu = le16_to_cpu(
-                                               info->ether->wMaxSegmentSize);
-                       /* 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 || (!rndis && !info->ether)) {
-               dev_dbg (&intf->dev, "missing cdc %s%s%sdescriptor\n",
-                       info->header ? "" : "header ",
-                       info->u ? "" : "union ",
-                       info->ether ? "" : "ether ");
-               goto bad_desc;
-       }
-
-       /* claim data interface and set it up ... with side effects.
-        * network traffic can't flow until an altsetting is enabled.
-        */
-       status = usb_driver_claim_interface (&usbnet_driver, info->data, dev);
-       if (status < 0)
-               return status;
-       status = usbnet_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;
-       }
-
-       /* status endpoint: optional for CDC Ethernet, not RNDIS (or ACM) */
-       dev->status = NULL;
-       if (info->control->cur_altsetting->desc.bNumEndpoints == 1) {
-               struct usb_endpoint_descriptor  *desc;
-
-               dev->status = &info->control->cur_altsetting->endpoint [0];
-               desc = &dev->status->desc;
-               if (desc->bmAttributes != USB_ENDPOINT_XFER_INT
-                               || !(desc->bEndpointAddress & USB_DIR_IN)
-                               || (le16_to_cpu(desc->wMaxPacketSize)
-                                       < sizeof (struct usb_cdc_notification))
-                               || !desc->bInterval) {
-                       dev_dbg (&intf->dev, "bad notification endpoint\n");
-                       dev->status = NULL;
-               }
-       }
-       if (rndis && !dev->status) {
-               dev_dbg (&intf->dev, "missing RNDIS status endpoint\n");
-               usb_set_intfdata(info->data, NULL);
-               usb_driver_release_interface (&usbnet_driver, info->data);
-               return -ENODEV;
-       }
-       return 0;
-
-bad_desc:
-       dev_info (&dev->udev->dev, "bad CDC descriptors\n");
-       return -ENODEV;
-}
-EXPORT_SYMBOL_GPL(usbnet_generic_cdc_bind);
-
-void usbnet_cdc_unbind (struct usbnet *dev, struct usb_interface *intf)
-{
-       struct cdc_state                *info = (void *) &dev->data;
-
-       /* 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 = NULL;
-       }
-
-       /* 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 = NULL;
-       }
-}
-EXPORT_SYMBOL_GPL(usbnet_cdc_unbind);
-
-#endif /* NEED_GENERIC_CDC */
-
-\f
-#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 void dumpspeed (struct usbnet *dev, __le32 *speeds)
-{
-       if (netif_msg_timer (dev))
-               devinfo (dev, "link speeds: %u kbps up, %u kbps down",
-                       __le32_to_cpu(speeds[0]) / 1000,
-               __le32_to_cpu(speeds[1]) / 1000);
-}
-
-static void cdc_status (struct usbnet *dev, struct urb *urb)
-{
-       struct usb_cdc_notification     *event;
-
-       if (urb->actual_length < sizeof *event)
-               return;
-       
-       /* SPEED_CHANGE can get split into two 8-byte packets */
-       if (test_and_clear_bit (EVENT_STS_SPLIT, &dev->flags)) {
-               dumpspeed (dev, (__le32 *) urb->transfer_buffer);
-               return;
-       }
-
-       event = urb->transfer_buffer;
-       switch (event->bNotificationType) {
-       case USB_CDC_NOTIFY_NETWORK_CONNECTION:
-               if (netif_msg_timer (dev))
-                       devdbg (dev, "CDC: carrier %s",
-                                       event->wValue ? "on" : "off");
-               if (event->wValue)
-                       netif_carrier_on(dev->net);
-               else
-                       netif_carrier_off(dev->net);
-               break;
-       case USB_CDC_NOTIFY_SPEED_CHANGE:       /* tx/rx rates */
-               if (netif_msg_timer (dev))
-                       devdbg (dev, "CDC: speed change (len %d)",
-                                       urb->actual_length);
-               if (urb->actual_length != (sizeof *event + 8))
-                       set_bit (EVENT_STS_SPLIT, &dev->flags);
-               else
-                       dumpspeed (dev, (__le32 *) &event[1]);
-               break;
-       // case USB_CDC_NOTIFY_RESPONSE_AVAILABLE:      /* RNDIS; or unsolicited */
-       default:
-               deverr (dev, "CDC: unexpected notification %02x!",
-                                event->bNotificationType);
-               break;
-       }
-}
-
-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 usb_cdc_ether_desc *e)
-{
-       int             tmp, i;
-       unsigned char   buf [13];
-
-       tmp = usb_string (dev->udev, e->iMACAddress, buf, sizeof buf);
-       if (tmp != 12) {
-               dev_dbg (&dev->udev->dev,
-                       "bad MAC string %d fetch, %d\n", e->iMACAddress, tmp);
-               if (tmp >= 0)
-                       tmp = -EINVAL;
-               return tmp;
-       }
-       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 = usbnet_generic_cdc_bind (dev, intf);
-       if (status < 0)
-               return status;
-
-       status = get_ethernet_addr (dev, info->ether);
-       if (status < 0) {
-               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.
-        */
-       return 0;
-}
-
-static const struct driver_info        cdc_info = {
-       .description =  "CDC Ethernet Device",
-       .flags =        FLAG_ETHER,
-       // .check_connect = cdc_check_connect,
-       .bind =         cdc_bind,
-       .unbind =       usbnet_cdc_unbind,
-       .status =       cdc_status,
-};
-
-#endif /* CONFIG_USB_CDCETHER */
-
-
 \f
 #ifdef CONFIG_USB_PL2301
 #define        HAVE_HARDWARE
@@ -1754,23 +1383,6 @@ static const struct usb_device_id        products [] = {
        .driver_info = (unsigned long) &rndis_info,
 },
 #endif
-
-#ifdef CONFIG_USB_CDCETHER
-{
-       /* CDC Ether uses two interfaces, not necessarily consecutive.
-        * We match the main interface, ignoring the optional device
-        * class so we could handle devices that aren't exclusively
-        * CDC ether.
-        *
-        * NOTE:  this match must come AFTER entries working around
-        * bugs/quirks in a given product (like Zaurus, above).
-        */
-       USB_INTERFACE_INFO (USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET,
-                       USB_CDC_PROTO_NONE),
-       .driver_info = (unsigned long) &cdc_info,
-},
-#endif
-
        { },            // END
 };
 MODULE_DEVICE_TABLE (usb, products);
@@ -1792,10 +1404,6 @@ static int __init usbnet_init(void)
        // compiler should optimize these out
        BUG_ON (sizeof (((struct sk_buff *)0)->cb)
                        < sizeof (struct skb_data));
-#ifdef CONFIG_USB_CDCETHER
-       BUG_ON ((sizeof (((struct usbnet *)0)->data)
-                       < sizeof (struct cdc_state)));
-#endif
 
        random_ether_addr(node_id);