USB: Davicom DM9601 usbnet driver
[safe/jmp/linux-2.6] / drivers / usb / net / usbnet.c
index 75a05ab..de69b18 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * USB Networking Links
+ * USB Network driver infrastructure
  * Copyright (C) 2000-2005 by David Brownell
  * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com>
  *
 
 /*
  * This is a generic "USB networking" framework that works with several
- * kinds of full and high speed networking devices:
+ * kinds of full and high speed networking devices:  host-to-host cables,
+ * smart usb peripherals, and actual Ethernet adapters.
  *
- *   + USB host-to-host "network cables", used for IP-over-USB links.
- *     These are often used for Laplink style connectivity products.
- *     - AnchorChip 2720
- *     - Belkin, eTEK (interops with Win32 drivers)
- *     - GeneSys GL620USB-A
- *     - NetChip 1080 (interoperates with NetChip Win32 drivers)
- *     - Prolific PL-2301/2302 (replaces "plusb" driver)
- *     - KC Technology KC2190
- *
- *   + Smart USB devices can support such links directly, using Internet
- *     standard protocols instead of proprietary host-to-device links.
- *     - Linux PDAs like iPaq, Yopy, and Zaurus
- *     - The BLOB boot loader (for diskless booting)
- *     - Linux "gadgets", perhaps using PXA-2xx or Net2280 controllers
- *     - Devices using EPSON's sample USB firmware
- *     - CDC-Ethernet class devices, such as many cable modems
- *
- *   + Adapters to networks such as Ethernet.
- *     - AX8817X based USB 2.0 products
- *
- * Links to these devices can be bridged using Linux Ethernet bridging.
- * With minor exceptions, these all use similar USB framing for network
- * traffic, but need different protocols for control traffic.
- *
- * USB devices can implement their side of this protocol at the cost
- * of two bulk endpoints; it's not restricted to "cable" applications.
- * See the SA1110, Zaurus, or EPSON device/client support in this driver;
- * slave/target drivers such as "usb-eth" (on most SA-1100 PDAs) or
- * "g_ether" (in the Linux "gadget" framework) implement that behavior
- * within devices.
- *
- *
- * CHANGELOG:
- *
- * 13-sep-2000 experimental, new
- * 10-oct-2000 usb_device_id table created. 
- * 28-oct-2000 misc fixes; mostly, discard more TTL-mangled rx packets.
- * 01-nov-2000 usb_device_id table and probing api update by
- *             Adam J. Richter <adam@yggdrasil.com>.
- * 18-dec-2000 (db) tx watchdog, "net1080" renaming to "usbnet", device_info
- *             and prolific support, isolate net1080-specific bits, cleanup.
- *             fix unlink_urbs oops in D3 PM resume code path.
- *
- * 02-feb-2001 (db) fix tx skb sharing, packet length, match_flags, ...
- * 08-feb-2001 stubbed in "linuxdev", maybe the SA-1100 folk can use it;
- *             AnchorChips 2720 support (from spec) for testing;
- *             fix bit-ordering problem with ethernet multicast addr
- * 19-feb-2001  Support for clearing halt conditions. SA1100 UDC support
- *             updates. Oleg Drokin (green@iXcelerator.com)
- * 25-mar-2001 More SA-1100 updates, including workaround for ip problem
- *             expecting cleared skb->cb and framing change to match latest
- *             handhelds.org version (Oleg).  Enable device IDs from the
- *             Win32 Belkin driver; other cleanups (db).
- * 16-jul-2001 Bugfixes for uhci oops-on-unplug, Belkin support, various
- *             cleanups for problems not yet seen in the field. (db)
- * 17-oct-2001 Handle "Advance USBNET" product, like Belkin/eTEK devices,
- *             from Ioannis Mavroukakis <i.mavroukakis@btinternet.com>;
- *             rx unlinks somehow weren't async; minor cleanup.
- * 03-nov-2001 Merged GeneSys driver; original code from Jiun-Jie Huang
- *             <huangjj@genesyslogic.com.tw>, updated by Stanislav Brabec
- *             <utx@penguin.cz>.  Made framing options (NetChip/GeneSys)
- *             tie mostly to (sub)driver info.  Workaround some PL-2302
- *             chips that seem to reject SET_INTERFACE requests.
- *
- * 06-apr-2002 Added ethtool support, based on a patch from Brad Hards.
- *             Level of diagnostics is more configurable; they use device
- *             location (usb_device->devpath) instead of address (2.5).
- *             For tx_fixup, memflags can't be NOIO.
- * 07-may-2002 Generalize/cleanup keventd support, handling rx stalls (mostly
- *             for USB 2.0 TTs) and memory shortages (potential) too. (db)
- *             Use "locally assigned" IEEE802 address space. (Brad Hards)
- * 18-oct-2002 Support for Zaurus (Pavel Machek), related cleanup (db).
- * 14-dec-2002 Remove Zaurus-private crc32 code (Pavel); 2.5 oops fix,
- *             cleanups and stubbed PXA-250 support (db), fix for framing
- *             issues on Z, net1080, and gl620a (Toby Milne)
- *
- * 31-mar-2003 Use endpoint descriptors:  high speed support, simpler sa1100
- *             vs pxa25x, and CDC Ethernet.  Throttle down log floods on
- *             disconnect; other cleanups. (db)  Flush net1080 fifos
- *             after several sequential framing errors. (Johannes Erdfelt)
- * 22-aug-2003 AX8817X support (Dave Hollis).
- * 14-jun-2004  Trivial patch for AX8817X based Buffalo LUA-U2-KTX in Japan
- *             (Neil Bortnak)
- * 03-nov-2004 Trivial patch for KC2190 (KC-190) chip. (Jonathan McDowell)
- *
- * 01-feb-2005 AX88772 support (Phil Chang & Dave Hollis)
- *-------------------------------------------------------------------------*/
+ * These devices usually differ in terms of control protocols (if they
+ * even have one!) and sometimes they define new framing to wrap or batch
+ * Ethernet packets.  Otherwise, they talk to USB pretty much the same,
+ * so interface (un)binding, endpoint I/O queues, fault handling, and other
+ * issues can usefully be addressed by this framework.
+ */
 
 // #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>
  * let the USB host controller be busy for 5msec or more before an irq
  * is required, under load.  Jumbograms change the equation.
  */
