From 0cdb1e5d804602fab307d782456d8c7a18a4e604 Mon Sep 17 00:00:00 2001 From: hwg Date: Wed, 7 May 2014 17:29:10 +0800 Subject: [PATCH] usb ethernet: support dm9601, dm9620 --- arch/arm/configs/rockchip_defconfig | 1 + drivers/net/usb/Kconfig | 8 + drivers/net/usb/Makefile | 1 + drivers/net/usb/axusbnet.c | 1366 --------------------------- drivers/net/usb/axusbnet.h | 208 ---- drivers/net/usb/dm9601.c | 1 + drivers/net/usb/dm9620.c | 742 ++++++++++++--- 7 files changed, 619 insertions(+), 1708 deletions(-) mode change 100644 => 100755 drivers/net/usb/Kconfig mode change 100644 => 100755 drivers/net/usb/Makefile delete mode 100755 drivers/net/usb/axusbnet.c delete mode 100755 drivers/net/usb/axusbnet.h diff --git a/arch/arm/configs/rockchip_defconfig b/arch/arm/configs/rockchip_defconfig index 19b5832913f7..690a64f7dca1 100755 --- a/arch/arm/configs/rockchip_defconfig +++ b/arch/arm/configs/rockchip_defconfig @@ -256,6 +256,7 @@ CONFIG_USB_USBNET=y CONFIG_USB_NET_CDC_EEM=y CONFIG_USB_NET_CDC_MBIM=y CONFIG_USB_NET_DM9601=y +CONFIG_USB_NET_DM9620=y CONFIG_USB_NET_SMSC75XX=y CONFIG_USB_NET_SMSC95XX=y CONFIG_USB_NET_GL620A=y diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig old mode 100644 new mode 100755 index 287cc624b90b..05e003d5c53a --- a/drivers/net/usb/Kconfig +++ b/drivers/net/usb/Kconfig @@ -272,6 +272,14 @@ config USB_NET_DM9601 This option adds support for Davicom DM9601 based USB 1.1 10/100 Ethernet adapters. +config USB_NET_DM9620 + tristate "Davicom DM9620 based USB 2.0 10/100 ethernet devices" + depends on USB_USBNET + select CRC32 + help + This option adds support for Davicom DM9620 based USB 2.0 + 10/100 Ethernet adapters. + config USB_NET_SMSC75XX tristate "SMSC LAN75XX based USB 2.0 gigabit ethernet devices" depends on USB_USBNET diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile old mode 100644 new mode 100755 index 9ab5c9d4b45a..7d95e5cbc274 --- a/drivers/net/usb/Makefile +++ b/drivers/net/usb/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_USB_NET_AX88179_178A) += ax88179_178a.o obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o obj-$(CONFIG_USB_NET_CDC_EEM) += cdc_eem.o obj-$(CONFIG_USB_NET_DM9601) += dm9601.o +obj-$(CONFIG_USB_NET_DM9620) += dm9620.o obj-$(CONFIG_USB_NET_SMSC75XX) += smsc75xx.o obj-$(CONFIG_USB_NET_SMSC95XX) += smsc95xx.o obj-$(CONFIG_USB_NET_GL620A) += gl620a.o diff --git a/drivers/net/usb/axusbnet.c b/drivers/net/usb/axusbnet.c deleted file mode 100755 index 142480724784..000000000000 --- a/drivers/net/usb/axusbnet.c +++ /dev/null @@ -1,1366 +0,0 @@ -/* - * USB Network driver infrastructure - * Copyright (C) 2000-2005 by David Brownell - * Copyright (C) 2003-2005 David Hollis - * - * 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 - */ - -/* - * This is a generic "USB networking" framework that works with several - * kinds of full and high speed networking devices: host-to-host cables, - * smart usb peripherals, and actual Ethernet adapters. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -/*#include */ - -#include "asix.h" -#include "axusbnet.h" - -#define DRIVER_VERSION "22-Aug-2005" -#define TAG "AX88xx------>" - -static void axusbnet_unlink_rx_urbs(struct usbnet *); - -/*-------------------------------------------------------------------------*/ - -/* - * Nineteen USB 1.1 max size bulk transactions per frame (ms), max. - * Several dozen bytes of IPv4 data can fit in two such transactions. - * One maximum size Ethernet packet takes twenty four of them. - * For high speed, each frame comfortably fits almost 36 max size - * Ethernet packets (so queues should be bigger). - * - * REVISIT qlens should be members of 'struct usbnet'; the goal is to - * let the USB host controller be busy for 5msec or more before an irq - * is required, under load. Jumbograms change the equation. - */ -#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) -#define TX_TIMEOUT_JIFFIES (30*HZ) - -// throttle rx/tx briefly after some faults, so khubd might disconnect() -// us (it polls at HZ/4 usually) before we report too many false errors. -#define THROTTLE_JIFFIES (HZ/8) - -// between wakeups -#define UNLINK_TIMEOUT_MS 3 - -/*-------------------------------------------------------------------------*/ - -static const char driver_name [] = "axusbnet"; - -/* use ethtool to change the level for any given device */ -static int msg_level = -1; -module_param (msg_level, int, 0); -MODULE_PARM_DESC (msg_level, "Override default message level"); - -/*-------------------------------------------------------------------------*/ - -/* handles CDC Ethernet and many other network "bulk data" interfaces */ -static -int axusbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf) -{ - int tmp; - struct usb_host_interface *alt = NULL; - struct usb_host_endpoint *in = NULL, *out = NULL; - struct usb_host_endpoint *status = NULL; - - for (tmp = 0; tmp < intf->num_altsetting; tmp++) { - unsigned ep; - - in = out = status = NULL; - alt = intf->altsetting + tmp; - - /* take the first altsetting with in-bulk + out-bulk; - * remember any status endpoint, just in case; - * ignore other endpoints and altsetttings. - */ - for (ep = 0; ep < alt->desc.bNumEndpoints; ep++) { - struct usb_host_endpoint *e; - int intr = 0; - - e = alt->endpoint + ep; - switch (e->desc.bmAttributes) { - case USB_ENDPOINT_XFER_INT: - if (!(e->desc.bEndpointAddress & USB_DIR_IN)) - continue; - intr = 1; - /* FALLTHROUGH */ - case USB_ENDPOINT_XFER_BULK: - break; - default: - continue; - } - if (e->desc.bEndpointAddress & USB_DIR_IN) { - if (!intr && !in) - in = e; - else if (intr && !status) - status = e; - } else { - if (!out) - out = e; - } - } - if (in && out) - break; - } - if (!alt || !in || !out) - return -EINVAL; - - if (alt->desc.bAlternateSetting != 0 - || !(dev->driver_info->flags & FLAG_NO_SETINT)) { - tmp = usb_set_interface (dev->udev, alt->desc.bInterfaceNumber, - alt->desc.bAlternateSetting); - if (tmp < 0) - return tmp; - } - - dev->in = usb_rcvbulkpipe (dev->udev, - in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); - dev->out = usb_sndbulkpipe (dev->udev, - out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); - dev->status = status; - return 0; -} - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) -static void intr_complete (struct urb *urb, struct pt_regs *regs); -#else -static void intr_complete (struct urb *urb); -#endif - -static int init_status (struct usbnet *dev, struct usb_interface *intf) -{ - char *buf = NULL; - unsigned pipe = 0; - unsigned maxp; - unsigned period; - - if (!dev->driver_info->status) - return 0; - - pipe = usb_rcvintpipe (dev->udev, - dev->status->desc.bEndpointAddress - & USB_ENDPOINT_NUMBER_MASK); - maxp = usb_maxpacket (dev->udev, pipe, 0); - - /* avoid 1 msec chatter: min 8 msec poll rate */ - period = max ((int) dev->status->desc.bInterval, - (dev->udev->speed == USB_SPEED_HIGH) ? 7 : 3); - - buf = kmalloc (maxp, GFP_KERNEL); - if (buf) { - dev->interrupt = usb_alloc_urb (0, GFP_KERNEL); - if (!dev->interrupt) { - kfree (buf); - return -ENOMEM; - } else { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) - dev->interrupt->transfer_flags |= URB_ASYNC_UNLINK; -#endif - usb_fill_int_urb(dev->interrupt, dev->udev, pipe, - buf, maxp, intr_complete, dev, period); - devdbg(dev, - "status ep%din, %d bytes period %d", - usb_pipeendpoint(pipe), maxp, period); - } - } - return 0; -} - -/* Passes this packet up the stack, updating its accounting. - * Some link protocols batch packets, so their rx_fixup paths - * can return clones as well as just modify the original skb. - */ -static -void axusbnet_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; - - if (netif_msg_rx_status (dev)) - devdbg (dev, "< rx, len %zu, type 0x%x", - skb->len + sizeof (struct ethhdr), skb->protocol); - memset (skb->cb, 0, sizeof (struct skb_data)); - status = netif_rx (skb); - if (status != NET_RX_SUCCESS && netif_msg_rx_err (dev)) - devdbg (dev, "netif_rx status %d", status); -} - -/*------------------------------------------------------------------------- - * - * Network Device Driver (peer link to "Host Device", from USB host) - * - *-------------------------------------------------------------------------*/ - -static -int axusbnet_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) - 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) - axusbnet_unlink_rx_urbs(dev); - } - - return 0; -} - -static struct net_device_stats *axusbnet_get_stats (struct net_device *net) -{ - struct usbnet *dev = netdev_priv (net); - return &dev->stats; -} - -/*-------------------------------------------------------------------------*/ - -/* some LK 2.4 HCDs oopsed if we freed or resubmitted urbs from - * completion callbacks. 2.5 should have fixed those bugs... - */ - -static void -defer_bh(struct usbnet *dev, struct sk_buff *skb, struct sk_buff_head *list) -{ - unsigned long flags; - - spin_lock_irqsave(&list->lock, flags); - __skb_unlink(skb, list); - spin_unlock(&list->lock); - spin_lock(&dev->done.lock); - __skb_queue_tail(&dev->done, skb); - if (dev->done.qlen == 1) - tasklet_schedule(&dev->bh); - spin_unlock_irqrestore(&dev->done.lock, flags); -} - -/* some work can't be done in tasklets, so we use keventd - * - * NOTE: annoying asymmetry: if it's active, schedule_work() fails, - * but tasklet_schedule() doesn't. hope the failure is rare. - */ -static -void axusbnet_defer_kevent (struct usbnet *dev, int work) -{ - set_bit (work, &dev->flags); - if (!schedule_work (&dev->kevent)) - deverr (dev, "kevent %d may have been dropped", work); - else - devdbg (dev, "kevent %d scheduled", work); -} - -/*-------------------------------------------------------------------------*/ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) -static void rx_complete (struct urb *urb, struct pt_regs *regs); -#else -static void rx_complete (struct urb *urb); -#endif - -static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) -{ - struct sk_buff *skb; - struct skb_data *entry; - int retval = 0; - unsigned long lockflags; - size_t size = dev->rx_urb_size; - struct driver_info *info = dev->driver_info; - u8 align; - -#if (AX_FORCE_BUFF_ALIGN) - align = 0; -#else - if (!(info->flags & FLAG_HW_IP_ALIGNMENT)) - align = NET_IP_ALIGN; - else - align = 0; -#endif - - if ((skb = alloc_skb (size + align, flags)) == NULL) { - if (netif_msg_rx_err (dev)) - devdbg (dev, "no rx skb"); - axusbnet_defer_kevent (dev, EVENT_RX_MEMORY); - usb_free_urb (urb); - return; - } - - if (align) - skb_reserve (skb, NET_IP_ALIGN); - - entry = (struct skb_data *) skb->cb; - entry->urb = urb; - entry->dev = dev; - entry->state = rx_start; - entry->length = 0; - - usb_fill_bulk_urb (urb, dev->udev, dev->in, - skb->data, size, rx_complete, skb); - - spin_lock_irqsave (&dev->rxq.lock, lockflags); - - 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)) { - case -EPIPE: - axusbnet_defer_kevent (dev, EVENT_RX_HALT); - break; - case -ENOMEM: - axusbnet_defer_kevent (dev, EVENT_RX_MEMORY); - break; - case -ENODEV: - if (netif_msg_ifdown (dev)) - devdbg (dev, "device gone"); - netif_device_detach (dev->net); - break; - default: - if (netif_msg_rx_err (dev)) - devdbg (dev, "rx submit, %d", retval); - tasklet_schedule (&dev->bh); - break; - case 0: - __skb_queue_tail (&dev->rxq, skb); - } - } else { - if (netif_msg_ifdown (dev)) - deverr (dev, "rx: stopped"); - retval = -ENOLINK; - } - spin_unlock_irqrestore (&dev->rxq.lock, lockflags); - if (retval) { - dev_kfree_skb_any (skb); - usb_free_urb (urb); - } -} - - -/*-------------------------------------------------------------------------*/ - -static inline void rx_process (struct usbnet *dev, struct sk_buff *skb) -{ - if (dev->driver_info->rx_fixup - && !dev->driver_info->rx_fixup (dev, skb)) - goto error; - // else network stack removes extra byte if we forced a short packet - - if (skb->len) - axusbnet_skb_return (dev, skb); - else { - if (netif_msg_rx_err (dev)) - devdbg (dev, "drop"); -error: - dev->stats.rx_errors++; - skb_queue_tail (&dev->done, skb); - } -} - -/*-------------------------------------------------------------------------*/ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) -static void rx_complete (struct urb *urb, struct pt_regs *regs) -#else -static void rx_complete (struct urb *urb) -#endif -{ - struct sk_buff *skb = (struct sk_buff *) urb->context; - struct skb_data *entry = (struct skb_data *) skb->cb; - struct usbnet *dev = entry->dev; - int urb_status = urb->status; - - skb_put (skb, urb->actual_length); - entry->state = rx_done; - entry->urb = NULL; - - switch (urb_status) { - /* success */ - case 0: - if (skb->len < dev->net->hard_header_len) { - entry->state = rx_cleanup; - dev->stats.rx_errors++; - dev->stats.rx_length_errors++; - if (netif_msg_rx_err (dev)) - ;// deverr (dev, "rx length %d", skb->len); - } - break; - - /* stalls need manual reset. this is rare ... except that - * when going through USB 2.0 TTs, unplug appears this way. - * we avoid the highspeed version of the ETIMEDOUT/EILSEQ - * storm, recovering as needed. - */ - case -EPIPE: - dev->stats.rx_errors++; - axusbnet_defer_kevent (dev, EVENT_RX_HALT); - // FALLTHROUGH - - /* software-driven interface shutdown */ - case -ECONNRESET: /* async unlink */ - case -ESHUTDOWN: /* hardware gone */ - if (netif_msg_ifdown (dev)) - ;// deverr (dev, "rx shutdown, code %d", urb_status); - goto block; - - /* 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: - case -ETIME: - case -EILSEQ: - dev->stats.rx_errors++; - if (!timer_pending (&dev->delay)) { - mod_timer (&dev->delay, jiffies + THROTTLE_JIFFIES); - if (netif_msg_link (dev)) - ;// deverr (dev, "rx throttle %d", urb_status); - } -block: - entry->state = rx_cleanup; - entry->urb = urb; - urb = NULL; - break; - - /* data overrun ... flush fifo? */ - case -EOVERFLOW: - dev->stats.rx_over_errors++; - // FALLTHROUGH - - default: - entry->state = rx_cleanup; - dev->stats.rx_errors++; - if (netif_msg_rx_err (dev)) - ;// deverr (dev, "rx status %d", urb_status); - break; - } - - defer_bh(dev, skb, &dev->rxq); - - if (urb) { - if (netif_running (dev->net) - && !test_bit (EVENT_RX_HALT, &dev->flags)) { - rx_submit (dev, urb, GFP_ATOMIC); - return; - } - usb_free_urb (urb); - } - if (netif_msg_rx_err (dev)) - deverr (dev, "no read resubmitted"); -} -extern void dwc_otg_clear_halt(struct urb *_urb); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) -static void intr_complete (struct urb *urb, struct pt_regs *regs) -#else -static void intr_complete (struct urb *urb) -#endif -{ - struct usbnet *dev = urb->context; - int status = urb->status; - - switch (status) { - /* success */ - case 0: - dev->driver_info->status(dev, urb); - break; - - /* software-driven interface shutdown */ - case -ENOENT: /* urb killed */ - case -ESHUTDOWN: /* hardware gone */ - if (netif_msg_ifdown (dev)) - devdbg (dev, "intr shutdown, code %d", status); - break; - // return; - - /* NOTE: not throttling like RX/TX, since this endpoint - * already polls infrequently - */ - default: - devdbg (dev, "intr status %d", status); - if(status < 0) - dwc_otg_clear_halt(urb); - break; - } - - if (!netif_running (dev->net)) - return; - - memset(urb->transfer_buffer, 0, urb->transfer_buffer_length); - status = usb_submit_urb (urb, GFP_ATOMIC); - if (status != 0 && netif_msg_timer (dev)) - deverr(dev, "intr resubmit --> %d", status); -} - -/*-------------------------------------------------------------------------*/ - -// unlink pending rx/tx; completion handlers do all other cleanup - -static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q) -{ - unsigned long flags; - struct sk_buff *skb, *skbnext; - int count = 0; - - spin_lock_irqsave (&q->lock, flags); - skb_queue_walk_safe(q, skb, skbnext) { - struct skb_data *entry; - struct urb *urb; - int retval; - - entry = (struct skb_data *) skb->cb; - urb = entry->urb; - - // during some PM-driven resume scenarios, - // these (async) unlinks complete immediately - retval = usb_unlink_urb (urb); - if (retval != -EINPROGRESS && retval != 0) - devdbg (dev, "unlink urb err, %d", retval); - else - count++; - } - spin_unlock_irqrestore (&q->lock, flags); - return count; -} - -// Flush all pending rx urbs -// minidrivers may need to do this when the MTU changes - -static -void axusbnet_unlink_rx_urbs(struct usbnet *dev) -{ - if (netif_running(dev->net)) { - (void) unlink_urbs (dev, &dev->rxq); - tasklet_schedule(&dev->bh); - } -} - -/*-------------------------------------------------------------------------*/ - -// precondition: never called in_interrupt - -static -int axusbnet_stop (struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - struct driver_info *info = dev->driver_info; - int temp; - int retval; -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18) - DECLARE_WAIT_QUEUE_HEAD_ONSTACK (unlink_wakeup); -#else - DECLARE_WAIT_QUEUE_HEAD (unlink_wakeup); -#endif - 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_errors, dev->stats.tx_errors - ); - - /* allow minidriver to stop correctly (wireless devices to turn off - * radio etc) */ - if (info->stop) { - retval = info->stop(dev); - if (retval < 0 && netif_msg_ifdown(dev)) - devinfo(dev, - "stop fail (%d) usbnet usb-%s-%s, %s", - retval, - dev->udev->bus->bus_name, dev->udev->devpath, - info->description); - } - - if (!(info->flags & FLAG_AVOID_UNLINK_URBS)) { - /* ensure there are no more active urbs */ - add_wait_queue(&unlink_wakeup, &wait); - dev->wait = &unlink_wakeup; - temp = unlink_urbs(dev, &dev->txq) + - unlink_urbs(dev, &dev->rxq); - - /* maybe wait for deletions to finish. */ - while (!skb_queue_empty(&dev->rxq) - && !skb_queue_empty(&dev->txq) - && !skb_queue_empty(&dev->done)) { - msleep(UNLINK_TIMEOUT_MS); - if (netif_msg_ifdown(dev)) - devdbg(dev, "waited for %d urb completions", - temp); - } - dev->wait = NULL; - remove_wait_queue(&unlink_wakeup, &wait); - } - - usb_kill_urb(dev->interrupt); - - /* deferred work (task, timer, softirq) must also stop. - * can't flush_scheduled_work() until we drop rtnl (later), - * else workers could deadlock; so make workers a NOP. - */ - dev->flags = 0; - del_timer_sync (&dev->delay); - tasklet_kill (&dev->bh); - - return 0; -} - -/*-------------------------------------------------------------------------*/ - -// posts reads, and enables write queuing - -// precondition: never called in_interrupt - -static -int axusbnet_open (struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - int retval = 0; - struct driver_info *info = dev->driver_info; - - // put into "known safe" state - if (info->reset && (retval = info->reset (dev)) < 0) { - if (netif_msg_ifup (dev)) - devinfo (dev, - "open reset fail (%d) usbnet usb-%s-%s, %s", - retval, - dev->udev->bus->bus_name, dev->udev->devpath, - info->description); - goto done; - } - - // insist peer be connected - if (info->check_connect && (retval = info->check_connect (dev)) < 0) { - if (netif_msg_ifup (dev)) - devdbg (dev, "can't open; %d", retval); - goto done; - } - - /* start any status interrupt transfer */ - if (dev->interrupt) { - retval = usb_submit_urb (dev->interrupt, GFP_KERNEL); - if (retval < 0) { - if (netif_msg_ifup (dev)) - deverr (dev, "intr submit %d", retval); - goto done; - } - } - - netif_start_queue (net); - if (netif_msg_ifup (dev)) { - char *framing; - - if (dev->driver_info->flags & FLAG_FRAMING_NC) - framing = "NetChip"; - else if (dev->driver_info->flags & FLAG_FRAMING_GL) - framing = "GeneSys"; - else if (dev->driver_info->flags & FLAG_FRAMING_Z) - framing = "Zaurus"; - else if (dev->driver_info->flags & FLAG_FRAMING_RN) - framing = "RNDIS"; - else if (dev->driver_info->flags & FLAG_FRAMING_AX) - framing = "ASIX"; - else - framing = "simple"; - - devinfo (dev, "open: enable queueing " - "(rx %d, tx %d) mtu %d %s framing", - (int)RX_QLEN (dev), (int)TX_QLEN (dev), dev->net->mtu, - framing); - } - - // delay posting reads until we're fully open - tasklet_schedule (&dev->bh); - return retval; -done: - return retval; -} - -/*-------------------------------------------------------------------------*/ - -/* ethtool methods; minidrivers may need to add some more, but - * they'll probably want to use this base set. - */ - -static -int axusbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd) -{ - struct usbnet *dev = netdev_priv(net); - - if (!dev->mii.mdio_read) - return -EOPNOTSUPP; - - return mii_ethtool_gset(&dev->mii, cmd); -} - -static -int axusbnet_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; - -} - -static -u32 axusbnet_get_link (struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - - /* If a check_connect is defined, return its result */ - 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, dtrt for drivers calling netif_carrier_{on,off} */ - return ethtool_op_get_link(net); -} - -static -int axusbnet_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); -} - -static -void axusbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info) -{ - struct usbnet *dev = netdev_priv(net); - - strncpy (info->driver, dev->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); -} - -static -u32 axusbnet_get_msglevel (struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - - return dev->msg_enable; -} - -static -void axusbnet_set_msglevel (struct net_device *net, u32 level) -{ - struct usbnet *dev = netdev_priv(net); - - dev->msg_enable = level; -} - -/* drivers may override default ethtool_ops in their bind() routine */ -static struct ethtool_ops axusbnet_ethtool_ops = { - .get_settings = axusbnet_get_settings, - .set_settings = axusbnet_set_settings, - .get_link = axusbnet_get_link, - .nway_reset = axusbnet_nway_reset, - .get_drvinfo = axusbnet_get_drvinfo, - .get_msglevel = axusbnet_get_msglevel, - .set_msglevel = axusbnet_set_msglevel, -}; - -/*-------------------------------------------------------------------------*/ - -/* work that cannot be done in interrupt context uses keventd. - * - * NOTE: with 2.5 we could do more of this using completion callbacks, - * especially now that control transfers can be queued. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) -static void kevent (void *data) -{ - struct usbnet *dev = (struct usbnet *)data; -#else -static void kevent (struct work_struct *work) -{ - struct usbnet *dev = - container_of(work, struct usbnet, kevent); -#endif - int status; - - /* usb_clear_halt() needs a thread context */ - if (test_bit (EVENT_TX_HALT, &dev->flags)) { -printk ("EVENT_TX_HALT\n"); - unlink_urbs (dev, &dev->txq); - status = usb_clear_halt (dev->udev, dev->out); - if (status < 0 - && status != -EPIPE - && status != -ESHUTDOWN) { - if (netif_msg_tx_err (dev)) - deverr (dev, "can't clear tx halt, status %d", - status); - } else { - clear_bit (EVENT_TX_HALT, &dev->flags); - if (status != -ESHUTDOWN) - netif_wake_queue (dev->net); - } - } - if (test_bit (EVENT_RX_HALT, &dev->flags)) { -printk ("EVENT_RX_HALT\n"); - unlink_urbs (dev, &dev->rxq); - status = usb_clear_halt (dev->udev, dev->in); - if (status < 0 - && status != -EPIPE - && status != -ESHUTDOWN) { - if (netif_msg_rx_err (dev)) - deverr (dev, "can't clear rx halt, status %d", - status); - } else { - clear_bit (EVENT_RX_HALT, &dev->flags); - tasklet_schedule (&dev->bh); - } - } - - /* tasklet could resubmit itself forever if memory is tight */ - if (test_bit (EVENT_RX_MEMORY, &dev->flags)) { - struct urb *urb = NULL; -printk ("EVENT_RX_MEMORY\n"); - if (netif_running (dev->net)) - urb = usb_alloc_urb (0, GFP_KERNEL); - else - clear_bit (EVENT_RX_MEMORY, &dev->flags); - if (urb != NULL) { - clear_bit (EVENT_RX_MEMORY, &dev->flags); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) - urb->transfer_flags |= URB_ASYNC_UNLINK; -#endif - rx_submit (dev, urb, GFP_KERNEL); - tasklet_schedule (&dev->bh); - } - } - - if (test_bit (EVENT_LINK_RESET, &dev->flags)) { - struct driver_info *info = dev->driver_info; - int retval = 0; - - clear_bit (EVENT_LINK_RESET, &dev->flags); - if(info->link_reset && (retval = info->link_reset(dev)) < 0) { - devinfo(dev, "link reset failed (%d) usbnet usb-%s-%s, %s", - retval, - dev->udev->bus->bus_name, dev->udev->devpath, - info->description); - } - } - - if (dev->flags) - devdbg (dev, "kevent done, flags = 0x%lx", - dev->flags); -} - -/*-------------------------------------------------------------------------*/ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) -static void tx_complete (struct urb *urb, struct pt_regs *regs) -#else -static void tx_complete (struct urb *urb) -#endif -{ - struct sk_buff *skb = (struct sk_buff *) urb->context; - struct skb_data *entry = (struct skb_data *) skb->cb; - struct usbnet *dev = entry->dev; - - if (urb->status == 0) { - dev->stats.tx_packets++; - dev->stats.tx_bytes += entry->length; - } else { - dev->stats.tx_errors++; - - switch (urb->status) { - case -EPIPE: - axusbnet_defer_kevent (dev, EVENT_TX_HALT); - break; - - /* software-driven interface shutdown */ - case -ECONNRESET: // async unlink - case -ESHUTDOWN: // hardware gone - break; - - // like rx, tx gets controller i/o faults during khubd delays - // and so it uses the same throttling mechanism. - case -EPROTO: - case -ETIME: - case -EILSEQ: - if (!timer_pending (&dev->delay)) { - mod_timer (&dev->delay, - jiffies + THROTTLE_JIFFIES); - if (netif_msg_link (dev)) - devdbg (dev, "tx throttle %d", - urb->status); - } - netif_stop_queue (dev->net); - break; - default: - if (netif_msg_tx_err (dev)) - devdbg (dev, "tx err %d", entry->urb->status); - break; - } - } - - urb->dev = NULL; - entry->state = tx_done; - defer_bh(dev, skb, &dev->txq); -} - -/*-------------------------------------------------------------------------*/ - -static -void axusbnet_tx_timeout (struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - - devdbg(dev,"---> %s %d\n",__FUNCTION__, __LINE__); - unlink_urbs (dev, &dev->txq); - tasklet_schedule (&dev->bh); - - // FIXME: device recovery -- reset? -} - -/*-------------------------------------------------------------------------*/ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) -static int -#else -static netdev_tx_t -#endif -axusbnet_start_xmit (struct sk_buff *skb, - struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - int length; - struct urb *urb = NULL; - struct skb_data *entry; - struct driver_info *info = dev->driver_info; - unsigned long flags; - int retval; - - // some devices want funky USB-level framing, for - // win32 driver (usually) and/or hardware quirks - if (info->tx_fixup) { - skb = info->tx_fixup (dev, skb, GFP_ATOMIC); - if (!skb) { - if (netif_msg_tx_err (dev)) - devdbg (dev, "can't tx_fixup skb"); - goto drop; - } - } - length = skb->len; - - if (!(urb = usb_alloc_urb (0, GFP_ATOMIC))) { - if (netif_msg_tx_err (dev)) - devdbg (dev, "no urb"); - goto drop; - } - - entry = (struct skb_data *) skb->cb; - entry->urb = urb; - entry->dev = dev; - entry->state = tx_start; - entry->length = length; - - usb_fill_bulk_urb (urb, dev->udev, dev->out, - skb->data, skb->len, tx_complete, skb); - - /* don't assume the hardware handles USB_ZERO_PACKET - * NOTE: strictly conforming cdc-ether devices should expect - * the ZLP here, but ignore the one-byte packet. - */ - if (!(info->flags & FLAG_SEND_ZLP) && (length % dev->maxpacket) == 0) { - urb->transfer_buffer_length++; - if (skb_tailroom(skb)) { - skb->data[skb->len] = 0; - __skb_put(skb, 1); - } - } - - spin_lock_irqsave (&dev->txq.lock, flags); - - switch ((retval = usb_submit_urb (urb, GFP_ATOMIC))) { - case -EPIPE: - netif_stop_queue (net); - axusbnet_defer_kevent (dev, EVENT_TX_HALT); - break; - default: - if (netif_msg_tx_err (dev)) - devdbg (dev, "tx: submit urb err %d", retval); - break; - case 0: - net->trans_start = jiffies; - __skb_queue_tail (&dev->txq, skb); - if (dev->txq.qlen >= TX_QLEN (dev)) - netif_stop_queue (net); - } - spin_unlock_irqrestore (&dev->txq.lock, flags); - - if (retval) { - if (netif_msg_tx_err (dev)) - devdbg (dev, "drop, code %d", retval); -drop: - dev->stats.tx_dropped++; - if (skb) - dev_kfree_skb_any (skb); - usb_free_urb (urb); - } else if (netif_msg_tx_queued (dev)) { - devdbg (dev, "> tx, len %d, type 0x%x", - length, skb->protocol); - } - return NETDEV_TX_OK; -} - -/*-------------------------------------------------------------------------*/ - -// tasklet (work deferred from completions, in_irq) or timer - -static void axusbnet_bh (unsigned long param) -{ - struct usbnet *dev = (struct usbnet *) param; - struct sk_buff *skb; - struct skb_data *entry; - - while ((skb = skb_dequeue (&dev->done))) { - entry = (struct skb_data *) skb->cb; - switch (entry->state) { - case rx_done: - entry->state = rx_cleanup; - rx_process (dev, skb); - continue; - case tx_done: - case rx_cleanup: - usb_free_urb (entry->urb); - dev_kfree_skb (skb); - continue; - default: - devdbg (dev, "bogus skb state %d", entry->state); - } - } - - // waiting for all pending urbs to complete? - if (dev->wait) { - if ((dev->txq.qlen + dev->rxq.qlen + dev->done.qlen) == 0) { - wake_up (dev->wait); - } - - // or are we maybe short a few urbs? - } else if (netif_running (dev->net) - && netif_device_present (dev->net) - && !timer_pending (&dev->delay) - && !test_bit (EVENT_RX_HALT, &dev->flags)) { - int temp = dev->rxq.qlen; - int qlen = RX_QLEN (dev); - - if (temp < qlen) { - struct urb *urb; - int i; - - // don't refill the queue all at once - for (i = 0; i < 10 && dev->rxq.qlen < qlen; i++) { - urb = usb_alloc_urb (0, GFP_ATOMIC); - if (urb != NULL) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) - urb->transfer_flags |= URB_ASYNC_UNLINK; -#endif - rx_submit (dev, urb, GFP_ATOMIC); - } - } - if (temp != dev->rxq.qlen && netif_msg_link (dev)) - devdbg (dev, "rxqlen %d --> %d", - temp, dev->rxq.qlen); - if (dev->rxq.qlen < qlen) - tasklet_schedule (&dev->bh); - } - if (dev->txq.qlen < TX_QLEN (dev)) - netif_wake_queue (dev->net); - } -} - - -/*------------------------------------------------------------------------- - * - * USB Device Driver support - * - *-------------------------------------------------------------------------*/ - -// precondition: never called in_interrupt - -static -void axusbnet_disconnect (struct usb_interface *intf) -{ - struct usbnet *dev; - struct usb_device *xdev; - struct net_device *net; - - dev = usb_get_intfdata(intf); - usb_set_intfdata(intf, NULL); - if (!dev) - return; - - xdev = interface_to_usbdev (intf); - - if (netif_msg_probe (dev)) - devinfo (dev, "unregister '%s' usb-%s-%s, %s", - intf->dev.driver->name, - xdev->bus->bus_name, xdev->devpath, - dev->driver_info->description); - - net = dev->net; - unregister_netdev (net); - - /* we don't hold rtnl here ... */ - flush_scheduled_work (); - - if (dev->driver_info->unbind) - dev->driver_info->unbind (dev, intf); - - free_netdev(net); - usb_put_dev (xdev); -} - -/*-------------------------------------------------------------------------*/ - -// precondition: never called in_interrupt - -static int -axusbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) -{ - struct usbnet *dev; - struct net_device *net; - struct usb_host_interface *interface; - struct driver_info *info; - struct usb_device *xdev; - int status; - const char *name; - - name = udev->dev.driver->name; - info = (struct driver_info *) prod->driver_info; - if (!info) { - printk (KERN_ERR "blacklisted by %s\n", name); - return -ENODEV; - } - xdev = interface_to_usbdev (udev); - interface = udev->cur_altsetting; - - usb_get_dev (xdev); - - status = -ENOMEM; - - // set up our own records - net = alloc_etherdev(sizeof(*dev)); - if (!net) { - dbg ("can't kmalloc dev"); - goto out; - } - - dev = netdev_priv(net); - dev->udev = xdev; - dev->intf = udev; - dev->driver_info = info; - dev->driver_name = name; - dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV - | NETIF_MSG_PROBE | NETIF_MSG_LINK | NETIF_MSG_IFDOWN |NETIF_MSG_IFUP); - skb_queue_head_init (&dev->rxq); - skb_queue_head_init (&dev->txq); - skb_queue_head_init (&dev->done); - dev->bh.func = axusbnet_bh; - dev->bh.data = (unsigned long) dev; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) - INIT_WORK (&dev->kevent, kevent, dev); -#else - INIT_WORK (&dev->kevent, kevent); -#endif - - dev->delay.function = axusbnet_bh; - dev->delay.data = (unsigned long) dev; - init_timer (&dev->delay); -// mutex_init (&dev->phy_mutex); - - dev->net = net; - - /* rx and tx sides can use different message sizes; - * bind() should set rx_urb_size in that case. - */ - dev->hard_mtu = net->mtu + net->hard_header_len; - -#if 0 -// dma_supported() is deeply broken on almost all architectures - // possible with some EHCI controllers - if (dma_supported (&udev->dev, DMA_BIT_MASK(64))) - net->features |= NETIF_F_HIGHDMA; -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) - net->open = axusbnet_open, - net->stop = axusbnet_stop, - net->hard_start_xmit = axusbnet_start_xmit, - net->tx_timeout = axusbnet_tx_timeout, - net->get_stats = axusbnet_get_stats; -#endif - - net->watchdog_timeo = TX_TIMEOUT_JIFFIES; - net->ethtool_ops = &axusbnet_ethtool_ops; - - info->flags |= FLAG_AVOID_UNLINK_URBS; - - // allow device-specific bind/init procedures - // NOTE net->name still not usable ... - status = info->bind (dev, udev); - if (status < 0) { - deverr(dev, "Binding device failed: %d", status); - goto out1; - } else { - printk("----> %s %d:bind %s\n",__FUNCTION__,__LINE__,info->description); - } - - /* maybe the remote can't receive an Ethernet MTU */ - if (net->mtu > (dev->hard_mtu - net->hard_header_len)) - net->mtu = dev->hard_mtu - net->hard_header_len; - - status = init_status (dev, udev); - if (status < 0) - 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) { - deverr(dev, "net device registration failed: %d", status); - goto out3; - } - - if (netif_msg_probe (dev)) - devinfo (dev, "register '%s' at usb-%s-%s, %s, %pM", - udev->dev.driver->name, - xdev->bus->bus_name, xdev->devpath, - dev->driver_info->description, - net->dev_addr); - - // ok, it's ready to go. - usb_set_intfdata (udev, dev); - - // start as if the link is up - netif_device_attach (net); - - return 0; - -out3: - if (info->unbind) - info->unbind (dev, udev); -out1: - free_netdev(net); -out: - usb_put_dev(xdev); - return status; -} - -/*-------------------------------------------------------------------------*/ - -/* - * suspend the whole driver as soon as the first interface is suspended - * resume only when the last interface is resumed - */ - -static int axusbnet_suspend (struct usb_interface *intf, -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10) -pm_message_t message) -#else -u32 message) -#endif -{ - struct usbnet *dev = usb_get_intfdata(intf); - - if (!dev->suspend_count++) { - /* - * 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); - /* - * reattach so runtime management can use and - * wake the device - */ - netif_device_attach (dev->net); - } - return 0; -} - -static int -axusbnet_resume (struct usb_interface *intf) -{ - struct usbnet *dev = usb_get_intfdata(intf); - - if (!--dev->suspend_count) - tasklet_schedule (&dev->bh); - - return 0; -} - diff --git a/drivers/net/usb/axusbnet.h b/drivers/net/usb/axusbnet.h deleted file mode 100755 index d492de3b80e1..000000000000 --- a/drivers/net/usb/axusbnet.h +++ /dev/null @@ -1,208 +0,0 @@ -/* - * USB Networking Link Interface - * - * Copyright (C) 2000-2005 by David Brownell - * Copyright (C) 2003-2005 David Hollis - * - * 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 - */ - -#ifndef __LINUX_USB_USBNET_H -#define __LINUX_USB_USBNET_H - -#ifndef gfp_t -#define gfp_t int -#endif - -/* interface from usbnet core to each USB networking link we handle */ -struct usbnet { - /* housekeeping */ - struct usb_device *udev; - struct usb_interface *intf; - struct driver_info *driver_info; - const char *driver_name; - void *driver_priv; - wait_queue_head_t *wait; -// struct mutex phy_mutex; - unsigned char suspend_count; - - /* i/o info: pipes etc */ - unsigned in, out; - struct usb_host_endpoint *status; - unsigned maxpacket; - struct timer_list delay; - - /* protocol/interface state */ - struct net_device *net; - struct net_device_stats stats; - int msg_enable; - unsigned long data [5]; - u32 xid; - u32 hard_mtu; /* count any extra framing */ - size_t rx_urb_size; /* size for rx urbs */ - struct mii_if_info mii; - - /* various kinds of pending driver work */ - struct sk_buff_head rxq; - struct sk_buff_head txq; - struct sk_buff_head done; - struct sk_buff_head rxq_pause; - struct urb *interrupt; - struct tasklet_struct bh; - - struct work_struct kevent; - unsigned long flags; -# define EVENT_TX_HALT 0 -# define EVENT_RX_HALT 1 -# define EVENT_RX_MEMORY 2 -# define EVENT_STS_SPLIT 3 -# define EVENT_LINK_RESET 4 -# define EVENT_RX_PAUSED 5 - - void *priv; /* point to minidriver private data */ - unsigned char rx_size; -}; - -static inline struct usb_driver *driver_of(struct usb_interface *intf) -{ - return to_usb_driver(intf->dev.driver); -} - -/* interface from the device/framing level "minidriver" to core */ -struct driver_info { - char *description; - - int flags; -/* framing is CDC Ethernet, not writing ZLPs (hw issues), or optionally: */ -#define FLAG_FRAMING_NC 0x0001 /* guard against device dropouts */ -#define FLAG_FRAMING_GL 0x0002 /* genelink batches packets */ -#define FLAG_FRAMING_Z 0x0004 /* zaurus adds a trailer */ -#define FLAG_FRAMING_RN 0x0008 /* RNDIS batches, plus huge header */ - -#define FLAG_NO_SETINT 0x0010 /* device can't set_interface() */ -#define FLAG_ETHER 0x0020 /* maybe use "eth%d" names */ - -#define FLAG_FRAMING_AX 0x0040 /* AX88772/178 packets */ -#define FLAG_WLAN 0x0080 /* use "wlan%d" names */ -#define FLAG_AVOID_UNLINK_URBS 0x0100 /* don't unlink urbs at usbnet_stop() */ -#define FLAG_SEND_ZLP 0x0200 /* hw requires ZLPs are sent */ -#define FLAG_HW_IP_ALIGNMENT 0x0400 /* AX88772B support hardware IP alignment */ - - - /* init device ... can sleep, or cause probe() failure */ - int (*bind)(struct usbnet *, struct usb_interface *); - - /* cleanup device ... can sleep, but can't fail */ - void (*unbind)(struct usbnet *, struct usb_interface *); - - /* reset device ... can sleep */ - int (*reset)(struct usbnet *); - - /* stop device ... can sleep */ - int (*stop)(struct usbnet *); - - /* see if peer is connected ... can sleep */ - int (*check_connect)(struct usbnet *); - - /* for status polling */ - void (*status)(struct usbnet *, struct urb *); - - /* link reset handling, called from defer_kevent */ - int (*link_reset)(struct usbnet *); - - /* fixup rx packet (strip framing) */ - int (*rx_fixup)(struct usbnet *dev, struct sk_buff *skb); - - /* fixup tx packet (add framing) */ - struct sk_buff *(*tx_fixup)(struct usbnet *dev, - struct sk_buff *skb, gfp_t flags); - - /* early initialization code, can sleep. This is for minidrivers - * having 'subminidrivers' that need to do extra initialization - * right after minidriver have initialized hardware. */ - int (*early_init)(struct usbnet *dev); - - /* called by minidriver when receiving indication */ - void (*indication)(struct usbnet *dev, void *ind, int indlen); - - /* for new devices, use the descriptor-reading code instead */ - int in; /* rx endpoint */ - int out; /* tx endpoint */ - - unsigned long data; /* Misc driver specific data */ -}; - -/* Drivers that reuse some of the standard USB CDC infrastructure - * (notably, using multiple interfaces according to the CDC - * union descriptor) get some helper code. - */ -struct cdc_state { - struct usb_cdc_header_desc *header; - struct usb_cdc_union_desc *u; - struct usb_cdc_ether_desc *ether; - struct usb_interface *control; - struct usb_interface *data; -}; - -/* CDC and RNDIS support the same host-chosen packet filters for IN transfers */ -#define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \ - |USB_CDC_PACKET_TYPE_ALL_MULTICAST \ - |USB_CDC_PACKET_TYPE_PROMISCUOUS \ - |USB_CDC_PACKET_TYPE_DIRECTED) - - -/* we record the state for each of our queued skbs */ -enum skb_state { - illegal = 0, - tx_start, tx_done, - rx_start, rx_done, rx_cleanup -}; - -struct skb_data { /* skb->cb is one of these */ - struct urb *urb; - struct usbnet *dev; - enum skb_state state; - size_t length; -}; - -#ifndef skb_queue_walk_safe -#define skb_queue_walk_safe(queue, skb, tmp) \ - for (skb = (queue)->next, tmp = skb->next; \ - skb != (struct sk_buff *)(queue); \ - skb = tmp, tmp = skb->next) -#endif - -/* messaging support includes the interface name, so it must not be - * used before it has one ... notably, in minidriver bind() calls. - */ -#ifdef DEBUG -#define devdbg(usbnet, fmt, arg...) \ - printk("%s: " fmt "\n" , (usbnet)->net->name , ## arg) -#else -#define devdbg(usbnet, fmt, arg...) \ - ({ if (0) printk("%s: " fmt "\n" , (usbnet)->net->name , \ - ## arg); 0; }) -#endif - -#define deverr(usbnet, fmt, arg...) \ - printk(KERN_ERR "%s: " fmt "\n" , (usbnet)->net->name , ## arg) -#define devwarn(usbnet, fmt, arg...) \ - printk(KERN_WARNING "%s: " fmt "\n" , (usbnet)->net->name , ## arg) - -#define devinfo(usbnet, fmt, arg...) \ - printk(KERN_INFO "%s: " fmt "\n" , (usbnet)->net->name , ## arg); \ - - -#endif /* __LINUX_USB_USBNET_H */ diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c index c0bfc818c701..f3d5e216933d 100644 --- a/drivers/net/usb/dm9601.c +++ b/drivers/net/usb/dm9601.c @@ -370,6 +370,7 @@ static int dm9601_bind(struct usbnet *dev, struct usb_interface *intf) * ethernet frames. */ dev->rx_urb_size = dev->net->mtu + ETH_HLEN + DM_RX_OVERHEAD + 1; + dev->rx_urb_size = (dev->rx_urb_size > 2048) ? dev->rx_urb_size : 2048; dev->mii.dev = dev->net; dev->mii.mdio_read = dm9601_mdio_read; diff --git a/drivers/net/usb/dm9620.c b/drivers/net/usb/dm9620.c index 9df1e01d47d6..699bab627866 100755 --- a/drivers/net/usb/dm9620.c +++ b/drivers/net/usb/dm9620.c @@ -16,16 +16,28 @@ * Support DM9685 * Transmit Check Sum Control by Optopn (Source Code Default: Disable) * Recieve Drop Check Sum Error Packet Disable as chip default - * V1.5 - Support RK2818 (Debug the Register Function) + * V1.5 - Support RK2818 (Debug the Register Function) + * V1.6 - Solve compiler issue for Linux 2.6.35 + * V1.7 - Enable MAC Layer Flow Control and define debug_message for linux version update. + * V1.8 - Enable PHY Layer Flow Control, clear debug code, setup default phy_id value is 1. + * Update dm9620_mdio_read and dm9620_mdio_write. + * Fix bug of ethtool eeprom write + * V1.9 - Fixed "deverr" line 367 error in Linux 2.6.38 + * V2.0 - Fixed "dm9620_set_multicast" function CRC bug. + * V2.1 - Add 802.3az for dm9621a + * V2.2 - Add PID=0x1269 support CDC mode. + * V2.3 - Add PID=0x0269 support CDC mode. + * V2.41 - Support Linux 3.6.9 + * V2.42 - Work to V2.42 according to "DM9620 BulkOut ¸É¤B¤À¸Ñ.doc" + * V2.43 - Special suport for DM9621A in the table 'products' + * V2.45 - Fix the function TxStyle(), correct to be (len%2) from (len%1). 20131211. */ //#define DEBUG - -#define RK2818 +#define LNX_DM9620_VER_STR "V2.45" #include -//#include // new v1.3 #include #include #include @@ -55,6 +67,7 @@ /* registers */ #define DM_NET_CTRL 0x00 #define DM_RX_CTRL 0x05 +#define DM_FLOW_CTRL 0x0a #define DM_SHARED_CTRL 0x0b #define DM_SHARED_ADDR 0x0c #define DM_SHARED_DATA 0x0d /* low + high */ @@ -65,12 +78,14 @@ #define DM_MCAST_ADDR 0x16 /* 8 bytes */ #define DM_GPR_CTRL 0x1e #define DM_GPR_DATA 0x1f +#define DM_PID 0x2a #define DM_XPHY_CTRL 0x2e #define DM_TX_CRC_CTRL 0x31 #define DM_RX_CRC_CTRL 0x32 #define DM_SMIREG 0x91 #define USB_CTRL 0xf4 #define PHY_SPEC_CFG 20 +#define DM_TXRX_M 0x5C #define MD96XX_EEPROM_MAGIC 0x9620 #define DM_MAX_MCAST 64 @@ -82,16 +97,29 @@ #define DM_TIMEOUT 1000 #define DM_MODE9620 0x80 #define DM_TX_CS_EN 0 /* Transmit Check Sum Control */ +#define DM9620_PHY_ID 1 /* Stone add For kernel read phy register */ struct dm96xx_priv { - int flag_fail_count; - u8 mode_9620; + //int flag_fail_count; // EVER RX-DBG + int flg_txdbg; // NOW TX-DBG + u8 mode_9620; + u8 tx_fix_mod; }; - - +#if defined(DEBUG) +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,33) +#define dm9620_print(__dev, format, args...) netdev_dbg((__dev)->net, format, ##args) +#define dm9620_err(__dev, format, args...) netdev_err((__dev)->net, format, ##args) +#else if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,33) +#define dm9620_print(dev, format, args...) devdbg(dev, format, ##args) +#define dm9620_err(dev, format, args...) deverr(dev, format, ##args) +#endif +#else +#define dm9620_print(dev, format, args...) printk(format, ##args) +#define dm9620_err(dev, format, args...) printk(format, ##args) +#endif static int dm_read(struct usbnet *dev, u8 reg, u16 length, void *data) { - devdbg(dev, "dm_read() reg=0x%02x length=%d", reg, length); +// dm9620_print(dev, "dm_read() reg=0x%02x length=%d", reg, length); return usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), DM_READ_REGS, @@ -101,12 +129,6 @@ static int dm_read(struct usbnet *dev, u8 reg, u16 length, void *data) static int dm_read_reg(struct usbnet *dev, u8 reg, u8 *value) { -// return dm_read(dev, reg, 1, value); - - //__le16 w; - //int ret = dm_read(dev, reg, 2, &w); // usb_submit_urb - //*value= (u8)(w & 0xff); - //return ret; u16 *tmpwPtr; int ret; tmpwPtr= kmalloc (2, GFP_ATOMIC); @@ -125,7 +147,7 @@ static int dm_read_reg(struct usbnet *dev, u8 reg, u8 *value) static int dm_write(struct usbnet *dev, u8 reg, u16 length, void *data) { - devdbg(dev, "dm_write() reg=0x%02x, length=%d", reg, length); +// dm9620_print(dev, "dm_write() reg=0x%02x, length=%d", reg, length); return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), DM_WRITE_REGS, @@ -135,7 +157,7 @@ static int dm_write(struct usbnet *dev, u8 reg, u16 length, void *data) static int dm_write_reg(struct usbnet *dev, u8 reg, u8 value) { - devdbg(dev, "dm_write_reg() reg=0x%02x, value=0x%02x", reg, value); +// dm9620_print(dev , "dm_write_reg() reg=0x%02x, value=0x%02x", reg, value); return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), DM_WRITE_REG, @@ -164,13 +186,13 @@ static void dm_write_async_helper(struct usbnet *dev, u8 reg, u8 value, urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) { - deverr(dev, "Error allocating URB in dm_write_async_helper!"); + dm9620_err(dev, "Error allocating URB in dm_write_async_helper!"); return; } req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); if (!req) { - deverr(dev, "Failed to allocate memory for control request"); + dm9620_err(dev, "Failed to allocate memory for control request"); usb_free_urb(urb); return; } @@ -188,8 +210,8 @@ static void dm_write_async_helper(struct usbnet *dev, u8 reg, u8 value, status = usb_submit_urb(urb, GFP_ATOMIC); if (status < 0) { - deverr(dev, "Error submitting the control message: status=%d", - status); + dm9620_err(dev, "Error submitting the control message: status=%d", + status); kfree(req); usb_free_urb(urb); } @@ -197,15 +219,14 @@ static void dm_write_async_helper(struct usbnet *dev, u8 reg, u8 value, static void dm_write_async(struct usbnet *dev, u8 reg, u16 length, void *data) { - devdbg(dev, "dm_write_async() reg=0x%02x length=%d", reg, length); - +// dm9620_print(dev, "dm_write_async() reg=0x%02x length=%d", reg, length); dm_write_async_helper(dev, reg, 0, length, data); } static void dm_write_reg_async(struct usbnet *dev, u8 reg, u8 value) { - devdbg(dev, "dm_write_reg_async() reg=0x%02x value=0x%02x", - reg, value); +// dm9620_print(dev, "dm_write_reg_async() reg=0x%02x value=0x%02x", +// reg, value); dm_write_async_helper(dev, reg, value, 0, NULL); } @@ -213,6 +234,7 @@ static void dm_write_reg_async(struct usbnet *dev, u8 reg, u8 value) static int dm_read_shared_word(struct usbnet *dev, int phy, u8 reg, __le16 *value) { int ret, i; + u16 *tmpwPtr1; mutex_lock(&dev->phy_mutex); @@ -233,16 +255,28 @@ static int dm_read_shared_word(struct usbnet *dev, int phy, u8 reg, __le16 *valu } if (i == DM_TIMEOUT) { - deverr(dev, "%s read timed out!", phy ? "phy" : "eeprom"); + dm9620_err(dev, "%s read timed out!", phy ? "phy" : "eeprom"); ret = -EIO; goto out; } dm_write_reg(dev, DM_SHARED_CTRL, 0x0); - ret = dm_read(dev, DM_SHARED_DATA, 2, value); +// ret = dm_read(dev, DM_SHARED_DATA, 2, value); +//Stone add + tmpwPtr1= kmalloc (2, GFP_ATOMIC); + if (!tmpwPtr1) + { + printk("+++++++++++ JJ5 dm_read_reg() Error: can not kmalloc!\n"); //usbnet_suspend (intf, message); + return 0; + } + + ret = dm_read(dev, DM_SHARED_DATA, 2, tmpwPtr1); // usb_submit_urb v.s. usb_control_msg + *value= (u16)(*tmpwPtr1 & 0xffff); + + kfree (tmpwPtr1); - devdbg(dev, "read shared %d 0x%02x returned 0x%04x, %d", - phy, reg, *value, ret); +// dm9620_print(dev, "read shared %d 0x%02x returned 0x%04x, %d", +// phy, reg, *value, ret); out: mutex_unlock(&dev->phy_mutex); @@ -260,7 +294,6 @@ static int dm_write_shared_word(struct usbnet *dev, int phy, u8 reg, __le16 valu goto out; dm_write_reg(dev, DM_SHARED_ADDR, phy ? (reg | 0x40) : reg); - //dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0x0a : 0x12); if (!phy) dm_write_reg(dev, DM_SHARED_CTRL, 0x10); dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0x0a : 0x12); dm_write_reg(dev, DM_SHARED_CTRL, 0x10); @@ -279,7 +312,7 @@ static int dm_write_shared_word(struct usbnet *dev, int phy, u8 reg, __le16 valu } if (i == DM_TIMEOUT) { - deverr(dev, "%s write timed out!", phy ? "phy" : "eeprom"); + dm9620_err(dev,"%s write timed out!", phy ? "phy" : "eeprom"); ret = -EIO; goto out; } @@ -291,10 +324,11 @@ out: return ret; } + static int dm_write_eeprom_word(struct usbnet *dev, int phy, u8 offset, u8 value) { int ret, i; - u8 reg,dloc; + u8 reg,dloc,tmp_H,tmp_L; __le16 eeword; //devwarn(dev, " offset =0x%x value = 0x%x ", offset,value); @@ -308,16 +342,31 @@ static int dm_write_eeprom_word(struct usbnet *dev, int phy, u8 offset, u8 value /* retrieve high and low byte from the corresponding reg*/ ret=dm_read_shared_word(dev,0,reg,&eeword); //devwarn(dev, " reg =0x%x dloc = 0x%x eeword = 0x%4x", reg,dloc,eeword); - + //printk(" reg =0x%x dloc = 0x%x eeword = 0x%4x\n", reg,dloc,eeword); + + tmp_H = (eeword & 0xff); + tmp_L = (eeword >> 8); + + printk("tmp_L =0x%2x tmp_H =0x%2x eeword = 0x%4x\n", tmp_L,tmp_H,eeword); + /* determine new high and low byte */ + + if (offset & 0x01) { + tmp_L = value; } else { + tmp_H = value; } + + //printk("updated new: tmp_L =0x%2x tmp_H =0x%2x\n", tmp_L,tmp_H); + mutex_lock(&dev->phy_mutex); - /* hank: write data to eeprom high/low byte reg */ - dm_write(dev, (offset & 0x01)? DM_EE_PHY_H:DM_EE_PHY_L, 1, &value); - /* load the unaffected word to value */ - (offset & 0x01)? (value = eeword << 8):(value = eeword >> 8); + + /* hank: write low byte data first to eeprom reg */ + // dm_write(dev, (offset & 0x01)? DM_EE_PHY_H:DM_EE_PHY_L, 1, &value); + dm_write(dev,DM_EE_PHY_L, 1, &tmp_H); + /* high byte will be zero */ + //(offset & 0x01)? (value = eeword << 8):(value = eeword >> 8); /* write the not modified 8 bits back to its origional high/low byte reg */ - dm_write(dev, (offset & 0x01)? DM_EE_PHY_L:DM_EE_PHY_H, 1, &value); + dm_write(dev,DM_EE_PHY_H, 1, &tmp_L); if (ret < 0) goto out; @@ -342,7 +391,7 @@ static int dm_write_eeprom_word(struct usbnet *dev, int phy, u8 offset, u8 value } if (i == DM_TIMEOUT) { - deverr(dev, "%s write timed out!", phy ? "phy" : "eeprom"); + dm9620_err(dev, "%s write timed out!", phy ? "phy" : "eeprom"); ret = -EIO; goto out; } @@ -353,6 +402,7 @@ out: mutex_unlock(&dev->phy_mutex); return ret; } + static int dm_read_eeprom_word(struct usbnet *dev, u8 offset, void *value) { return dm_read_shared_word(dev, 0, offset, value); @@ -363,10 +413,10 @@ static int dm9620_set_eeprom(struct net_device *net,struct ethtool_eeprom *eepro { struct usbnet *dev = netdev_priv(net); - devwarn(dev, "EEPROM: magic value, magic = 0x%x offset =0x%x data = 0x%x ",eeprom->magic, eeprom->offset,*data); + dm9620_print(dev, "EEPROM: magic value, magic = 0x%x offset =0x%x data = 0x%x ",eeprom->magic, eeprom->offset,*data); if (eeprom->magic != MD96XX_EEPROM_MAGIC) { - devwarn(dev, "EEPROM: magic value mismatch, magic = 0x%x", - eeprom->magic); + dm9620_print(dev, "EEPROM: magic value mismatch, magic = 0x%x", + eeprom->magic); return -EINVAL; } @@ -406,17 +456,10 @@ static int dm9620_mdio_read(struct net_device *netdev, int phy_id, int loc) __le16 res; - if (phy_id) { - devdbg(dev, "Only internal phy supported"); - return 0; - } - - dm_read_shared_word(dev, 1, loc, &res); - - devdbg(dev, - "dm9620_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x", - phy_id, loc, le16_to_cpu(res)); + dm_read_shared_word(dev, phy_id, loc, &res); +// dm9620_print(dev, "dm9620_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x", +// phy_id, loc, le16_to_cpu(res)); return le16_to_cpu(res); } @@ -427,15 +470,10 @@ static void dm9620_mdio_write(struct net_device *netdev, int phy_id, int loc, __le16 res = cpu_to_le16(val); int mdio_val; - if (phy_id) { - devdbg(dev, "Only internal phy supported"); - return; - } - - devdbg(dev,"dm9620_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x", - phy_id, loc, val); +// dm9620_print(dev, "dm9620_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x", +// phy_id, loc, val); - dm_write_shared_word(dev, 1, loc, res); + dm_write_shared_word(dev, phy_id, loc, res); mdelay(1); mdio_val = dm9620_mdio_read(netdev, phy_id, loc); @@ -503,7 +541,7 @@ dm9620_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) dm_write_reg(dev, DM_NET_CTRL, 0x48); // enable WAKEEN - dm_write_reg(dev, 0x92, 0x3f); //keep clock on Hank Jun 30 +// dm_write_reg(dev, 0x92, 0x3f); //keep clock on Hank Jun 30 return dm_write_reg(dev, DM_WAKEUP_CTRL, opt); } @@ -525,31 +563,43 @@ static struct ethtool_ops dm9620_ethtool_ops = { static void dm9620_set_multicast(struct net_device *net) { - struct usbnet *dev = netdev_priv(net); - /* We use the 20 byte dev->data for our 8 byte filter buffer - * to avoid allocating memory that is tricky to free later */ - u8 *hashes = (u8 *) & dev->data; - u8 rx_ctl = 0x31; - - memset(hashes, 0x00, DM_MCAST_SIZE); - hashes[DM_MCAST_SIZE - 1] |= 0x80; /* broadcast address */ - - if (net->flags & IFF_PROMISC) { - rx_ctl |= 0x02; - } else if (net->flags & IFF_ALLMULTI || - netdev_mc_count(net) > DM_MAX_MCAST) { - rx_ctl |= 0x04; - } else if (!netdev_mc_empty(net)) { - struct netdev_hw_addr *ha; - - netdev_for_each_mc_addr(ha, net) { - u32 crc = ether_crc(ETH_ALEN, ha->addr) >> 26; - hashes[crc >> 3] |= 1 << (crc & 0x7); - } - } - - dm_write_async(dev, DM_MCAST_ADDR, DM_MCAST_SIZE, hashes); - dm_write_reg_async(dev, DM_RX_CTRL, rx_ctl); + struct usbnet *dev = netdev_priv(net); + /* We use the 20 byte dev->data for our 8 byte filter buffer + * to avoid allocating memory that is tricky to free later */ + u8 *hashes = (u8 *) & dev->data; + u8 rx_ctl = 0x31; + + memset(hashes, 0x00, DM_MCAST_SIZE); + hashes[DM_MCAST_SIZE - 1] |= 0x80; /* broadcast address */ + + if (net->flags & IFF_PROMISC) { + rx_ctl |= 0x02; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,33) + } else if (net->flags & IFF_ALLMULTI || netdev_mc_count(net) > DM_MAX_MCAST) { + rx_ctl |= 0x8; + } else if (!netdev_mc_empty(net)) { + struct netdev_hw_addr *ha; + + netdev_for_each_mc_addr(ha, net) { + u32 crc = crc32_le(~0, ha->addr, ETH_ALEN) & 0x3f; + hashes[crc>>3] |= 1 << (crc & 0x7); + } +#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,33) + } else if (net->flags & IFF_ALLMULTI || net->mc_count > DM_MAX_MCAST) { + rx_ctl |= 0x08; + } else if (net->mc_count) { + struct dev_mc_list *mc_list = net->mc_list; + int i; + + for (i = 0; i < net->mc_count; i++, mc_list = mc_list->next) { + u32 crc = crc32_le(~0, mc_list->dmi_addr, ETH_ALEN) & 0x3f; + hashes[crc>>3] |= 1 << (crc & 0x7); + } +#endif + } + + dm_write_async(dev, DM_MCAST_ADDR, DM_MCAST_SIZE, hashes); + dm_write_reg_async(dev, DM_RX_CTRL, rx_ctl); } @@ -595,13 +645,18 @@ static const struct net_device_ops vm_netdev_ops= { // new kernel 2.6.31 (20091 .ndo_change_mtu = usbnet_change_mtu, .ndo_validate_addr = eth_validate_addr, .ndo_do_ioctl = dm9620_ioctl, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) + .ndo_set_rx_mode = dm9620_set_multicast, +#else .ndo_set_multicast_list = dm9620_set_multicast, +#endif .ndo_set_mac_address = dm9620_set_mac_address, }; #endif static int dm9620_bind(struct usbnet *dev, struct usb_interface *intf) { + u16 *tmpwPtr2; int ret,mdio_val,i; struct dm96xx_priv* priv; u8 temp; @@ -621,18 +676,17 @@ static int dm9620_bind(struct usbnet *dev, struct usb_interface *intf) #endif dev->net->hard_header_len += DM_TX_OVERHEAD; dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len; -#ifdef RK2818 //harris 2010.12.27 - dev->rx_urb_size = dev->net->mtu + ETH_HLEN + DM_RX_OVERHEAD+1; -#else - dev->rx_urb_size = 2048;//dev->net->mtu + ETH_HLEN + DM_RX_OVERHEAD+1; // ftp fail fixed -#endif + dev->rx_urb_size = dev->net->mtu + ETH_HLEN + DM_RX_OVERHEAD+1; // ftp fail fixed + dev->rx_urb_size = (dev->rx_urb_size > 2048) ? dev->rx_urb_size : 2048; dev->mii.dev = dev->net; dev->mii.mdio_read = dm9620_mdio_read; dev->mii.mdio_write = dm9620_mdio_write; dev->mii.phy_id_mask = 0x1f; dev->mii.reg_num_mask = 0x1f; + dev->mii.phy_id = DM9620_PHY_ID; + printk("[dm962] Linux Driver = %s\n", LNX_DM9620_VER_STR); //JJ1 if ( (ret= dm_read_reg(dev, 0x29, &tmp)) >=0) printk("++++++[dm962]+++++ dm_read_reg() 0x29 0x%02x\n",tmp); @@ -669,10 +723,13 @@ static int dm9620_bind(struct usbnet *dev, struct usb_interface *intf) printk("++++++[dm962]+++++ [Analysis.2] 0xF2, D[0] %d %s\n", (tmp>>0)&1, (tmp&(1<<0))? "Status: TX buffer has pkts": "Status: TX buffer 0 pkts" ); /* reset */ - dm_write_reg(dev, DM_XPHY_CTRL, 0); // dm9622/dm9685, bit[5](EXTERNAL), clear-it, add clk & limit to internal PHY dm_write_reg(dev, DM_NET_CTRL, 1); udelay(20); - + //Stone add Enable "MAC layer" Flow Control, TX Pause Packet Enable and + dm_write_reg(dev, DM_FLOW_CTRL, 0x29); + //Stone add Enable "PHY layer" Flow Control support (phy register 0x04 bit 10) + temp = dm9620_mdio_read(dev->net, dev->mii.phy_id, 0x04); + dm9620_mdio_write(dev->net, dev->mii.phy_id, 0x04, temp | 0x400); /* Add V1.1, Enable auto link while plug in RJ45, Hank July 20, 2009*/ @@ -695,19 +752,23 @@ static int dm9620_bind(struct usbnet *dev, struct usb_interface *intf) /* read SMI mode register */ priv = dev->driver_priv = kmalloc(sizeof(struct dm96xx_priv), GFP_ATOMIC); if (!priv) { - deverr(dev, "Failed to allocate memory for dm96xx_priv"); + dm9620_err(dev,"Failed to allocate memory for dm96xx_priv"); ret = -ENOMEM; goto out; } /* work-around for 9620 mode */ + dm_read_reg(dev, 0x5c, &temp); + priv->tx_fix_mod = temp; + printk(KERN_WARNING "[dm96] 9620 tx_fix_mod (DM9_NREV= %d)\n", priv->tx_fix_mod); + printk("[dm96] Fixme: work around for 9620 mode\n"); printk("[dm96] Add tx_fixup() debug...\n"); dm_write_reg(dev, DM_MCAST_ADDR, 0); // clear data bus to 0s dm_read_reg(dev, DM_MCAST_ADDR, &temp); // clear data bus to 0s ret = dm_read_reg(dev, DM_SMIREG, &temp); // Must clear data bus before we can read the 'MODE9620' bit - priv->flag_fail_count= 0; + priv->flg_txdbg= 0; //->flag_fail_count= 0; if (ret<0) { printk(KERN_ERR "[dm96] Error read SMI register\n"); } @@ -715,6 +776,31 @@ static int dm9620_bind(struct usbnet *dev, struct usb_interface *intf) printk(KERN_WARNING "[dm96] 9620 Mode = %d\n", priv->mode_9620); + dm_read_reg(dev, DM_TXRX_M, &temp); // Need to check the Chipset version (register 0x5c is 0x02?) + if (temp == 0x02) + { + dm_read_reg(dev, 0x3f, &temp); + temp |= 0x80; + dm_write_reg(dev, 0x3f, temp); + } + + //Stone add for check Product ID == 0x1269 + tmpwPtr2= kmalloc (2, GFP_ATOMIC); + if (!tmpwPtr2) + { + printk("+++++++++++ JJ5 dm_read_reg() Error: can not kmalloc!\n"); //usbnet_suspend (intf, message); + return 0; + } + ret =dm_read(dev, DM_PID, 2, tmpwPtr2); + + if (*tmpwPtr2 == 0x1269) + dm_write_reg(dev, DM_SMIREG, 0xa0); + + if (*tmpwPtr2 == 0x0269) + dm_write_reg(dev, DM_SMIREG, 0xa0); + + kfree (tmpwPtr2); + /* power up phy */ dm_write_reg(dev, DM_GPR_CTRL, 1); dm_write_reg(dev, DM_GPR_DATA, 0); @@ -732,9 +818,7 @@ static int dm9620_bind(struct usbnet *dev, struct usb_interface *intf) /* Hank add, work for comapubility issue (10M Power control) */ dm9620_mdio_write(dev->net, dev->mii.phy_id, PHY_SPEC_CFG, 0x800); - //printk("[dm96] dm962++ write phy[20]= 0x800\n"); mdio_val = dm9620_mdio_read(dev->net, dev->mii.phy_id, PHY_SPEC_CFG); - //printk("[dm96] dm962++ read phy[20]= %x\n",mdio_val ); dm9620_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); @@ -747,11 +831,10 @@ out: void dm9620_unbind(struct usbnet *dev, struct usb_interface *intf) { struct dm96xx_priv* priv= dev->driver_priv; -//u8 opt=0; -//int i; printk("dm9620_unbind():\n"); - printk("flag_fail_count %lu\n", (long unsigned int)priv->flag_fail_count); + //printk("flag_fail_count %lu\n", (long unsigned int)priv->flag_fail_count); + printk("flg_txdbg %lu\n", (long unsigned int)priv->flg_txdbg); kfree(dev->driver_priv); // displayed dev->.. above, then can free dev #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) @@ -770,9 +853,6 @@ struct dm96xx_priv* priv= dev->driver_priv; printk("rx_missed_errors %lu\n",dev->stats.rx_missed_errors); #endif -// check if dm9620 receive magic packet -//i=dm_read_reg(dev, DM_WAKEUP_CTRL, &opt); -// printk("rx_magic_packet %lu\n",i); } @@ -807,11 +887,10 @@ static int dm9620_rx_fixup(struct usbnet *dev, struct sk_buff *skb) dev_err(&dev->udev->dev, "unexpected tiny rx frame\n"); return 0; } - - //. struct dm96xx_priv* priv= dev->driver_priv; - // if (skb->data[0]!=0x01) - // priv->flag_fail_count++; - + + // if (skb->data[0]!=0x01) + // priv->flag_fail_count++; + status = skb->data[1]; len = (skb->data[2] | (skb->data[3] << 8)) - 4; @@ -864,10 +943,43 @@ static int dm9620_rx_fixup(struct usbnet *dev, struct sk_buff *skb) return 1; } // 'priv' +#define TX_LEN_E (1<<0) //EVEN, No action +#define TX_LEN_O (1<<1) //ODD, Odd to even workaround +#define TX_LEN_F (1<<2) //FULL, Full payload workaround +u8 TxStyle(int len, unsigned full_payload){ + u8 s= (len%2)? TX_LEN_O: TX_LEN_E; + len= ((len+1)/2)*2; + len += 2; + if ((len % full_payload)==0) + s |= TX_LEN_F; + return s; +} +struct sk_buff *TxExpend(struct dm96xx_priv* priv, u8 ts, struct sk_buff *skb, gfp_t flags) +{ + int newheadroom= 2, newtailroom= 0; + if (ts&TX_LEN_O) newtailroom++; + if (ts&TX_LEN_F) newtailroom += 2; + if (skb_headroom(skb) >= newheadroom) newheadroom= 0; // head no need expend + if (skb_tailroom(skb) >= newtailroom) newtailroom= 0; // tail no need expend + if (newheadroom || newtailroom){ + struct sk_buff *skb2; + skb2 = skb_copy_expand(skb, newheadroom, newtailroom, flags); + dev_kfree_skb_any(skb); + skb = skb2; + if (!skb){ + printk("[dm96-TxRound].%d expend copy fail, for head, tail= %d, %d\n", priv->flg_txdbg++, newheadroom, newtailroom); + return NULL; + } + printk("[dm96-TxRound].%d expend copy OK, for head, tail= %d, %d\n", priv->flg_txdbg++, newheadroom, newtailroom); + } + return skb; +} static struct sk_buff *dm9620_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) { int len; + int newheadroom, newtailroom; + struct dm96xx_priv* priv = (struct dm96xx_priv *)dev->driver_priv; /* format: b0: packet length low @@ -877,6 +989,9 @@ static struct sk_buff *dm9620_tx_fixup(struct usbnet *dev, struct sk_buff *skb, len = skb->len; + if (priv->tx_fix_mod<3) + { + /* if (skb_headroom(skb) < DM_TX_OVERHEAD) { struct sk_buff *skb2; skb2 = skb_copy_expand(skb, DM_TX_OVERHEAD, 0, flags); @@ -888,10 +1003,52 @@ static struct sk_buff *dm9620_tx_fixup(struct usbnet *dev, struct sk_buff *skb, __skb_push(skb, DM_TX_OVERHEAD); - /* usbnet adds padding if length is a multiple of packet size - if so, adjust length value in header */ if ((skb->len % dev->maxpacket) == 0) len++; + */ + //;DM9620-E4,E5, and E6 + /* usbnet adds padding 1 byte if odd len */ + /* usbnet adds padding 2 bytes if length is a multiple of packet size + if so, adjust length value in header */ + u8 TS= TxStyle(len, dev->maxpacket); // + if (!(skb= TxExpend(priv, TS, skb, flags))) return NULL; // + + if (TS & TX_LEN_F) len += 2; + + newheadroom= 2; //2 + newtailroom= 0; //0, 1, 2, or 3 + if (TS & TX_LEN_O) newtailroom++; + if (TS & TX_LEN_F) newtailroom += 2; + + if (TS & TX_LEN_O) printk("[dm96-TxRound].%d for LEN_ODD tail_room +1, rslt add %d\n", priv->flg_txdbg, newtailroom); + if (TS & TX_LEN_F) printk("[dm96-TxRound].%d for LEN_PLOAD tail_room +2, rslt add %d\n", priv->flg_txdbg, newtailroom); + if (TS & TX_LEN_F) printk("[dm96-TxRound].%d for LEN_PLOAD data_len +2, len from %d to %d\n", priv->flg_txdbg, len-2, len); + if (TS & (TX_LEN_O|TX_LEN_F)) priv->flg_txdbg++; + + __skb_push(skb, newheadroom); //2 bytes,for data[0],data[1] + __skb_put(skb, newtailroom); //0, 1, 2, or 3 bytes (for tailer), + //Note: 0, NOTHING + //Note: 1, Odd to even WORKAROUND. + //Note: 2 or 3, the condition is full payload, + // This is the add more two bytes WORKAROUND + // for bulkout and buffLen. + } + else + { + //;DM9620-E7 + if (skb_headroom(skb) < DM_TX_OVERHEAD) { + struct sk_buff *skb2; + skb2 = skb_copy_expand(skb, DM_TX_OVERHEAD, 0, flags); + dev_kfree_skb_any(skb); + skb = skb2; + if (!skb) + return NULL; + } + + newheadroom= 2; //2 + __skb_push(skb, newheadroom); //2 bytes, for data[0],data[1] + } + skb->data[0] = len; skb->data[1] = len >> 8; @@ -931,7 +1088,7 @@ static void dm9620_status(struct usbnet *dev, struct urb *urb) } else netif_carrier_off(dev->net); - devdbg(dev, "Link Status is: %d", link); + dm9620_print(dev, "Link Status is: %d", link); } } @@ -942,8 +1099,8 @@ static int dm9620_link_reset(struct usbnet *dev) mii_ethtool_gset(&dev->mii, &ecmd); /* hank add*/ dm9620_mdio_write(dev->net, dev->mii.phy_id, PHY_SPEC_CFG, 0x800); - devdbg(dev, "link_reset() speed: %d duplex: %d", - ecmd.speed, ecmd.duplex); + dm9620_print(dev, "link_reset() speed: %d duplex: %d", + ecmd.speed, ecmd.duplex); return 0; } @@ -955,12 +1112,8 @@ static const struct driver_info dm9620_info = { .rx_fixup = dm9620_rx_fixup, .tx_fixup = dm9620_tx_fixup, .status = dm9620_status, -#ifdef RK2818 //harris 2010.12.27 - -#else .link_reset = dm9620_link_reset, .reset = dm9620_link_reset, -#endif .unbind = dm9620_unbind, }; @@ -989,29 +1142,350 @@ static const struct usb_device_id products[] = { USB_DEVICE(0x0a47, 0x9601), /* Hirose USB-100 */ .driver_info = (unsigned long)&dm9620_info, }, - { - USB_DEVICE(0x0a46, 0x9620), /* Davicom 9620 */ - .driver_info = (unsigned long)&dm9620_info, - }, - { - USB_DEVICE(0x0a46, 0x9621), /* Davicom 9621 */ - .driver_info = (unsigned long)&dm9620_info, - }, - { - USB_DEVICE(0x0a46, 0x9622), /* Davicom 9622 */ - .driver_info = (unsigned long)&dm9620_info, - }, - { - USB_DEVICE(0x0fe6, 0x8101), /* Davicom 9601 USB to Fast Ethernet Adapter */ - .driver_info = (unsigned long)&dm9620_info, - }, + { + USB_DEVICE(0x0a46, 0x9620), /* Davicom 9620 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0a46, 0x9621), /* Davicom 9621 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0a46, 0x9622), /* Davicom 9622 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0fe6, 0x8101), /* Davicom 9601 USB to Fast Ethernet Adapter */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0a46, 0x1269), /* Davicom 9621A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0a46, 0x0269), /* Davicom 9620A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + //+ + //VID.00 + //0.0000 0000 0000 + { + USB_DEVICE(0x0000, 0x9620), /* Davicom 9620 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0000, 0x0269), /* Davicom 9620A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0000, 0x9621), /* Davicom 9621 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0000, 0x1269), /* Davicom 9621A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + //1.0000 0000 0010 + //2.0000 0000 0100 + //3.0000 0000 0110 + //4.0000 0100 0000 + //5.0000 0100 0010 + //6.0000 0100 0100 + //7.0000 0100 0110 + { + USB_DEVICE(0x0002, 0x9621), /* Davicom 9621 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0002, 0x1269), /* Davicom 9621A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0004, 0x9621), /* Davicom 9621 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0004, 0x1269), /* Davicom 9621A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0006, 0x9621), /* Davicom 9621 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0006, 0x1269), /* Davicom 9621A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0040, 0x9621), /* Davicom 9621 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0040, 0x1269), /* Davicom 9621A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0042, 0x9621), /* Davicom 9621 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0042, 0x1269), /* Davicom 9621A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0044, 0x9621), /* Davicom 9621 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0044, 0x1269), /* Davicom 9621A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + //7.0000 0100 0110 (0A46) + { + USB_DEVICE(0x0046, 0x9621), /* Davicom 9621 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0046, 0x1269), /* Davicom 9621A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + // .. + + //8.0010 0000 0000 + //9.0010 0000 0010 + //A.0010 0000 0100 + //B.0010 0000 0110 + //C.0010 0100 0000 + //D.0010 0100 0010 + //E.0010 0100 0100 + //F.0010 0100 0110 + { + USB_DEVICE(0x0200, 0x9621), /* Davicom 9621 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0200, 0x1269), /* Davicom 9621A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0202, 0x9621), /* Davicom 9621 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0202, 0x1269), /* Davicom 9621A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0204, 0x9621), /* Davicom 9621 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0204, 0x1269), /* Davicom 9621A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0206, 0x9621), /* Davicom 9621 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0206, 0x1269), /* Davicom 9621A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0240, 0x9621), /* Davicom 9621 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0240, 0x1269), /* Davicom 9621A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0242, 0x9621), /* Davicom 9621 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0242, 0x1269), /* Davicom 9621A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0244, 0x9621), /* Davicom 9621 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0244, 0x1269), /* Davicom 9621A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + //F.0010 0100 0110 (0A46) + { + USB_DEVICE(0x0246, 0x9621), /* Davicom 9621 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0246, 0x1269), /* Davicom 9621A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + // .. + + //10.1000 0000 0000 + //11.1000 0000 0010 + //12.1000 0000 0100 + //13.1000 0000 0110 + //14.1000 0100 0000 + //15.1000 0100 0010 + //16.1000 0100 0100 + //17.1000 0100 0110 + { + USB_DEVICE(0x0800, 0x9621), /* Davicom 9621 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0800, 0x1269), /* Davicom 9621A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0802, 0x9621), /* Davicom 9621 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0802, 0x1269), /* Davicom 9621A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0804, 0x9621), /* Davicom 9621 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0804, 0x1269), /* Davicom 9621A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0806, 0x9621), /* Davicom 9621 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0806, 0x1269), /* Davicom 9621A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0840, 0x9621), /* Davicom 9621 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0840, 0x1269), /* Davicom 9621A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0842, 0x9621), /* Davicom 9621 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0842, 0x1269), /* Davicom 9621A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0844, 0x9621), /* Davicom 9621 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0844, 0x1269), /* Davicom 9621A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + //17.1010 0100 0110 (0A46) + { + USB_DEVICE(0x0846, 0x9621), /* Davicom 9621 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0846, 0x1269), /* Davicom 9621A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + // .. + + //18.1010 0000 0000 + //19.1010 0000 0010 + //1A.1010 0000 0100 + //1B.1010 0000 0110 + //1C.1010 0100 0000 + //1D.1010 0100 0010 + //1E.1010 0100 0100 + { + USB_DEVICE(0x0A00, 0x9621), /* Davicom 9621 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0A00, 0x1269), /* Davicom 9621A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0A02, 0x9621), /* Davicom 9621 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0A02, 0x1269), /* Davicom 9621A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0A04, 0x9621), /* Davicom 9621 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0A04, 0x1269), /* Davicom 9621A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0A06, 0x9621), /* Davicom 9621 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0A06, 0x1269), /* Davicom 9621A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0A40, 0x9621), /* Davicom 9621 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0A40, 0x1269), /* Davicom 9621A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0A42, 0x9621), /* Davicom 9621 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0A42, 0x1269), /* Davicom 9621A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0A44, 0x9621), /* Davicom 9621 */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0A44, 0x1269), /* Davicom 9621A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + //1F.1010 0100 0110 (0A46) + // .Original Default. + //+ + //1268, 1200 + { + USB_DEVICE(0x0000, 0x1268), /* Davicom 9621A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0000, 0x1200), /* Davicom 9620A CDC */ + .driver_info = (unsigned long)&dm9620_info, + }, + { + USB_DEVICE(0x0000, 0x1220), /* Davicom 9620A CDC, 1220 test mode */ + .driver_info = (unsigned long)&dm9620_info, + }, {}, // END }; MODULE_DEVICE_TABLE(usb, products); static struct usb_driver dm9620_driver = { -// .name = "dm9601", .name = "dm9620", .id_table = products, .probe = usbnet_probe, -- 2.34.1