diff options
Diffstat (limited to 'drivers/usb/net/usbnet.c')
-rw-r--r-- | drivers/usb/net/usbnet.c | 3226 |
1 files changed, 105 insertions, 3121 deletions
diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index a2f67245f6d..6c460918d54 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -1,10 +1,7 @@ /* - * USB Networking Links - * Copyright (C) 2000-2005 by David Brownell <dbrownell@users.sourceforge.net> - * Copyright (C) 2002 Pavel Machek <pavel@ucw.cz> + * USB Network driver infrastructure + * Copyright (C) 2000-2005 by David Brownell * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com> - * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net> - * Copyright (c) 2002-2003 TiVo Inc. * * 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 @@ -23,95 +20,15 @@ /* * This is a generic "USB networking" framework that works with several - * kinds of full and high speed networking devices: - * - * + 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) - *-------------------------------------------------------------------------*/ + * 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 @@ -121,24 +38,18 @@ # define DEBUG #endif #include <linux/module.h> -#include <linux/kmod.h> #include <linux/sched.h> #include <linux/init.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> -#include <linux/random.h> #include <linux/ethtool.h> #include <linux/workqueue.h> #include <linux/mii.h> -#include <asm/uaccess.h> -#include <asm/unaligned.h> #include <linux/usb.h> -#include <asm/io.h> -#include <asm/scatterlist.h> -#include <linux/mm.h> -#include <linux/dma-mapping.h> -#define DRIVER_VERSION "03-Nov-2004" +#include "usbnet.h" + +#define DRIVER_VERSION "22-Aug-2005" /*-------------------------------------------------------------------------*/ @@ -149,15 +60,14 @@ * 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_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? 60 : 4) #define TX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? 60 : 4) -// packets are always ethernet inside -// ... except they can be bigger (limit of 64K with NetChip framing) -#define MIN_PACKET sizeof(struct ethhdr) -#define MAX_PACKET 32768 - // reawaken network queue this soon after stopping; else watchdog barks #define TX_TIMEOUT_JIFFIES (5*HZ) @@ -165,9 +75,6 @@ // us (it polls at HZ/4 usually) before we report too many false errors. #define THROTTLE_JIFFIES (HZ/8) -// for vendor-specific control operations -#define CONTROL_TIMEOUT_MS 500 - // between wakeups #define UNLINK_TIMEOUT_MS 3 @@ -176,109 +83,6 @@ // randomly generated ethernet address static u8 node_id [ETH_ALEN]; -// state we keep for each device we handle -struct usbnet { - // housekeeping - struct usb_device *udev; - struct driver_info *driver_info; - wait_queue_head_t *wait; - - // 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]; - - 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 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 -}; - -// device-specific info used by the driver -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 */ - - /* 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 *); - - /* 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, int flags); - - // FIXME -- also an interrupt mechanism - // useful for at least PL2301/2302 and GL620USB-A - // and CDC use them to report 'is it connected' changes - - /* for new devices, use the descriptor-reading code instead */ - int in; /* rx endpoint */ - int out; /* tx endpoint */ - - unsigned long data; /* Misc driver specific data */ -}; - -// 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; -}; - static const char driver_name [] = "usbnet"; /* use ethtool to change the level for any given device */ @@ -286,39 +90,10 @@ static int msg_level = -1; module_param (msg_level, int, 0); MODULE_PARM_DESC (msg_level, "Override default message level"); - -#ifdef DEBUG -#define devdbg(usbnet, fmt, arg...) \ - printk(KERN_DEBUG "%s: " fmt "\n" , (usbnet)->net->name , ## arg) -#else -#define devdbg(usbnet, fmt, arg...) do {} while(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); \ - /*-------------------------------------------------------------------------*/ -static void usbnet_get_drvinfo (struct net_device *, struct ethtool_drvinfo *); -static u32 usbnet_get_link (struct net_device *); -static u32 usbnet_get_msglevel (struct net_device *); -static void usbnet_set_msglevel (struct net_device *, u32); -static void defer_kevent (struct usbnet *, int); - -/* mostly for PDA style devices, which are always connected if present */ -static int always_connected (struct usbnet *dev) -{ - return 0; -} - /* handles CDC Ethernet and many other network "bulk data" interfaces */ -static int -get_endpoints (struct usbnet *dev, struct usb_interface *intf) +int usbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf) { int tmp; struct usb_host_interface *alt = NULL; @@ -382,6 +157,7 @@ get_endpoints (struct usbnet *dev, struct usb_interface *intf) dev->status = status; return 0; } +EXPORT_SYMBOL_GPL(usbnet_get_endpoints); static void intr_complete (struct urb *urb, struct pt_regs *regs); @@ -421,7 +197,11 @@ static int init_status (struct usbnet *dev, struct usb_interface *intf) return 0; } -static void skb_return (struct usbnet *dev, struct sk_buff *skb) +/* 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. + */ +void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb) { int status; @@ -438,2425 +218,7 @@ static void skb_return (struct usbnet *dev, struct sk_buff *skb) if (status != NET_RX_SUCCESS && netif_msg_rx_err (dev)) devdbg (dev, "netif_rx status %d", status); } - - -#ifdef CONFIG_USB_ALI_M5632 -#define HAVE_HARDWARE - -/*------------------------------------------------------------------------- - * - * ALi M5632 driver ... does high speed - * - *-------------------------------------------------------------------------*/ - -static const struct driver_info ali_m5632_info = { - .description = "ALi M5632", -}; - - -#endif - - -#ifdef CONFIG_USB_AN2720 -#define HAVE_HARDWARE - -/*------------------------------------------------------------------------- - * - * AnchorChips 2720 driver ... http://www.cypress.com - * - * This doesn't seem to have a way to detect whether the peer is - * connected, or need any reset handshaking. It's got pretty big - * internal buffers (handles most of a frame's worth of data). - * Chip data sheets don't describe any vendor control messages. - * - *-------------------------------------------------------------------------*/ - -static const struct driver_info an2720_info = { - .description = "AnchorChips/Cypress 2720", - // no reset available! - // no check_connect available! - - .in = 2, .out = 2, // direction distinguishes these -}; - -#endif /* CONFIG_USB_AN2720 */ - - -#ifdef CONFIG_USB_AX8817X -/* ASIX AX8817X based USB 2.0 Ethernet Devices */ - -#define HAVE_HARDWARE -#define NEED_MII - -#include <linux/crc32.h> - -#define AX_CMD_SET_SW_MII 0x06 -#define AX_CMD_READ_MII_REG 0x07 -#define AX_CMD_WRITE_MII_REG 0x08 -#define AX_CMD_SET_HW_MII 0x0a -#define AX_CMD_READ_EEPROM 0x0b -#define AX_CMD_WRITE_EEPROM 0x0c -#define AX_CMD_WRITE_ENABLE 0x0d -#define AX_CMD_WRITE_DISABLE 0x0e -#define AX_CMD_WRITE_RX_CTL 0x10 -#define AX_CMD_READ_IPG012 0x11 -#define AX_CMD_WRITE_IPG0 0x12 -#define AX_CMD_WRITE_IPG1 0x13 -#define AX_CMD_WRITE_IPG2 0x14 -#define AX_CMD_WRITE_MULTI_FILTER 0x16 -#define AX_CMD_READ_NODE_ID 0x17 -#define AX_CMD_READ_PHY_ID 0x19 -#define AX_CMD_READ_MEDIUM_STATUS 0x1a -#define AX_CMD_WRITE_MEDIUM_MODE 0x1b -#define AX_CMD_READ_MONITOR_MODE 0x1c -#define AX_CMD_WRITE_MONITOR_MODE 0x1d -#define AX_CMD_WRITE_GPIOS 0x1f -#define AX_CMD_SW_RESET 0x20 -#define AX_CMD_SW_PHY_STATUS 0x21 -#define AX_CMD_SW_PHY_SELECT 0x22 -#define AX88772_CMD_READ_NODE_ID 0x13 - -#define AX_MONITOR_MODE 0x01 -#define AX_MONITOR_LINK 0x02 -#define AX_MONITOR_MAGIC 0x04 -#define AX_MONITOR_HSFS 0x10 - -/* AX88172 Medium Status Register values */ -#define AX_MEDIUM_FULL_DUPLEX 0x02 -#define AX_MEDIUM_TX_ABORT_ALLOW 0x04 -#define AX_MEDIUM_FLOW_CONTROL_EN 0x10 - -#define AX_MCAST_FILTER_SIZE 8 -#define AX_MAX_MCAST 64 - -#define AX_EEPROM_LEN 0x40 - -#define AX_SWRESET_CLEAR 0x00 -#define AX_SWRESET_RR 0x01 -#define AX_SWRESET_RT 0x02 -#define AX_SWRESET_PRTE 0x04 -#define AX_SWRESET_PRL 0x08 -#define AX_SWRESET_BZ 0x10 -#define AX_SWRESET_IPRL 0x20 -#define AX_SWRESET_IPPD 0x40 - -#define AX88772_IPG0_DEFAULT 0x15 -#define AX88772_IPG1_DEFAULT 0x0c -#define AX88772_IPG2_DEFAULT 0x12 - -#define AX88772_MEDIUM_FULL_DUPLEX 0x0002 -#define AX88772_MEDIUM_RESERVED 0x0004 -#define AX88772_MEDIUM_RX_FC_ENABLE 0x0010 -#define AX88772_MEDIUM_TX_FC_ENABLE 0x0020 -#define AX88772_MEDIUM_PAUSE_FORMAT 0x0080 -#define AX88772_MEDIUM_RX_ENABLE 0x0100 -#define AX88772_MEDIUM_100MB 0x0200 -#define AX88772_MEDIUM_DEFAULT \ - (AX88772_MEDIUM_FULL_DUPLEX | AX88772_MEDIUM_RX_FC_ENABLE | \ - AX88772_MEDIUM_TX_FC_ENABLE | AX88772_MEDIUM_100MB | \ - AX88772_MEDIUM_RESERVED | AX88772_MEDIUM_RX_ENABLE ) - -#define AX_EEPROM_MAGIC 0xdeadbeef - -/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ -struct ax8817x_data { - u8 multi_filter[AX_MCAST_FILTER_SIZE]; -}; - -struct ax88172_int_data { - u16 res1; - u8 link; - u16 res2; - u8 status; - u16 res3; -} __attribute__ ((packed)); - -static int ax8817x_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, - u16 size, void *data) -{ - return usb_control_msg( - dev->udev, - usb_rcvctrlpipe(dev->udev, 0), - cmd, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, - index, - data, - size, - CONTROL_TIMEOUT_MS); -} - -static int ax8817x_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, - u16 size, void *data) -{ - return usb_control_msg( - dev->udev, - usb_sndctrlpipe(dev->udev, 0), - cmd, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, - index, - data, - size, - CONTROL_TIMEOUT_MS); -} - -static void ax8817x_async_cmd_callback(struct urb *urb, struct pt_regs *regs) -{ - struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; - - if (urb->status < 0) - printk(KERN_DEBUG "ax8817x_async_cmd_callback() failed with %d", - urb->status); - - kfree(req); - usb_free_urb(urb); -} - -static void ax8817x_status(struct usbnet *dev, struct urb *urb) -{ - struct ax88172_int_data *event; - int link; - - if (urb->actual_length < 8) - return; - - event = urb->transfer_buffer; - link = event->link & 0x01; - if (netif_carrier_ok(dev->net) != link) { - if (link) { - netif_carrier_on(dev->net); - defer_kevent (dev, EVENT_LINK_RESET ); - } else - netif_carrier_off(dev->net); - devdbg(dev, "ax8817x - Link Status is: %d", link); - } -} - -static void ax8817x_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, - u16 size, void *data) -{ - struct usb_ctrlrequest *req; - int status; - struct urb *urb; - - if ((urb = usb_alloc_urb(0, GFP_ATOMIC)) == NULL) { - devdbg(dev, "Error allocating URB in write_cmd_async!"); - return; - } - - if ((req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC)) == NULL) { - deverr(dev, "Failed to allocate memory for control request"); - usb_free_urb(urb); - return; - } - - req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; - req->bRequest = cmd; - req->wValue = cpu_to_le16(value); - req->wIndex = cpu_to_le16(index); - req->wLength = cpu_to_le16(size); - - usb_fill_control_urb(urb, dev->udev, - usb_sndctrlpipe(dev->udev, 0), - (void *)req, data, size, - ax8817x_async_cmd_callback, req); - - if((status = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { - deverr(dev, "Error submitting the control message: status=%d", status); - kfree(req); - usb_free_urb(urb); - } -} - -static void ax8817x_set_multicast(struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; - u8 rx_ctl = 0x8c; - - if (net->flags & IFF_PROMISC) { - rx_ctl |= 0x01; - } else if (net->flags & IFF_ALLMULTI - || net->mc_count > AX_MAX_MCAST) { - rx_ctl |= 0x02; - } else if (net->mc_count == 0) { - /* just broadcast and directed */ - } else { - /* We use the 20 byte dev->data - * for our 8 byte filter buffer - * to avoid allocating memory that - * is tricky to free later */ - struct dev_mc_list *mc_list = net->mc_list; - u32 crc_bits; - int i; - - memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); - - /* Build the multicast hash filter. */ - for (i = 0; i < net->mc_count; i++) { - crc_bits = - ether_crc(ETH_ALEN, - mc_list->dmi_addr) >> 26; - data->multi_filter[crc_bits >> 3] |= - 1 << (crc_bits & 7); - mc_list = mc_list->next; - } - - ax8817x_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, - AX_MCAST_FILTER_SIZE, data->multi_filter); - - rx_ctl |= 0x10; - } - - ax8817x_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); -} - -static int ax8817x_mdio_read(struct net_device *netdev, int phy_id, int loc) -{ - struct usbnet *dev = netdev_priv(netdev); - u16 res; - u8 buf[1]; - - ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, &buf); - ax8817x_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, (__u16)loc, 2, (u16 *)&res); - ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf); - - return res & 0xffff; -} - -static void ax8817x_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) -{ - struct usbnet *dev = netdev_priv(netdev); - u16 res = val; - u8 buf[1]; - - ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, &buf); - ax8817x_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, (u16 *)&res); - ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf); -} - -static int ax88172_link_reset(struct usbnet *dev) -{ - u16 lpa; - u8 mode; - - mode = AX_MEDIUM_TX_ABORT_ALLOW | AX_MEDIUM_FLOW_CONTROL_EN; - lpa = ax8817x_mdio_read(dev->net, dev->mii.phy_id, MII_LPA); - if (lpa & LPA_DUPLEX) - mode |= AX_MEDIUM_FULL_DUPLEX; - ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); - - return 0; -} - -static void ax8817x_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) -{ - struct usbnet *dev = netdev_priv(net); - u8 opt; - - if (ax8817x_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) { - wolinfo->supported = 0; - wolinfo->wolopts = 0; - return; - } - wolinfo->supported = WAKE_PHY | WAKE_MAGIC; - wolinfo->wolopts = 0; - if (opt & AX_MONITOR_MODE) { - if (opt & AX_MONITOR_LINK) - wolinfo->wolopts |= WAKE_PHY; - if (opt & AX_MONITOR_MAGIC) - wolinfo->wolopts |= WAKE_MAGIC; - } -} - -static int ax8817x_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) -{ - struct usbnet *dev = netdev_priv(net); - u8 opt = 0; - u8 buf[1]; - - if (wolinfo->wolopts & WAKE_PHY) - opt |= AX_MONITOR_LINK; - if (wolinfo->wolopts & WAKE_MAGIC) - opt |= AX_MONITOR_MAGIC; - if (opt != 0) - opt |= AX_MONITOR_MODE; - - if (ax8817x_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE, - opt, 0, 0, &buf) < 0) - return -EINVAL; - - return 0; -} - -static int ax8817x_get_eeprom_len(struct net_device *net) -{ - return AX_EEPROM_LEN; -} - -static int ax8817x_get_eeprom(struct net_device *net, - struct ethtool_eeprom *eeprom, u8 *data) -{ - struct usbnet *dev = netdev_priv(net); - u16 *ebuf = (u16 *)data; - int i; - - /* Crude hack to ensure that we don't overwrite memory - * if an odd length is supplied - */ - if (eeprom->len % 2) - return -EINVAL; - - eeprom->magic = AX_EEPROM_MAGIC; - - /* ax8817x returns 2 bytes from eeprom on read */ - for (i=0; i < eeprom->len / 2; i++) { - if (ax8817x_read_cmd(dev, AX_CMD_READ_EEPROM, - eeprom->offset + i, 0, 2, &ebuf[i]) < 0) - return -EINVAL; - } - return 0; -} - -static void ax8817x_get_drvinfo (struct net_device *net, - struct ethtool_drvinfo *info) -{ - /* Inherit standard device info */ - usbnet_get_drvinfo(net, info); - info->eedump_len = 0x3e; -} - -static int ax8817x_get_settings(struct net_device *net, struct ethtool_cmd *cmd) -{ - struct usbnet *dev = netdev_priv(net); - - return mii_ethtool_gset(&dev->mii,cmd); -} - -static int ax8817x_set_settings(struct net_device *net, struct ethtool_cmd *cmd) -{ - struct usbnet *dev = netdev_priv(net); - - return mii_ethtool_sset(&dev->mii,cmd); -} - -/* We need to override some ethtool_ops so we require our - own structure so we don't interfere with other usbnet - devices that may be connected at the same time. */ -static struct ethtool_ops ax8817x_ethtool_ops = { - .get_drvinfo = ax8817x_get_drvinfo, - .get_link = ethtool_op_get_link, - .get_msglevel = usbnet_get_msglevel, - .set_msglevel = usbnet_set_msglevel, - .get_wol = ax8817x_get_wol, - .set_wol = ax8817x_set_wol, - .get_eeprom_len = ax8817x_get_eeprom_len, - .get_eeprom = ax8817x_get_eeprom, - .get_settings = ax8817x_get_settings, - .set_settings = ax8817x_set_settings, -}; - -static int ax8817x_bind(struct usbnet *dev, struct usb_interface *intf) -{ - int ret = 0; - void *buf; - int i; - unsigned long gpio_bits = dev->driver_info->data; - - get_endpoints(dev,intf); - - buf = kmalloc(ETH_ALEN, GFP_KERNEL); - if(!buf) { - ret = -ENOMEM; - goto out1; - } - - /* Toggle the GPIOs in a manufacturer/model specific way */ - for (i = 2; i >= 0; i--) { - if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, - (gpio_bits >> (i * 8)) & 0xff, 0, 0, - buf)) < 0) - goto out2; - msleep(5); - } - - if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x80, 0, 0, buf)) < 0) { - dbg("send AX_CMD_WRITE_RX_CTL failed: %d", ret); - goto out2; - } - - /* Get the MAC address */ - memset(buf, 0, ETH_ALEN); - if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, 6, buf)) < 0) { - dbg("read AX_CMD_READ_NODE_ID failed: %d", ret); - goto out2; - } - memcpy(dev->net->dev_addr, buf, ETH_ALEN); - - /* Get the PHY id */ - if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf)) < 0) { - dbg("error on read AX_CMD_READ_PHY_ID: %02x", ret); - goto out2; - } else if (ret < 2) { - /* this should always return 2 bytes */ - dbg("AX_CMD_READ_PHY_ID returned less than 2 bytes: ret=%02x", ret); - ret = -EIO; - goto out2; - } - - /* Initialize MII structure */ - dev->mii.dev = dev->net; - dev->mii.mdio_read = ax8817x_mdio_read; - dev->mii.mdio_write = ax8817x_mdio_write; - dev->mii.phy_id_mask = 0x3f; - dev->mii.reg_num_mask = 0x1f; - dev->mii.phy_id = *((u8 *)buf + 1); - - dev->net->set_multicast_list = ax8817x_set_multicast; - dev->net->ethtool_ops = &ax8817x_ethtool_ops; - - ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); - ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, - ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); - mii_nway_restart(&dev->mii); - - return 0; -out2: - kfree(buf); -out1: - return ret; -} - -static struct ethtool_ops ax88772_ethtool_ops = { - .get_drvinfo = ax8817x_get_drvinfo, - .get_link = ethtool_op_get_link, - .get_msglevel = usbnet_get_msglevel, - .set_msglevel = usbnet_set_msglevel, - .get_wol = ax8817x_get_wol, - .set_wol = ax8817x_set_wol, - .get_eeprom_len = ax8817x_get_eeprom_len, - .get_eeprom = ax8817x_get_eeprom, - .get_settings = ax8817x_get_settings, - .set_settings = ax8817x_set_settings, -}; - -static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) -{ - int ret; - void *buf; - - get_endpoints(dev,intf); - - buf = kmalloc(6, GFP_KERNEL); - if(!buf) { - dbg ("Cannot allocate memory for buffer"); - ret = -ENOMEM; - goto out1; - } - - if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, - 0x00B0, 0, 0, buf)) < 0) - goto out2; - - msleep(5); - if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT, 0x0001, 0, 0, buf)) < 0) { - dbg("Select PHY #1 failed: %d", ret); - goto out2; - } - - if ((ret = - ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPPD, 0, 0, buf)) < 0) { - dbg("Failed to power down internal PHY: %d", ret); - goto out2; - } - - msleep(150); - if ((ret = - ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_CLEAR, 0, 0, buf)) < 0) { - dbg("Failed to perform software reset: %d", ret); - goto out2; - } - - msleep(150); - if ((ret = - ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPRL | AX_SWRESET_PRL, 0, 0, buf)) < 0) { - dbg("Failed to set Internal/External PHY reset control: %d", ret); - goto out2; - } - - msleep(150); - if ((ret = - ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x0000, 0, 0, - buf)) < 0) { - dbg("Failed to reset RX_CTL: %d", ret); - goto out2; - } - - /* Get the MAC address */ - memset(buf, 0, ETH_ALEN); - if ((ret = ax8817x_read_cmd(dev, AX88772_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf)) < 0) { - dbg("Failed to read MAC address: %d", ret); - goto out2; - } - memcpy(dev->net->dev_addr, buf, ETH_ALEN); - - if ((ret = ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, buf)) < 0) { - dbg("Enabling software MII failed: %d", ret); - goto out2; - } - - if (((ret = - ax8817x_read_cmd(dev, AX_CMD_READ_MII_REG, 0x0010, 2, 2, buf)) < 0) - || (*((u16 *)buf) != 0x003b)) { - dbg("Read PHY register 2 must be 0x3b00: %d", ret); - goto out2; - } - - /* Initialize MII structure */ - dev->mii.dev = dev->net; - dev->mii.mdio_read = ax8817x_mdio_read; - dev->mii.mdio_write = ax8817x_mdio_write; - dev->mii.phy_id_mask = 0xff; - dev->mii.reg_num_mask = 0xff; - - /* Get the PHY id */ - if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf)) < 0) { - dbg("Error reading PHY ID: %02x", ret); - goto out2; - } else if (ret < 2) { - /* this should always return 2 bytes */ - dbg("AX_CMD_READ_PHY_ID returned less than 2 bytes: ret=%02x", - ret); - ret = -EIO; - goto out2; - } - dev->mii.phy_id = *((u8 *)buf + 1); - - if ((ret = - ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_PRL, 0, 0, buf)) < 0) { - dbg("Set external PHY reset pin level: %d", ret); - goto out2; - } - msleep(150); - if ((ret = - ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPRL | AX_SWRESET_PRL, 0, 0, buf)) < 0) { - dbg("Set Internal/External PHY reset control: %d", ret); - goto out2; - } - msleep(150); - - - dev->net->set_multicast_list = ax8817x_set_multicast; - dev->net->ethtool_ops = &ax88772_ethtool_ops; - - ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); - ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, - ADVERTISE_ALL | ADVERTISE_CSMA); - mii_nway_restart(&dev->mii); - - if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, AX88772_MEDIUM_DEFAULT, 0, 0, buf)) < 0) { - dbg("Write medium mode register: %d", ret); - goto out2; - } - - if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_IPG0, AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT,AX88772_IPG2_DEFAULT, 0, buf)) < 0) { - dbg("Write IPG,IPG1,IPG2 failed: %d", ret); - goto out2; - } - if ((ret = - ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf)) < 0) { - dbg("Failed to set hardware MII: %02x", ret); - goto out2; - } - - /* Set RX_CTL to default values with 2k buffer, and enable cactus */ - if ((ret = - ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x0088, 0, 0, - buf)) < 0) { - dbg("Reset RX_CTL failed: %d", ret); - goto out2; - } - - kfree(buf); - - return 0; - -out2: - kfree(buf); -out1: - return ret; -} - -static int ax88772_rx_fixup(struct usbnet *dev, struct sk_buff *skb) -{ - u32 *header; - char *packet; - struct sk_buff *ax_skb; - u16 size; - - header = (u32 *) skb->data; - le32_to_cpus(header); - packet = (char *)(header + 1); - - skb_pull(skb, 4); - - while (skb->len > 0) { - if ((short)(*header & 0x0000ffff) != - ~((short)((*header & 0xffff0000) >> 16))) { - devdbg(dev,"header length data is error"); - } - /* get the packet length */ - size = (u16) (*header & 0x0000ffff); - - if ((skb->len) - ((size + 1) & 0xfffe) == 0) - return 2; - if (size > ETH_FRAME_LEN) { - devdbg(dev,"invalid rx length %d", size); - return 0; - } - ax_skb = skb_clone(skb, GFP_ATOMIC); - if (ax_skb) { - ax_skb->len = size; - ax_skb->data = packet; - ax_skb->tail = packet + size; - skb_return(dev, ax_skb); - } else { - return 0; - } - - skb_pull(skb, (size + 1) & 0xfffe); - - if (skb->len == 0) - break; - - header = (u32 *) skb->data; - le32_to_cpus(header); - packet = (char *)(header + 1); - skb_pull(skb, 4); - } - - if (skb->len < 0) { - devdbg(dev,"invalid rx length %d", skb->len); - return 0; - } - return 1; -} - -static struct sk_buff *ax88772_tx_fixup(struct usbnet *dev, struct sk_buff *skb, - int flags) -{ - int padlen; - int headroom = skb_headroom(skb); - int tailroom = skb_tailroom(skb); - u32 *packet_len; - u32 *padbytes_ptr; - - padlen = ((skb->len + 4) % 512) ? 0 : 4; - - if ((!skb_cloned(skb)) - && ((headroom + tailroom) >= (4 + padlen))) { - if ((headroom < 4) || (tailroom < padlen)) { - skb->data = memmove(skb->head + 4, skb->data, skb->len); - skb->tail = skb->data + skb->len; - } - } else { - struct sk_buff *skb2; - skb2 = skb_copy_expand(skb, 4, padlen, flags); - dev_kfree_skb_any(skb); - skb = skb2; - if (!skb) - return NULL; - } - - packet_len = (u32 *) skb_push(skb, 4); - - packet_len = (u32 *) skb->data; - *packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4); - - if ((skb->len % 512) == 0) { - padbytes_ptr = (u32 *) skb->tail; - *padbytes_ptr = 0xffff0000; - skb_put(skb, padlen); - } - return skb; -} - -static int ax88772_link_reset(struct usbnet *dev) -{ - u16 lpa; - u16 mode; - - mode = AX88772_MEDIUM_DEFAULT; - lpa = ax8817x_mdio_read(dev->net, dev->mii.phy_id, MII_LPA); - - if ((lpa & LPA_DUPLEX) == 0) - mode &= ~AX88772_MEDIUM_FULL_DUPLEX; - if ((lpa & LPA_100) == 0) - mode &= ~AX88772_MEDIUM_100MB; - ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); - - return 0; -} - -static const struct driver_info ax8817x_info = { - .description = "ASIX AX8817x USB 2.0 Ethernet", - .bind = ax8817x_bind, - .status = ax8817x_status, - .link_reset = ax88172_link_reset, - .reset = ax88172_link_reset, - .flags = FLAG_ETHER, - .data = 0x00130103, -}; - -static const struct driver_info dlink_dub_e100_info = { - .description = "DLink DUB-E100 USB Ethernet", - .bind = ax8817x_bind, - .status = ax8817x_status, - .link_reset = ax88172_link_reset, - .reset = ax88172_link_reset, - .flags = FLAG_ETHER, - .data = 0x009f9d9f, -}; - -static const struct driver_info netgear |