-#define        RX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? 60 : 4)
-#define        TX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? 60 : 4)
+#define RX_MAX_QUEUE_MEMORY (60 * 1518)
+#define        RX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? \
+                       (RX_MAX_QUEUE_MEMORY/(dev)->rx_urb_size) : 4)
+#define        TX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? \
+                       (RX_MAX_QUEUE_MEMORY/(dev)->hard_mtu) : 4)
 
 // reawaken network queue this soon after stopping; else watchdog barks
 #define TX_TIMEOUT_JIFFIES     (5*HZ)
@@ -197,7 +115,7 @@ int usbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf)
                        e = alt->endpoint + ep;
                        switch (e->desc.bmAttributes) {
                        case USB_ENDPOINT_XFER_INT:
-                               if (!(e->desc.bEndpointAddress & USB_DIR_IN))
+                               if (!usb_endpoint_dir_in(&e->desc))
                                        continue;
                                intr = 1;
                                /* FALLTHROUGH */
@@ -206,7 +124,7 @@ int usbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf)
                        default:
                                continue;
                        }
-                       if (e->desc.bEndpointAddress & USB_DIR_IN) {
+                       if (usb_endpoint_dir_in(&e->desc)) {
                                if (!intr && !in)
                                        in = e;
                                else if (intr && !status)
@@ -229,7 +147,7 @@ int usbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf)
                if (tmp < 0)
                        return tmp;
        }
-       
+
        dev->in = usb_rcvbulkpipe (dev->udev,
                        in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
        dev->out = usb_sndbulkpipe (dev->udev,
@@ -239,7 +157,7 @@ int usbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf)
 }
 EXPORT_SYMBOL_GPL(usbnet_get_endpoints);
 
-static void intr_complete (struct urb *urb, struct pt_regs *regs);
+static void intr_complete (struct urb *urb);
 
 static int init_status (struct usbnet *dev, struct usb_interface *intf)
 {
@@ -260,9 +178,9 @@ static int init_status (struct usbnet *dev, struct usb_interface *intf)
        period = max ((int) dev->status->desc.bInterval,
                (dev->udev->speed == USB_SPEED_HIGH) ? 7 : 3);
 
-       buf = kmalloc (maxp, SLAB_KERNEL);
+       buf = kmalloc (maxp, GFP_KERNEL);
        if (buf) {
-               dev->interrupt = usb_alloc_urb (0, SLAB_KERNEL);
+               dev->interrupt = usb_alloc_urb (0, GFP_KERNEL);
                if (!dev->interrupt) {
                        kfree (buf);
                        return -ENOMEM;
@@ -303,448 +221,6 @@ 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
-
-/*-------------------------------------------------------------------------
- *
- * Prolific PL-2301/PL-2302 driver ... http://www.prolifictech.com
- *
- * The protocol and handshaking used here should be bug-compatible
- * with the Linux 2.2 "plusb" driver, by Deti Fliegl.
- *
- *-------------------------------------------------------------------------*/
-
-/*
- * Bits 0-4 can be used for software handshaking; they're set from
- * one end, cleared from the other, "read" with the interrupt byte.
- */
-#define        PL_S_EN         (1<<7)          /* (feature only) suspend enable */
-/* reserved bit -- rx ready (6) ? */
-#define        PL_TX_READY     (1<<5)          /* (interrupt only) transmit ready */
-#define        PL_RESET_OUT    (1<<4)          /* reset output pipe */
-#define        PL_RESET_IN     (1<<3)          /* reset input pipe */
-#define        PL_TX_C         (1<<2)          /* transmission complete */
-#define        PL_TX_REQ       (1<<1)          /* transmission received */
-#define        PL_PEER_E       (1<<0)          /* peer exists */
-
-static inline int
-pl_vendor_req (struct usbnet *dev, u8 req, u8 val, u8 index)
-{
-       return usb_control_msg (dev->udev,
-               usb_rcvctrlpipe (dev->udev, 0),
-               req,
-               USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-               val, index,
-               NULL, 0,
-               USB_CTRL_GET_TIMEOUT);
-}
-
-static inline int
-pl_clear_QuickLink_features (struct usbnet *dev, int val)
-{
-       return pl_vendor_req (dev, 1, (u8) val, 0);
-}
-
-static inline int
-pl_set_QuickLink_features (struct usbnet *dev, int val)
-{
-       return pl_vendor_req (dev, 3, (u8) val, 0);
-}
-
-/*-------------------------------------------------------------------------*/
-
-static int pl_reset (struct usbnet *dev)
-{
-       /* some units seem to need this reset, others reject it utterly.
-        * FIXME be more like "naplink" or windows drivers.
-        */
-       (void) pl_set_QuickLink_features (dev,
-               PL_S_EN|PL_RESET_OUT|PL_RESET_IN|PL_PEER_E);
-       return 0;
-}
-
-static const struct driver_info        prolific_info = {
-       .description =  "Prolific PL-2301/PL-2302",
-       .flags =        FLAG_NO_SETINT,
-               /* some PL-2302 versions seem to fail usb_set_interface() */
-       .reset =        pl_reset,
-};
-
-#endif /* CONFIG_USB_PL2301 */
-
-\f
-/*-------------------------------------------------------------------------
- *
  * Network Device Driver (peer link to "Host Device", from USB host)
  *
  *-------------------------------------------------------------------------*/
@@ -753,13 +229,23 @@ static int usbnet_change_mtu (struct net_device *net, int new_mtu)
 {
        struct usbnet   *dev = netdev_priv(net);
        int             ll_mtu = new_mtu + net->hard_header_len;
+       int             old_hard_mtu = dev->hard_mtu;
+       int             old_rx_urb_size = dev->rx_urb_size;
 
-       if (new_mtu <= 0 || ll_mtu > dev->hard_mtu)
+       if (new_mtu <= 0)
                return -EINVAL;
        // no second zero-length packet read wanted after mtu-sized packets
        if ((ll_mtu % dev->maxpacket) == 0)
                return -EDOM;
        net->mtu = new_mtu;
+
+       dev->hard_mtu = net->mtu + net->hard_header_len;
+       if (dev->rx_urb_size == old_hard_mtu) {
+               dev->rx_urb_size = dev->hard_mtu;
+               if (dev->rx_urb_size > old_rx_urb_size)
+                       usbnet_unlink_rx_urbs(dev);
+       }
+
        return 0;
 }
 
@@ -808,9 +294,9 @@ EXPORT_SYMBOL_GPL(usbnet_defer_kevent);
 
 /*-------------------------------------------------------------------------*/
 
-static void rx_complete (struct urb *urb, struct pt_regs *regs);
+static void rx_complete (struct urb *urb);
 
-static void rx_submit (struct usbnet *dev, struct urb *urb, unsigned flags)
+static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags)
 {
        struct sk_buff          *skb;
        struct skb_data         *entry;
@@ -841,7 +327,7 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, unsigned flags)
        if (netif_running (dev->net)
                        && netif_device_present (dev->net)
                        && !test_bit (EVENT_RX_HALT, &dev->flags)) {
-               switch (retval = usb_submit_urb (urb, GFP_ATOMIC)){ 
+               switch (retval = usb_submit_urb (urb, GFP_ATOMIC)){
                case -EPIPE:
                        usbnet_defer_kevent (dev, EVENT_RX_HALT);
                        break;
@@ -896,7 +382,7 @@ error:
 
 /*-------------------------------------------------------------------------*/
 
-static void rx_complete (struct urb *urb, struct pt_regs *regs)
+static void rx_complete (struct urb *urb)
 {
        struct sk_buff          *skb = (struct sk_buff *) urb->context;
        struct skb_data         *entry = (struct skb_data *) skb->cb;
@@ -938,9 +424,9 @@ static void rx_complete (struct urb *urb, struct pt_regs *regs)
            // we get controller i/o faults during khubd disconnect() delays.
            // throttle down resubmits, to avoid log floods; just temporarily,
            // so we still recover when the fault isn't a khubd delay.
-           case -EPROTO:               // ehci
-           case -ETIMEDOUT:            // ohci
-           case -EILSEQ:               // uhci
+           case -EPROTO:
+           case -ETIME:
+           case -EILSEQ:
                dev->stats.rx_errors++;
                if (!timer_pending (&dev->delay)) {
                        mod_timer (&dev->delay, jiffies + THROTTLE_JIFFIES);
@@ -957,7 +443,7 @@ block:
            case -EOVERFLOW:
                dev->stats.rx_over_errors++;
                // FALLTHROUGH
-           
+
            default:
                entry->state = rx_cleanup;
                dev->stats.rx_errors++;
@@ -980,7 +466,7 @@ block:
                devdbg (dev, "no read resubmitted");
 }
 
-static void intr_complete (struct urb *urb, struct pt_regs *regs)
+static void intr_complete (struct urb *urb)
 {
        struct usbnet   *dev = urb->context;
        int             status = urb->status;
@@ -1047,6 +533,17 @@ static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q)
        return count;
 }
 
+// Flush all pending rx urbs
+// minidrivers may need to do this when the MTU changes
+
+void usbnet_unlink_rx_urbs(struct usbnet *dev)
+{
+       if (netif_running(dev->net)) {
+               (void) unlink_urbs (dev, &dev->rxq);
+               tasklet_schedule(&dev->bh);
+       }
+}
+EXPORT_SYMBOL_GPL(usbnet_unlink_rx_urbs);
 
 /*-------------------------------------------------------------------------*/
 
@@ -1056,14 +553,14 @@ static int usbnet_stop (struct net_device *net)
 {
        struct usbnet           *dev = netdev_priv(net);
        int                     temp;
-       DECLARE_WAIT_QUEUE_HEAD (unlink_wakeup); 
+       DECLARE_WAIT_QUEUE_HEAD_ONSTACK (unlink_wakeup);
        DECLARE_WAITQUEUE (wait, current);
 
        netif_stop_queue (net);
 
        if (netif_msg_ifdown (dev))
                devinfo (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld",
-                       dev->stats.rx_packets, dev->stats.tx_packets, 
+                       dev->stats.rx_packets, dev->stats.tx_packets,
                        dev->stats.rx_errors, dev->stats.tx_errors
                        );
 
@@ -1081,7 +578,7 @@ static int usbnet_stop (struct net_device *net)
                        devdbg (dev, "waited for %d urb completions", temp);
        }
        dev->wait = NULL;
-       remove_wait_queue (&unlink_wakeup, &wait); 
+       remove_wait_queue (&unlink_wakeup, &wait);
 
        usb_kill_urb(dev->interrupt);
 
@@ -1155,7 +652,7 @@ static int usbnet_open (struct net_device *net)
 
                devinfo (dev, "open: enable queueing "
                                "(rx %d, tx %d) mtu %d %s framing",
-                       RX_QLEN (dev), TX_QLEN (dev), dev->net->mtu,
+                       (int)RX_QLEN (dev), (int)TX_QLEN (dev), dev->net->mtu,
                        framing);
        }
 
@@ -1171,20 +668,40 @@ done:
  * they'll probably want to use this base set.
  */
 
-void usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info)
+#if defined(CONFIG_MII) || defined(CONFIG_MII_MODULE)
+#define HAVE_MII
+
+int usbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd)
 {
        struct usbnet *dev = netdev_priv(net);
 
-       /* REVISIT don't always return "usbnet" */
-       strncpy (info->driver, driver_name, sizeof info->driver);
-       strncpy (info->version, DRIVER_VERSION, sizeof info->version);
-       strncpy (info->fw_version, dev->driver_info->description,
-               sizeof info->fw_version);
-       usb_make_path (dev->udev, info->bus_info, sizeof info->bus_info);
+       if (!dev->mii.mdio_read)
+               return -EOPNOTSUPP;
+
+       return mii_ethtool_gset(&dev->mii, cmd);
 }
-EXPORT_SYMBOL_GPL(usbnet_get_drvinfo);
+EXPORT_SYMBOL_GPL(usbnet_get_settings);
 
-static u32 usbnet_get_link (struct net_device *net)
+int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd)
+{
+       struct usbnet *dev = netdev_priv(net);
+       int retval;
+
+       if (!dev->mii.mdio_write)
+               return -EOPNOTSUPP;
+
+       retval = mii_ethtool_sset(&dev->mii, cmd);
+
+       /* link speed/duplex might have changed */
+       if (dev->driver_info->link_reset)
+               dev->driver_info->link_reset(dev);
+
+       return retval;
+
+}
+EXPORT_SYMBOL_GPL(usbnet_set_settings);
+
+u32 usbnet_get_link (struct net_device *net)
 {
        struct usbnet *dev = netdev_priv(net);
 
@@ -1192,9 +709,40 @@ static u32 usbnet_get_link (struct net_device *net)
        if (dev->driver_info->check_connect)
                return dev->driver_info->check_connect (dev) == 0;
 
+       /* if the device has mii operations, use those */
+       if (dev->mii.mdio_read)
+               return mii_link_ok(&dev->mii);
+
        /* Otherwise, say we're up (to avoid breaking scripts) */
        return 1;
 }
+EXPORT_SYMBOL_GPL(usbnet_get_link);
+
+int usbnet_nway_reset(struct net_device *net)
+{
+       struct usbnet *dev = netdev_priv(net);
+
+       if (!dev->mii.mdio_write)
+               return -EOPNOTSUPP;
+
+       return mii_nway_restart(&dev->mii);
+}
+EXPORT_SYMBOL_GPL(usbnet_nway_reset);
+
+#endif /* HAVE_MII */
+
+void usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info)
+{
+       struct usbnet *dev = netdev_priv(net);
+
+       /* REVISIT don't always return "usbnet" */
+       strncpy (info->driver, driver_name, sizeof info->driver);
+       strncpy (info->version, DRIVER_VERSION, sizeof info->version);
+       strncpy (info->fw_version, dev->driver_info->description,
+               sizeof info->fw_version);
+       usb_make_path (dev->udev, info->bus_info, sizeof info->bus_info);
+}
+EXPORT_SYMBOL_GPL(usbnet_get_drvinfo);
 
 u32 usbnet_get_msglevel (struct net_device *net)
 {
@@ -1214,8 +762,13 @@ EXPORT_SYMBOL_GPL(usbnet_set_msglevel);
 
 /* drivers may override default ethtool_ops in their bind() routine */
 static struct ethtool_ops usbnet_ethtool_ops = {
-       .get_drvinfo            = usbnet_get_drvinfo,
+#ifdef HAVE_MII
+       .get_settings           = usbnet_get_settings,
+       .set_settings           = usbnet_set_settings,
        .get_link               = usbnet_get_link,
+       .nway_reset             = usbnet_nway_reset,
+#endif
+       .get_drvinfo            = usbnet_get_drvinfo,
        .get_msglevel           = usbnet_get_msglevel,
        .set_msglevel           = usbnet_set_msglevel,
 };
@@ -1228,9 +781,10 @@ static struct ethtool_ops usbnet_ethtool_ops = {
  * especially now that control transfers can be queued.
  */
 static void
-kevent (void *data)
+kevent (struct work_struct *work)
 {
-       struct usbnet           *dev = data;
+       struct usbnet           *dev =
+               container_of(work, struct usbnet, kevent);
        int                     status;
 
        /* usb_clear_halt() needs a thread context */
@@ -1280,7 +834,7 @@ kevent (void *data)
        }
 
        if (test_bit (EVENT_LINK_RESET, &dev->flags)) {
-               struct driver_info      *info = dev->driver_info;
+               struct driver_info      *info = dev->driver_info;
                int                     retval = 0;
 
                clear_bit (EVENT_LINK_RESET, &dev->flags);
@@ -1299,7 +853,7 @@ kevent (void *data)
 
 /*-------------------------------------------------------------------------*/
 
-static void tx_complete (struct urb *urb, struct pt_regs *regs)
+static void tx_complete (struct urb *urb)
 {
        struct sk_buff          *skb = (struct sk_buff *) urb->context;
        struct skb_data         *entry = (struct skb_data *) skb->cb;
@@ -1323,9 +877,9 @@ static void tx_complete (struct urb *urb, struct pt_regs *regs)
 
                // like rx, tx gets controller i/o faults during khubd delays
                // and so it uses the same throttling mechanism.
-               case -EPROTO:           // ehci
-               case -ETIMEDOUT:        // ohci
-               case -EILSEQ:           // uhci
+               case -EPROTO:
+               case -ETIME:
+               case -EILSEQ:
                        if (!timer_pending (&dev->delay)) {
                                mod_timer (&dev->delay,
                                        jiffies + THROTTLE_JIFFIES);
@@ -1512,7 +1066,7 @@ static void usbnet_bh (unsigned long param)
  * USB Device Driver support
  *
  *-------------------------------------------------------------------------*/
+
 // precondition: never called in_interrupt
 
 void usbnet_disconnect (struct usb_interface *intf)
@@ -1533,7 +1087,7 @@ void usbnet_disconnect (struct usb_interface *intf)
                        intf->dev.driver->name,
                        xdev->bus->bus_name, xdev->devpath,
                        dev->driver_info->description);
-       
+
        net = dev->net;
        unregister_netdev (net);
 
@@ -1557,7 +1111,7 @@ int
 usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
 {
        struct usbnet                   *dev;
-       struct net_device               *net;
+       struct net_device               *net;
        struct usb_host_interface       *interface;
        struct driver_info              *info;
        struct usb_device               *xdev;
@@ -1592,10 +1146,11 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
        skb_queue_head_init (&dev->done);
        dev->bh.func = usbnet_bh;
        dev->bh.data = (unsigned long) dev;
-       INIT_WORK (&dev->kevent, kevent, dev);
+       INIT_WORK (&dev->kevent, kevent);
        dev->delay.function = usbnet_bh;
        dev->delay.data = (unsigned long) dev;
        init_timer (&dev->delay);
+       mutex_init (&dev->phy_mutex);
 
        SET_MODULE_OWNER (net);
        dev->net = net;
@@ -1626,6 +1181,9 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
        // NOTE net->name still not usable ...
        if (info->bind) {
                status = info->bind (dev, udev);
+               if (status < 0)
+                       goto out1;
+
                // heuristic:  "usb%d" for links we know are two-host,
                // else "eth%d" when there's reasonable doubt.  userspace
                // can rename the link if it knows better.
@@ -1652,12 +1210,12 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
        if (status == 0 && dev->status)
                status = init_status (dev, udev);
        if (status < 0)
-               goto out1;
+               goto out3;
 
        if (!dev->rx_urb_size)
                dev->rx_urb_size = dev->hard_mtu;
        dev->maxpacket = usb_maxpacket (dev->udev, dev->out, 1);
-       
+
        SET_NETDEV_DEV(net, &udev->dev);
        status = register_netdev (net);
        if (status)
@@ -1700,14 +1258,13 @@ EXPORT_SYMBOL_GPL(usbnet_probe);
 int usbnet_suspend (struct usb_interface *intf, pm_message_t message)
 {
        struct usbnet           *dev = usb_get_intfdata(intf);
-       
+
        /* accelerate emptying of the rx and queues, to avoid
         * having everything error out.
         */
        netif_device_detach (dev->net);
        (void) unlink_urbs (dev, &dev->rxq);
        (void) unlink_urbs (dev, &dev->txq);
-       intf->dev.power.power_state = PMSG_SUSPEND;
        return 0;
 }
 EXPORT_SYMBOL_GPL(usbnet_suspend);
@@ -1716,7 +1273,6 @@ int usbnet_resume (struct usb_interface *intf)
 {
        struct usbnet           *dev = usb_get_intfdata(intf);
 
-       intf->dev.power.power_state = PMSG_ON;
        netif_device_attach (dev->net);
        tasklet_schedule (&dev->bh);
        return 0;
@@ -1726,89 +1282,22 @@ EXPORT_SYMBOL_GPL(usbnet_resume);
 
 /*-------------------------------------------------------------------------*/
 
-#ifndef        HAVE_HARDWARE
-#error You need to configure some hardware for this driver
-#endif
-
-/*
- * chip vendor names won't normally be on the cables, and
- * may not be on the device.
- */
-
-static const struct usb_device_id      products [] = {
-
-#ifdef CONFIG_USB_PL2301
-{
-       USB_DEVICE (0x067b, 0x0000),    // PL-2301
-       .driver_info =  (unsigned long) &prolific_info,
-}, {
-       USB_DEVICE (0x067b, 0x0001),    // PL-2302
-       .driver_info =  (unsigned long) &prolific_info,
-},
-#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_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);
-
-static struct usb_driver usbnet_driver = {
-       .owner =        THIS_MODULE,
-       .name =         driver_name,
-       .id_table =     products,
-       .probe =        usbnet_probe,
-       .disconnect =   usbnet_disconnect,
-       .suspend =      usbnet_suspend,
-       .resume =       usbnet_resume,
-};
-
-/*-------------------------------------------------------------------------*/
-
 static int __init usbnet_init(void)
 {
-       // compiler should optimize these out
-       BUG_ON (sizeof (((struct sk_buff *)0)->cb)
+       /* compiler should optimize this out */
+       BUILD_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);
-
-       return usb_register(&usbnet_driver);
+       return 0;
 }
 module_init(usbnet_init);
 
 static void __exit usbnet_exit(void)
 {
-       usb_deregister(&usbnet_driver);
 }
 module_exit(usbnet_exit);
 
 MODULE_AUTHOR("David Brownell");
-MODULE_DESCRIPTION("USB Host-to-Host Link Drivers (numerous vendors)");
+MODULE_DESCRIPTION("USB network driver framework");
 MODULE_LICENSE("GPL");