diff options
author | Jeff Garzik <jeff@garzik.org> | 2007-05-10 05:31:55 +0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-05-10 05:31:55 +0400 |
commit | 5b2fc499917e5897a13add780e181b4cef197072 (patch) | |
tree | 1a1ba52c0c2a7ce9843875cdd713d75d37c4ea1b /drivers/usb | |
parent | 3cb7396b7b26585b1ab7c1a8ca554ec103da5d37 (diff) | |
download | linux-5b2fc499917e5897a13add780e181b4cef197072.tar.xz |
Move USB network drivers to drivers/net/usb.
It is preferable to group drivers by usage (net, scsi, ATA, ...) than
by bus. When reviewing drivers, the [PCI|USB|PCMCIA|...] maintainer
is probably less qualified on networking issues than a networking
maintainer. Also, from a practical standpoint, chips often
appear on multiple buses, which is why we do not put drivers into
drivers/pci/net.
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/Kconfig | 2 | ||||
-rw-r--r-- | drivers/usb/Makefile | 7 | ||||
-rw-r--r-- | drivers/usb/net/Kconfig | 338 | ||||
-rw-r--r-- | drivers/usb/net/Makefile | 23 | ||||
-rw-r--r-- | drivers/usb/net/asix.c | 1490 | ||||
-rw-r--r-- | drivers/usb/net/catc.c | 963 | ||||
-rw-r--r-- | drivers/usb/net/cdc_ether.c | 570 | ||||
-rw-r--r-- | drivers/usb/net/cdc_subset.c | 344 | ||||
-rw-r--r-- | drivers/usb/net/dm9601.c | 619 | ||||
-rw-r--r-- | drivers/usb/net/gl620a.c | 245 | ||||
-rw-r--r-- | drivers/usb/net/kaweth.c | 1337 | ||||
-rw-r--r-- | drivers/usb/net/kawethfw.h | 557 | ||||
-rw-r--r-- | drivers/usb/net/mcs7830.c | 534 | ||||
-rw-r--r-- | drivers/usb/net/net1080.c | 615 | ||||
-rw-r--r-- | drivers/usb/net/pegasus.c | 1504 | ||||
-rw-r--r-- | drivers/usb/net/pegasus.h | 307 | ||||
-rw-r--r-- | drivers/usb/net/plusb.c | 150 | ||||
-rw-r--r-- | drivers/usb/net/rndis_host.c | 727 | ||||
-rw-r--r-- | drivers/usb/net/rtl8150.c | 1004 | ||||
-rw-r--r-- | drivers/usb/net/usbnet.c | 1304 | ||||
-rw-r--r-- | drivers/usb/net/usbnet.h | 200 | ||||
-rw-r--r-- | drivers/usb/net/zaurus.c | 385 |
22 files changed, 0 insertions, 13225 deletions
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index b847bbc8b0e1..278a22cea5bf 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -87,8 +87,6 @@ source "drivers/usb/storage/Kconfig" source "drivers/usb/image/Kconfig" -source "drivers/usb/net/Kconfig" - source "drivers/usb/mon/Kconfig" comment "USB port drivers" diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 0ef090b1b37c..72464b586990 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -23,13 +23,6 @@ obj-$(CONFIG_USB_PRINTER) += class/ obj-$(CONFIG_USB_STORAGE) += storage/ obj-$(CONFIG_USB) += storage/ -obj-$(CONFIG_USB_CATC) += net/ -obj-$(CONFIG_USB_KAWETH) += net/ -obj-$(CONFIG_USB_PEGASUS) += net/ -obj-$(CONFIG_USB_RTL8150) += net/ -obj-$(CONFIG_USB_USBNET) += net/ -obj-$(CONFIG_USB_ZD1201) += net/ - obj-$(CONFIG_USB_MDC800) += image/ obj-$(CONFIG_USB_MICROTEK) += image/ diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig deleted file mode 100644 index 3de564b23147..000000000000 --- a/drivers/usb/net/Kconfig +++ /dev/null @@ -1,338 +0,0 @@ -# -# USB Network devices configuration -# -comment "Networking support is needed for USB Network Adapter support" - depends on USB && !NET - -menu "USB Network Adapters" - depends on USB && NET - -config USB_CATC - tristate "USB CATC NetMate-based Ethernet device support (EXPERIMENTAL)" - depends on EXPERIMENTAL - select CRC32 - ---help--- - Say Y if you want to use one of the following 10Mbps USB Ethernet - device based on the EL1210A chip. Supported devices are: - Belkin F5U011 - Belkin F5U111 - CATC NetMate - CATC NetMate II - smartBridges smartNIC - - This driver makes the adapter appear as a normal Ethernet interface, - typically on eth0, if it is the only ethernet device, or perhaps on - eth1, if you have a PCI or ISA ethernet card installed. - - To compile this driver as a module, choose M here: the - module will be called catc. - -config USB_KAWETH - tristate "USB KLSI KL5USB101-based ethernet device support" - ---help--- - Say Y here if you want to use one of the following 10Mbps only - USB Ethernet adapters based on the KLSI KL5KUSB101B chipset: - 3Com 3C19250 - ADS USB-10BT - ATEN USB Ethernet - ASANTE USB To Ethernet Adapter - AOX Endpoints USB Ethernet - Correga K.K. - D-Link DSB-650C and DU-E10 - Entrega / Portgear E45 - I-O DATA USB-ET/T - Jaton USB Ethernet Device Adapter - Kingston Technology USB Ethernet Adapter - Linksys USB10T - Mobility USB-Ethernet Adapter - NetGear EA-101 - Peracom Enet and Enet2 - Portsmith Express Ethernet Adapter - Shark Pocket Adapter - SMC 2202USB - Sony Vaio port extender - - This driver is likely to work with most 10Mbps only USB Ethernet - adapters, including some "no brand" devices. It does NOT work on - SmartBridges smartNIC or on Belkin F5U111 devices - you should use - the CATC NetMate driver for those. If you are not sure which one - you need, select both, and the correct one should be selected for - you. - - This driver makes the adapter appear as a normal Ethernet interface, - typically on eth0, if it is the only ethernet device, or perhaps on - eth1, if you have a PCI or ISA ethernet card installed. - - To compile this driver as a module, choose M here: the - module will be called kaweth. - -config USB_PEGASUS - tristate "USB Pegasus/Pegasus-II based ethernet device support" - select MII - ---help--- - Say Y here if you know you have Pegasus or Pegasus-II based adapter. - If in doubt then look at <file:drivers/usb/net/pegasus.h> for the - complete list of supported devices. - - If your particular adapter is not in the list and you are _sure_ it - is Pegasus or Pegasus II based then send me - <petkan@users.sourceforge.net> vendor and device IDs. - - To compile this driver as a module, choose M here: the - module will be called pegasus. - -config USB_RTL8150 - tristate "USB RTL8150 based ethernet device support (EXPERIMENTAL)" - depends on EXPERIMENTAL - select MII - help - Say Y here if you have RTL8150 based usb-ethernet adapter. - Send me <petkan@users.sourceforge.net> any comments you may have. - You can also check for updates at <http://pegasus2.sourceforge.net/>. - - To compile this driver as a module, choose M here: the - module will be called rtl8150. - -config USB_USBNET_MII - tristate - default n - -config USB_USBNET - tristate "Multi-purpose USB Networking Framework" - select MII if USB_USBNET_MII != n - ---help--- - This driver supports several kinds of network links over USB, - with "minidrivers" built around a common network driver core - that supports deep queues for efficient transfers. (This gives - better performance with small packets and at high speeds). - - The USB host runs "usbnet", and the other end of the link might be: - - - Another USB host, when using USB "network" or "data transfer" - cables. These are often used to network laptops to PCs, like - "Laplink" parallel cables or some motherboards. These rely - on specialized chips from many suppliers. - - - An intelligent USB gadget, perhaps embedding a Linux system. - These include PDAs running Linux (iPaq, Yopy, Zaurus, and - others), and devices that interoperate using the standard - CDC-Ethernet specification (including many cable modems). - - - Network adapter hardware (like those for 10/100 Ethernet) which - uses this driver framework. - - The link will appear with a name like "usb0", when the link is - a two-node link, or "eth0" for most CDC-Ethernet devices. Those - two-node links are most easily managed with Ethernet Bridging - (CONFIG_BRIDGE) instead of routing. - - For more information see <http://www.linux-usb.org/usbnet/>. - - To compile this driver as a module, choose M here: the - module will be called usbnet. - -config USB_NET_AX8817X - tristate "ASIX AX88xxx Based USB 2.0 Ethernet Adapters" - depends on USB_USBNET && NET_ETHERNET - select CRC32 - select USB_USBNET_MII - default y - help - This option adds support for ASIX AX88xxx based USB 2.0 - 10/100 Ethernet adapters. - - This driver should work with at least the following devices: - * Aten UC210T - * ASIX AX88172 - * Billionton Systems, USB2AR - * Buffalo LUA-U2-KTX - * Corega FEther USB2-TX - * D-Link DUB-E100 - * Hawking UF200 - * Linksys USB200M - * Netgear FA120 - * Sitecom LN-029 - * Intellinet USB 2.0 Ethernet - * ST Lab USB 2.0 Ethernet - * TrendNet TU2-ET100 - - This driver creates an interface named "ethX", where X depends on - what other networking devices you have in use. - - -config USB_NET_CDCETHER - tristate "CDC Ethernet support (smart devices such as cable modems)" - depends on USB_USBNET - default y - help - This option supports devices conforming to the Communication Device - Class (CDC) Ethernet Control Model, a specification that's easy to - implement in device firmware. The CDC specifications are available - from <http://www.usb.org/>. - - CDC Ethernet is an implementation option for DOCSIS cable modems - that support USB connectivity, used for non-Microsoft USB hosts. - The Linux-USB CDC Ethernet Gadget driver is an open implementation. - This driver should work with at least the following devices: - - * Ericsson PipeRider (all variants) - * Motorola (DM100 and SB4100) - * Broadcom Cable Modem (reference design) - * Toshiba PCX1100U - * ... - - This driver creates an interface named "ethX", where X depends on - what other networking devices you have in use. However, if the - IEEE 802 "local assignment" bit is set in the address, a "usbX" - name is used instead. - -config USB_NET_DM9601 - tristate "Davicom DM9601 based USB 1.1 10/100 ethernet devices" - depends on USB_USBNET - select CRC32 - select USB_USBNET_MII - help - This option adds support for Davicom DM9601 based USB 1.1 - 10/100 Ethernet adapters. - -config USB_NET_GL620A - tristate "GeneSys GL620USB-A based cables" - depends on USB_USBNET - help - Choose this option if you're using a host-to-host cable, - or PC2PC motherboard, with this chip. - - Note that the half-duplex "GL620USB" is not supported. - -config USB_NET_NET1080 - tristate "NetChip 1080 based cables (Laplink, ...)" - default y - depends on USB_USBNET - help - Choose this option if you're using a host-to-host cable based - on this design: one NetChip 1080 chip and supporting logic, - optionally with LEDs that indicate traffic - -config USB_NET_PLUSB - tristate "Prolific PL-2301/2302 based cables" - # if the handshake/init/reset problems, from original 'plusb', - # are ever resolved ... then remove "experimental" - depends on USB_USBNET && EXPERIMENTAL - help - Choose this option if you're using a host-to-host cable - with one of these chips. - -config USB_NET_MCS7830 - tristate "MosChip MCS7830 based Ethernet adapters" - depends on USB_USBNET - select USB_USBNET_MII - help - Choose this option if you're using a 10/100 Ethernet USB2 - adapter based on the MosChip 7830 controller. This includes - adapters marketed under the DeLOCK brand. - -config USB_NET_RNDIS_HOST - tristate "Host for RNDIS and ActiveSync devices (EXPERIMENTAL)" - depends on USB_USBNET && EXPERIMENTAL - select USB_NET_CDCETHER - help - This option enables hosting "Remote NDIS" USB networking links, - as encouraged by Microsoft (instead of CDC Ethernet!) for use in - various devices that may only support this protocol. A variant - of this protocol (with even less public documentation) seems to - be at the root of Microsoft's "ActiveSync" too. - - Avoid using this protocol unless you have no better options. - The protocol specification is incomplete, and is controlled by - (and for) Microsoft; it isn't an "Open" ecosystem or market. - -config USB_NET_CDC_SUBSET - tristate "Simple USB Network Links (CDC Ethernet subset)" - depends on USB_USBNET - default y - help - This driver module supports USB network devices that can work - without any device-specific information. Select it if you have - one of these drivers. - - Note that while many USB host-to-host cables can work in this mode, - that may mean not being able to talk to Win32 systems or more - commonly not being able to handle certain events (like replugging - the host on the other end) very well. Also, these devices will - not generally have permanently assigned Ethernet addresses. - -config USB_ALI_M5632 - boolean "ALi M5632 based 'USB 2.0 Data Link' cables" - depends on USB_NET_CDC_SUBSET - help - Choose this option if you're using a host-to-host cable - based on this design, which supports USB 2.0 high speed. - -config USB_AN2720 - boolean "AnchorChips 2720 based cables (Xircom PGUNET, ...)" - depends on USB_NET_CDC_SUBSET - help - Choose this option if you're using a host-to-host cable - based on this design. Note that AnchorChips is now a - Cypress brand. - -config USB_BELKIN - boolean "eTEK based host-to-host cables (Advance, Belkin, ...)" - depends on USB_NET_CDC_SUBSET - default y - help - Choose this option if you're using a host-to-host cable - based on this design: two NetChip 2890 chips and an Atmel - microcontroller, with LEDs that indicate traffic. - -config USB_ARMLINUX - boolean "Embedded ARM Linux links (iPaq, ...)" - depends on USB_NET_CDC_SUBSET - default y - help - Choose this option to support the "usb-eth" networking driver - used by most of the ARM Linux community with device controllers - such as the SA-11x0 and PXA-25x UDCs, or the tftp capabilities - in some PXA versions of the "blob" boot loader. - - Linux-based "Gumstix" PXA-25x based systems use this protocol - to talk with other Linux systems. - - Although the ROMs shipped with Sharp Zaurus products use a - different link level framing protocol, you can have them use - this simpler protocol by installing a different kernel. - -config USB_EPSON2888 - boolean "Epson 2888 based firmware (DEVELOPMENT)" - depends on USB_NET_CDC_SUBSET - help - Choose this option to support the usb networking links used - by some sample firmware from Epson. - -config USB_KC2190 - boolean "KT Technology KC2190 based cables (InstaNet)" - depends on USB_NET_CDC_SUBSET && EXPERIMENTAL - help - Choose this option if you're using a host-to-host cable - with one of these chips. - -config USB_NET_ZAURUS - tristate "Sharp Zaurus (stock ROMs) and compatible" - depends on USB_USBNET - select USB_NET_CDCETHER - select CRC32 - default y - help - Choose this option to support the usb networking links used by - Zaurus models like the SL-5000D, SL-5500, SL-5600, A-300, B-500. - This also supports some related device firmware, as used in some - PDAs from Olympus and some cell phones from Motorola. - - If you install an alternate image, such as the Linux 2.6 based - versions of OpenZaurus, you should no longer need to support this - protocol. Only the "eth-fd" or "net_fd" drivers in these devices - really need this non-conformant variant of CDC Ethernet (or in - some cases CDC MDLM) protocol, not "g_ether". - - -endmenu diff --git a/drivers/usb/net/Makefile b/drivers/usb/net/Makefile deleted file mode 100644 index 595a539f8384..000000000000 --- a/drivers/usb/net/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -# -# Makefile for USB Network drivers -# - -obj-$(CONFIG_USB_CATC) += catc.o -obj-$(CONFIG_USB_KAWETH) += kaweth.o -obj-$(CONFIG_USB_PEGASUS) += pegasus.o -obj-$(CONFIG_USB_RTL8150) += rtl8150.o -obj-$(CONFIG_USB_NET_AX8817X) += asix.o -obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o -obj-$(CONFIG_USB_NET_DM9601) += dm9601.o -obj-$(CONFIG_USB_NET_GL620A) += gl620a.o -obj-$(CONFIG_USB_NET_NET1080) += net1080.o -obj-$(CONFIG_USB_NET_PLUSB) += plusb.o -obj-$(CONFIG_USB_NET_RNDIS_HOST) += rndis_host.o -obj-$(CONFIG_USB_NET_CDC_SUBSET) += cdc_subset.o -obj-$(CONFIG_USB_NET_ZAURUS) += zaurus.o -obj-$(CONFIG_USB_NET_MCS7830) += mcs7830.o -obj-$(CONFIG_USB_USBNET) += usbnet.o - -ifeq ($(CONFIG_USB_DEBUG),y) -EXTRA_CFLAGS += -DDEBUG -endif diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c deleted file mode 100644 index d5ef97bc4d01..000000000000 --- a/drivers/usb/net/asix.c +++ /dev/null @@ -1,1490 +0,0 @@ -/* - * ASIX AX8817X based USB 2.0 Ethernet Devices - * Copyright (C) 2003-2006 David Hollis <dhollis@davehollis.com> - * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net> - * Copyright (C) 2006 James Painter <jamie.painter@iname.com> - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -// #define DEBUG // error path messages, extra info -// #define VERBOSE // more; success messages - -#include <linux/module.h> -#include <linux/kmod.h> -#include <linux/init.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/ethtool.h> -#include <linux/workqueue.h> -#include <linux/mii.h> -#include <linux/usb.h> -#include <linux/crc32.h> - -#include "usbnet.h" - -#define DRIVER_VERSION "14-Jun-2006" -static const char driver_name [] = "asix"; - -/* ASIX AX8817X based USB 2.0 Ethernet Devices */ - -#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_READ_RX_CTL 0x0f -#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_READ_NODE_ID 0x13 -#define AX_CMD_WRITE_IPG2 0x14 -#define AX_CMD_WRITE_MULTI_FILTER 0x16 -#define AX88172_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_READ_GPIOS 0x1e -#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 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 AX88172_MEDIUM_FD 0x02 -#define AX88172_MEDIUM_TX 0x04 -#define AX88172_MEDIUM_FC 0x10 -#define AX88172_MEDIUM_DEFAULT \ - ( AX88172_MEDIUM_FD | AX88172_MEDIUM_TX | AX88172_MEDIUM_FC ) - -#define AX_MCAST_FILTER_SIZE 8 -#define AX_MAX_MCAST 64 - -#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 - -/* AX88772 & AX88178 Medium Mode Register */ -#define AX_MEDIUM_PF 0x0080 -#define AX_MEDIUM_JFE 0x0040 -#define AX_MEDIUM_TFC 0x0020 -#define AX_MEDIUM_RFC 0x0010 -#define AX_MEDIUM_ENCK 0x0008 -#define AX_MEDIUM_AC 0x0004 -#define AX_MEDIUM_FD 0x0002 -#define AX_MEDIUM_GM 0x0001 -#define AX_MEDIUM_SM 0x1000 -#define AX_MEDIUM_SBP 0x0800 -#define AX_MEDIUM_PS 0x0200 -#define AX_MEDIUM_RE 0x0100 - -#define AX88178_MEDIUM_DEFAULT \ - (AX_MEDIUM_PS | AX_MEDIUM_FD | AX_MEDIUM_AC | \ - AX_MEDIUM_RFC | AX_MEDIUM_TFC | AX_MEDIUM_JFE | \ - AX_MEDIUM_RE ) - -#define AX88772_MEDIUM_DEFAULT \ - (AX_MEDIUM_FD | AX_MEDIUM_RFC | \ - AX_MEDIUM_TFC | AX_MEDIUM_PS | \ - AX_MEDIUM_AC | AX_MEDIUM_RE ) - -/* AX88772 & AX88178 RX_CTL values */ -#define AX_RX_CTL_SO 0x0080 -#define AX_RX_CTL_AP 0x0020 -#define AX_RX_CTL_AM 0x0010 -#define AX_RX_CTL_AB 0x0008 -#define AX_RX_CTL_SEP 0x0004 -#define AX_RX_CTL_AMALL 0x0002 -#define AX_RX_CTL_PRO 0x0001 -#define AX_RX_CTL_MFB_2048 0x0000 -#define AX_RX_CTL_MFB_4096 0x0100 -#define AX_RX_CTL_MFB_8192 0x0200 -#define AX_RX_CTL_MFB_16384 0x0300 - -#define AX_DEFAULT_RX_CTL \ - (AX_RX_CTL_SO | AX_RX_CTL_AB ) - -/* GPIO 0 .. 2 toggles */ -#define AX_GPIO_GPO0EN 0x01 /* GPIO0 Output enable */ -#define AX_GPIO_GPO_0 0x02 /* GPIO0 Output value */ -#define AX_GPIO_GPO1EN 0x04 /* GPIO1 Output enable */ -#define AX_GPIO_GPO_1 0x08 /* GPIO1 Output value */ -#define AX_GPIO_GPO2EN 0x10 /* GPIO2 Output enable */ -#define AX_GPIO_GPO_2 0x20 /* GPIO2 Output value */ -#define AX_GPIO_RESERVED 0x40 /* Reserved */ -#define AX_GPIO_RSE 0x80 /* Reload serial EEPROM */ - -#define AX_EEPROM_MAGIC 0xdeadbeef -#define AX88172_EEPROM_LEN 0x40 -#define AX88772_EEPROM_LEN 0xff - -#define PHY_MODE_MARVELL 0x0000 -#define MII_MARVELL_LED_CTRL 0x0018 -#define MII_MARVELL_STATUS 0x001b -#define MII_MARVELL_CTRL 0x0014 - -#define MARVELL_LED_MANUAL 0x0019 - -#define MARVELL_STATUS_HWCFG 0x0004 - -#define MARVELL_CTRL_TXDELAY 0x0002 -#define MARVELL_CTRL_RXDELAY 0x0080 - -/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ -struct asix_data { - u8 multi_filter[AX_MCAST_FILTER_SIZE]; - u8 phymode; - u8 ledmode; - u8 eeprom_len; -}; - -struct ax88172_int_data { - u16 res1; - u8 link; - u16 res2; - u8 status; - u16 res3; -} __attribute__ ((packed)); - -static int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, - u16 size, void *data) -{ - devdbg(dev,"asix_read_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d", - cmd, value, index, size); - 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, - USB_CTRL_GET_TIMEOUT); -} - -static int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, - u16 size, void *data) -{ - devdbg(dev,"asix_write_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d", - cmd, value, index, size); - 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, - USB_CTRL_SET_TIMEOUT); -} - -static void asix_async_cmd_callback(struct urb *urb) -{ - struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; - - if (urb->status < 0) - printk(KERN_DEBUG "asix_async_cmd_callback() failed with %d", - urb->status); - - kfree(req); - usb_free_urb(urb); -} - -static void -asix_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; - - devdbg(dev,"asix_write_cmd_async() cmd=0x%02x value=0x%04x index=0x%04x size=%d", - cmd, value, index, size); - if ((urb = usb_alloc_urb(0, GFP_ATOMIC)) == NULL) { - deverr(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, - asix_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 int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb) -{ - u8 *head; - u32 header; - char *packet; - struct sk_buff *ax_skb; - u16 size; - - head = (u8 *) skb->data; - memcpy(&header, head, sizeof(header)); - le32_to_cpus(&header); - packet = head + sizeof(header); - - skb_pull(skb, 4); - - while (skb->len > 0) { - if ((short)(header & 0x0000ffff) != - ~((short)((header & 0xffff0000) >> 16))) { - deverr(dev,"asix_rx_fixup() Bad Header Length"); - } - /* get the packet length */ - size = (u16) (header & 0x0000ffff); - - if ((skb->len) - ((size + 1) & 0xfffe) == 0) - return 2; - if (size > ETH_FRAME_LEN) { - deverr(dev,"asix_rx_fixup() Bad RX Length %d", size); - return 0; - } - ax_skb = skb_clone(skb, GFP_ATOMIC); - if (ax_skb) { - ax_skb->len = size; - ax_skb->data = packet; - skb_set_tail_pointer(ax_skb, size); - usbnet_skb_return(dev, ax_skb); - } else { - return 0; - } - - skb_pull(skb, (size + 1) & 0xfffe); - - if (skb->len == 0) - break; - - head = (u8 *) skb->data; - memcpy(&header, head, sizeof(header)); - le32_to_cpus(&header); - packet = head + sizeof(header); - skb_pull(skb, 4); - } - - if (skb->len < 0) { - deverr(dev,"asix_rx_fixup() Bad SKB Length %d", skb->len); - return 0; - } - return 1; -} - -static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, - gfp_t flags) -{ - int padlen; - int headroom = skb_headroom(skb); - int tailroom = skb_tailroom(skb); - u32 packet_len; - u32 padbytes = 0xffff0000; - - 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_set_tail_pointer(skb, 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; - } - - skb_push(skb, 4); - packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4); - cpu_to_le32s(&packet_len); - skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len)); - - if ((skb->len % 512) == 0) { - cpu_to_le32s(&padbytes); - memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes)); - skb_put(skb, sizeof(padbytes)); - } - return skb; -} - -static void asix_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); - usbnet_defer_kevent (dev, EVENT_LINK_RESET ); - } else - netif_carrier_off(dev->net); - devdbg(dev, "Link Status is: %d", link); - } -} - -static inline int asix_set_sw_mii(struct usbnet *dev) -{ - int ret; - ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL); - if (ret < 0) - deverr(dev, "Failed to enable software MII access"); - return ret; -} - -static inline int asix_set_hw_mii(struct usbnet *dev) -{ - int ret; - ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL); - if (ret < 0) - deverr(dev, "Failed to enable hardware MII access"); - return ret; -} - -static inline int asix_get_phy_addr(struct usbnet *dev) -{ - int ret = 0; - void *buf; - - devdbg(dev, "asix_get_phy_addr()"); - - buf = kmalloc(2, GFP_KERNEL); - if (!buf) - goto out1; - - if ((ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, - 0, 0, 2, buf)) < 2) { - deverr(dev, "Error reading PHYID register: %02x", ret); - goto out2; - } - devdbg(dev, "asix_get_phy_addr() returning 0x%04x", *((u16 *)buf)); - ret = *((u8 *)buf + 1); -out2: - kfree(buf); -out1: - return ret; -} - -static int asix_sw_reset(struct usbnet *dev, u8 flags) -{ - int ret; - - ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL); - if (ret < 0) - deverr(dev,"Failed to send software reset: %02x", ret); - - return ret; -} - -static u16 asix_read_rx_ctl(struct usbnet *dev) -{ - u16 ret = 0; - void *buf; - - buf = kmalloc(2, GFP_KERNEL); - if (!buf) - goto out1; - - if ((ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL, - 0, 0, 2, buf)) < 2) { - deverr(dev, "Error reading RX_CTL register: %02x", ret); - goto out2; - } - ret = le16_to_cpu(*((u16 *)buf)); -out2: - kfree(buf); -out1: - return ret; -} - -static int asix_write_rx_ctl(struct usbnet *dev, u16 mode) -{ - int ret; - - devdbg(dev,"asix_write_rx_ctl() - mode = 0x%04x", mode); - ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL); - if (ret < 0) - deverr(dev, "Failed to write RX_CTL mode to 0x%04x: %02x", - mode, ret); - - return ret; -} - -static u16 asix_read_medium_status(struct usbnet *dev) -{ - u16 ret = 0; - void *buf; - - buf = kmalloc(2, GFP_KERNEL); - if (!buf) - goto out1; - - if ((ret = asix_read_cmd(dev, AX_CMD_READ_MEDIUM_STATUS, - 0, 0, 2, buf)) < 2) { - deverr(dev, "Error reading Medium Status register: %02x", ret); - goto out2; - } - ret = le16_to_cpu(*((u16 *)buf)); -out2: - kfree(buf); -out1: - return ret; -} - -static int asix_write_medium_mode(struct usbnet *dev, u16 mode) -{ - int ret; - - devdbg(dev,"asix_write_medium_mode() - mode = 0x%04x", mode); - ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); - if (ret < 0) - deverr(dev, "Failed to write Medium Mode mode to 0x%04x: %02x", - mode, ret); - - return ret; -} - -static int asix_write_gpio(struct usbnet *dev, u16 value, int sleep) -{ - int ret; - - devdbg(dev,"asix_write_gpio() - value = 0x%04x", value); - ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL); - if (ret < 0) - deverr(dev, "Failed to write GPIO value 0x%04x: %02x", - value, ret); - - if (sleep) - msleep(sleep); - - return ret; -} - -/* - * AX88772 & AX88178 have a 16-bit RX_CTL value - */ -static void asix_set_multicast(struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - struct asix_data *data = (struct asix_data *)&dev->data; - u16 rx_ctl = AX_DEFAULT_RX_CTL; - - if (net->flags & IFF_PROMISC) { - rx_ctl |= AX_RX_CTL_PRO; - } else if (net->flags & IFF_ALLMULTI - || net->mc_count > AX_MAX_MCAST) { - rx_ctl |= AX_RX_CTL_AMALL; - } 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; - } - - asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, - AX_MCAST_FILTER_SIZE, data->multi_filter); - - rx_ctl |= AX_RX_CTL_AM; - } - - asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); -} - -static int asix_mdio_read(struct net_device *netdev, int phy_id, int loc) -{ - struct usbnet *dev = netdev_priv(netdev); - u16 res; - - mutex_lock(&dev->phy_mutex); - asix_set_sw_mii(dev); - asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, - (__u16)loc, 2, (u16 *)&res); - asix_set_hw_mii(dev); - mutex_unlock(&dev->phy_mutex); - - devdbg(dev, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x", phy_id, loc, le16_to_cpu(res & 0xffff)); - - return le16_to_cpu(res & 0xffff); -} - -static void -asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) -{ - struct usbnet *dev = netdev_priv(netdev); - u16 res = cpu_to_le16(val); - - devdbg(dev, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x", phy_id, loc, val); - mutex_lock(&dev->phy_mutex); - asix_set_sw_mii(dev); - asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, - (__u16)loc, 2, (u16 *)&res); - asix_set_hw_mii(dev); - mutex_unlock(&dev->phy_mutex); -} - -/* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */ -static u32 asix_get_phyid(struct usbnet *dev) -{ - int phy_reg; - u32 phy_id; - - phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID1); - if (phy_reg < 0) - return 0; - - phy_id = (phy_reg & 0xffff) << 16; - - phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID2); - if (phy_reg < 0) - return 0; - - phy_id |= (phy_reg & 0xffff); - - return phy_id; -} - -static void -asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) -{ - struct usbnet *dev = netdev_priv(net); - u8 opt; - - if (asix_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 -asix_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 (asix_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE, - opt, 0, 0, &buf) < 0) - return -EINVAL; - - return 0; -} - -static int asix_get_eeprom_len(struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - struct asix_data *data = (struct asix_data *)&dev->data; - - return data->eeprom_len; -} - -static int asix_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 (asix_read_cmd(dev, AX_CMD_READ_EEPROM, - eeprom->offset + i, 0, 2, &ebuf[i]) < 0) - return -EINVAL; - } - return 0; -} - -static void asix_get_drvinfo (struct net_device *net, - struct ethtool_drvinfo *info) -{ - struct usbnet *dev = netdev_priv(net); - struct asix_data *data = (struct asix_data *)&dev->data; - - /* Inherit standard device info */ - usbnet_get_drvinfo(net, info); - strncpy (info->driver, driver_name, sizeof info->driver); - strncpy (info->version, DRIVER_VERSION, sizeof info->version); - info->eedump_len = data->eeprom_len; -} - -static u32 asix_get_link(struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - - return mii_link_ok(&dev->mii); -} - -static int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd) -{ - struct usbnet *dev = netdev_priv(net); - - return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); -} - -/* 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 ax88172_ethtool_ops = { - .get_drvinfo = asix_get_drvinfo, - .get_link = asix_get_link, - .get_msglevel = usbnet_get_msglevel, - .set_msglevel = usbnet_set_msglevel, - .get_wol = asix_get_wol, - .set_wol = asix_set_wol, - .get_eeprom_len = asix_get_eeprom_len, - .get_eeprom = asix_get_eeprom, - .get_settings = usbnet_get_settings, - .set_settings = usbnet_set_settings, - .nway_reset = usbnet_nway_reset, -}; - -static void ax88172_set_multicast(struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - struct asix_data *data = (struct asix_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; - } - - asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, - AX_MCAST_FILTER_SIZE, data->multi_filter); - - rx_ctl |= 0x10; - } - - asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); -} - -static int ax88172_link_reset(struct usbnet *dev) -{ - u8 mode; - struct ethtool_cmd ecmd; - - mii_check_media(&dev->mii, 1, 1); - mii_ethtool_gset(&dev->mii, &ecmd); - mode = AX88172_MEDIUM_DEFAULT; - - if (ecmd.duplex != DUPLEX_FULL) - mode |= ~AX88172_MEDIUM_FD; - - devdbg(dev, "ax88172_link_reset() speed: %d duplex: %d setting mode to 0x%04x", ecmd.speed, ecmd.duplex, mode); - - asix_write_medium_mode(dev, mode); - - return 0; -} - -static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf) -{ - int ret = 0; - void *buf; - int i; - unsigned long gpio_bits = dev->driver_info->data; - struct asix_data *data = (struct asix_data *)&dev->data; - - data->eeprom_len = AX88172_EEPROM_LEN; - - usbnet_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 = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, - (gpio_bits >> (i * 8)) & 0xff, 0, 0, - buf)) < 0) - goto out2; - msleep(5); - } - - if ((ret = asix_write_rx_ctl(dev, 0x80)) < 0) - goto out2; - - /* Get the MAC address */ - memset(buf, 0, ETH_ALEN); - if ((ret = asix_read_cmd(dev, AX88172_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); - - /* Initialize MII structure */ - dev->mii.dev = dev->net; - dev->mii.mdio_read = asix_mdio_read; - dev->mii.mdio_write = asix_mdio_write; - dev->mii.phy_id_mask = 0x3f; - dev->mii.reg_num_mask = 0x1f; - dev->mii.phy_id = asix_get_phy_addr(dev); - dev->net->do_ioctl = asix_ioctl; - - dev->net->set_multicast_list = ax88172_set_multicast; - dev->net->ethtool_ops = &ax88172_ethtool_ops; - - asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); - asix_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 = asix_get_drvinfo, - .get_link = asix_get_link, - .get_msglevel = usbnet_get_msglevel, - .set_msglevel = usbnet_set_msglevel, - .get_wol = asix_get_wol, - .set_wol = asix_set_wol, - .get_eeprom_len = asix_get_eeprom_len, - .get_eeprom = asix_get_eeprom, - .get_settings = usbnet_get_settings, - .set_settings = usbnet_set_settings, - .nway_reset = usbnet_nway_reset, -}; - -static int ax88772_link_reset(struct usbnet *dev) -{ - u16 mode; - struct ethtool_cmd ecmd; - - mii_check_media(&dev->mii, 1, 1); - mii_ethtool_gset(&dev->mii, &ecmd); - mode = AX88772_MEDIUM_DEFAULT; - - if (ecmd.speed != SPEED_100) - mode &= ~AX_MEDIUM_PS; - - if (ecmd.duplex != DUPLEX_FULL) - mode &= ~AX_MEDIUM_FD; - - devdbg(dev, "ax88772_link_reset() speed: %d duplex: %d setting mode to 0x%04x", ecmd.speed, ecmd.duplex, mode); - - asix_write_medium_mode(dev, mode); - - return 0; -} - -static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) -{ - int ret, embd_phy; - void *buf; - u16 rx_ctl; - struct asix_data *data = (struct asix_data *)&dev->data; - u32 phyid; - - data->eeprom_len = AX88772_EEPROM_LEN; - - usbnet_get_endpoints(dev,intf); - - buf = kmalloc(6, GFP_KERNEL); - if(!buf) { - dbg ("Cannot allocate memory for buffer"); - ret = -ENOMEM; - goto out1; - } - - if ((ret = asix_write_gpio(dev, - AX_GPIO_RSE | AX_GPIO_GPO_2 | AX_GPIO_GPO2EN, 5)) < 0) - goto out2; - - /* 0x10 is the phy id of the embedded 10/100 ethernet phy */ - embd_phy = ((asix_get_phy_addr(dev) & 0x1f) == 0x10 ? 1 : 0); - if ((ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, - embd_phy, 0, 0, buf)) < 0) { - dbg("Select PHY #1 failed: %d", ret); - goto out2; - } - - if ((ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL)) < 0) - goto out2; - - msleep(150); - if ((ret = asix_sw_reset(dev, AX_SWRESET_CLEAR)) < 0) - goto out2; - - msleep(150); - if (embd_phy) { - if ((ret = asix_sw_reset(dev, AX_SWRESET_IPRL)) < 0) - goto out2; - } - else { - if ((ret = asix_sw_reset(dev, AX_SWRESET_PRTE)) < 0) - goto out2; - } - - msleep(150); - rx_ctl = asix_read_rx_ctl(dev); - dbg("RX_CTL is 0x%04x after software reset", rx_ctl); - if ((ret = asix_write_rx_ctl(dev, 0x0000)) < 0) - goto out2; - - rx_ctl = asix_read_rx_ctl(dev); - dbg("RX_CTL is 0x%04x setting to 0x0000", rx_ctl); - - /* Get the MAC address */ - memset(buf, 0, ETH_ALEN); - if ((ret = asix_read_cmd(dev, AX_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); - - /* Initialize MII structure */ - dev->mii.dev = dev->net; - dev->mii.mdio_read = asix_mdio_read; - dev->mii.mdio_write = asix_mdio_write; - dev->mii.phy_id_mask = 0x1f; - dev->mii.reg_num_mask = 0x1f; - dev->net->do_ioctl = asix_ioctl; - dev->mii.phy_id = asix_get_phy_addr(dev); - - phyid = asix_get_phyid(dev); - dbg("PHYID=0x%08x", phyid); - - if ((ret = asix_sw_reset(dev, AX_SWRESET_PRL)) < 0) - goto out2; - - msleep(150); - - if ((ret = asix_sw_reset(dev, AX_SWRESET_IPRL | AX_SWRESET_PRL)) < 0) - goto out2; - - msleep(150); - - dev->net->set_multicast_list = asix_set_multicast; - dev->net->ethtool_ops = &ax88772_ethtool_ops; - - asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); - asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, - ADVERTISE_ALL | ADVERTISE_CSMA); - mii_nway_restart(&dev->mii); - - if ((ret = asix_write_medium_mode(dev, AX88772_MEDIUM_DEFAULT)) < 0) - goto out2; - - if ((ret = asix_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; - } - - /* Set RX_CTL to default values with 2k buffer, and enable cactus */ - if ((ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL)) < 0) - goto out2; - - rx_ctl = asix_read_rx_ctl(dev); - dbg("RX_CTL is 0x%04x after all initializations", rx_ctl); - - rx_ctl = asix_read_medium_status(dev); - dbg("Medium Status is 0x%04x after all initializations", rx_ctl); - - kfree(buf); - - /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ - if (dev->driver_info->flags & FLAG_FRAMING_AX) { - /* hard_mtu is still the default - the device does not support - jumbo eth frames */ - dev->rx_urb_size = 2048; - } - - return 0; - -out2: - kfree(buf); -out1: - return ret; -} - -static struct ethtool_ops ax88178_ethtool_ops = { - .get_drvinfo = asix_get_drvinfo, - .get_link = asix_get_link, - .get_msglevel = usbnet_get_msglevel, - .set_msglevel = usbnet_set_msglevel, - .get_wol = asix_get_wol, - .set_wol = asix_set_wol, - .get_eeprom_len = asix_get_eeprom_len, - .get_eeprom = asix_get_eeprom, - .get_settings = usbnet_get_settings, - .set_settings = usbnet_set_settings, - .nway_reset = usbnet_nway_reset, -}; - -static int marvell_phy_init(struct usbnet *dev) -{ - struct asix_data *data = (struct asix_data *)&dev->data; - u16 reg; - - devdbg(dev,"marvell_phy_init()"); - - reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_MARVELL_STATUS); - devdbg(dev,"MII_MARVELL_STATUS = 0x%04x", reg); - - asix_mdio_write(dev->net, dev->mii.phy_id, MII_MARVELL_CTRL, - MARVELL_CTRL_RXDELAY | MARVELL_CTRL_TXDELAY); - - if (data->ledmode) { - reg = asix_mdio_read(dev->net, dev->mii.phy_id, - MII_MARVELL_LED_CTRL); - devdbg(dev,"MII_MARVELL_LED_CTRL (1) = 0x%04x", reg); - - reg &= 0xf8ff; - reg |= (1 + 0x0100); - asix_mdio_write(dev->net, dev->mii.phy_id, - MII_MARVELL_LED_CTRL, reg); - - reg = asix_mdio_read(dev->net, dev->mii.phy_id, - MII_MARVELL_LED_CTRL); - devdbg(dev,"MII_MARVELL_LED_CTRL (2) = 0x%04x", reg); - reg &= 0xfc0f; - } - - return 0; -} - -static int marvell_led_status(struct usbnet *dev, u16 speed) -{ - u16 reg = asix_mdio_read(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL); - - devdbg(dev, "marvell_led_status() read 0x%04x", reg); - - /* Clear out the center LED bits - 0x03F0 */ - reg &= 0xfc0f; - - switch (speed) { - case SPEED_1000: - reg |= 0x03e0; - break; - case SPEED_100: - reg |= 0x03b0; - break; - default: - reg |= 0x02f0; - } - - devdbg(dev, "marvell_led_status() writing 0x%04x", reg); - asix_mdio_write(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL, reg); - - return 0; -} - -static int ax88178_link_reset(struct usbnet *dev) -{ - u16 mode; - struct ethtool_cmd ecmd; - struct asix_data *data = (struct asix_data *)&dev->data; - - devdbg(dev,"ax88178_link_reset()"); - - mii_check_media(&dev->mii, 1, 1); - mii_ethtool_gset(&dev->mii, &ecmd); - mode = AX88178_MEDIUM_DEFAULT; - - if (ecmd.speed == SPEED_1000) - mode |= AX_MEDIUM_GM | AX_MEDIUM_ENCK; - else if (ecmd.speed == SPEED_100) - mode |= AX_MEDIUM_PS; - else - mode &= ~(AX_MEDIUM_PS | AX_MEDIUM_GM); - - if (ecmd.duplex == DUPLEX_FULL) - mode |= AX_MEDIUM_FD; - else - mode &= ~AX_MEDIUM_FD; - - devdbg(dev, "ax88178_link_reset() speed: %d duplex: %d setting mode to 0x%04x", ecmd.speed, ecmd.duplex, mode); - - asix_write_medium_mode(dev, mode); - - if (data->phymode == PHY_MODE_MARVELL && data->ledmode) - marvell_led_status(dev, ecmd.speed); - - return 0; -} - -static void ax88178_set_mfb(struct usbnet *dev) -{ - u16 mfb = AX_RX_CTL_MFB_16384; - u16 rxctl; - u16 medium; - int old_rx_urb_size = dev->rx_urb_size; - - if (dev->hard_mtu < 2048) { - dev->rx_urb_size = 2048; - mfb = AX_RX_CTL_MFB_2048; - } else if (dev->hard_mtu < 4096) { - dev->rx_urb_size = 4096; - mfb = AX_RX_CTL_MFB_4096; - } else if (dev->hard_mtu < 8192) { - dev->rx_urb_size = 8192; - mfb = AX_RX_CTL_MFB_8192; - } else if (dev->hard_mtu < 16384) { - dev->rx_urb_size = 16384; - mfb = AX_RX_CTL_MFB_16384; - } - - rxctl = asix_read_rx_ctl(dev); - asix_write_rx_ctl(dev, (rxctl & ~AX_RX_CTL_MFB_16384) | mfb); - - medium = asix_read_medium_status(dev); - if (dev->net->mtu > 1500) - medium |= AX_MEDIUM_JFE; - else - medium &= ~AX_MEDIUM_JFE; - asix_write_medium_mode(dev, medium); - - if (dev->rx_urb_size > old_rx_urb_size) - usbnet_unlink_rx_urbs(dev); -} - -static int ax88178_change_mtu(struct net_device *net, int new_mtu) -{ - struct usbnet *dev = netdev_priv(net); - int ll_mtu = new_mtu + net->hard_header_len + 4; - - devdbg(dev, "ax88178_change_mtu() new_mtu=%d", new_mtu); - - if (new_mtu <= 0 || ll_mtu > 16384) - return -EINVAL; - - if ((ll_mtu % dev->maxpacket) == 0) - return -EDOM; - - net->mtu = new_mtu; - dev->hard_mtu = net->mtu + net->hard_header_len; - ax88178_set_mfb(dev); - - return 0; -} - -static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf) -{ - struct asix_data *data = (struct asix_data *)&dev->data; - int ret; - void *buf; - u16 eeprom; - int gpio0 = 0; - u32 phyid; - - usbnet_get_endpoints(dev,intf); - - buf = kmalloc(6, GFP_KERNEL); - if(!buf) { - dbg ("Cannot allocate memory for buffer"); - ret = -ENOMEM; - goto out1; - } - - eeprom = 0; - asix_read_cmd(dev, AX_CMD_READ_GPIOS, 0, 0, 1, &eeprom); - dbg("GPIO Status: 0x%04x", eeprom); - - asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0, 0, 0, NULL); - asix_read_cmd(dev, AX_CMD_READ_EEPROM, 0x0017, 0, 2, &eeprom); - asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0, 0, 0, NULL); - - dbg("EEPROM index 0x17 is 0x%04x", eeprom); - - if (eeprom == 0xffff) { - data->phymode = PHY_MODE_MARVELL; - data->ledmode = 0; - gpio0 = 1; - } else { - data->phymode = eeprom & 7; - data->ledmode = eeprom >> 8; - gpio0 = (eeprom & 0x80) ? 0 : 1; - } - dbg("GPIO0: %d, PhyMode: %d", gpio0, data->phymode); - - asix_write_gpio(dev, AX_GPIO_RSE | AX_GPIO_GPO_1 | AX_GPIO_GPO1EN, 40); - if ((eeprom >> 8) != 1) { - asix_write_gpio(dev, 0x003c, 30); - asix_write_gpio(dev, 0x001c, 300); - asix_write_gpio(dev, 0x003c, 30); - } else { - dbg("gpio phymode == 1 path"); - asix_write_gpio(dev, AX_GPIO_GPO1EN, 30); - asix_write_gpio(dev, AX_GPIO_GPO1EN | AX_GPIO_GPO_1, 30); - } - - asix_sw_reset(dev, 0); - msleep(150); - - asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD); - msleep(150); - - asix_write_rx_ctl(dev, 0); - - /* Get the MAC address */ - memset(buf, 0, ETH_ALEN); - if ((ret = asix_read_cmd(dev, AX_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); - - /* Initialize MII structure */ - dev->mii.dev = dev->net; - dev->mii.mdio_read = asix_mdio_read; - dev->mii.mdio_write = asix_mdio_write; - dev->mii.phy_id_mask = 0x1f; - dev->mii.reg_num_mask = 0xff; - dev->mii.supports_gmii = 1; - dev->net->do_ioctl = asix_ioctl; - dev->mii.phy_id = asix_get_phy_addr(dev); - dev->net->set_multicast_list = asix_set_multicast; - dev->net->ethtool_ops = &ax88178_ethtool_ops; - dev->net->change_mtu = &ax88178_change_mtu; - - phyid = asix_get_phyid(dev); - dbg("PHYID=0x%08x", phyid); - - if (data->phymode == PHY_MODE_MARVELL) { - marvell_phy_init(dev); - msleep(60); - } - - asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, - BMCR_RESET | BMCR_ANENABLE); - asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, - ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); - asix_mdio_write(dev->net, dev->mii.phy_id, MII_CTRL1000, - ADVERTISE_1000FULL); - - mii_nway_restart(&dev->mii); - - if ((ret = asix_write_medium_mode(dev, AX88178_MEDIUM_DEFAULT)) < 0) - goto out2; - - if ((ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL)) < 0) - goto out2; - - kfree(buf); - - /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ - if (dev->driver_info->flags & FLAG_FRAMING_AX) { - /* hard_mtu is still the default - the device does not support - jumbo eth frames */ - dev->rx_urb_size = 2048; - } - - return 0; - -out2: - kfree(buf); -out1: - return ret; -} - -static const struct driver_info ax8817x_info = { - .description = "ASIX AX8817x USB 2.0 Ethernet", - .bind = ax88172_bind, - .status = asix_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 = ax88172_bind, - .status = asix_status, - .link_reset = ax88172_link_reset, - .reset = ax88172_link_reset, - .flags = FLAG_ETHER, - .data = 0x009f9d9f, -}; - -static const struct driver_info netgear_fa120_info = { - .description = "Netgear FA-120 USB Ethernet", - .bind = ax88172_bind, - .status = asix_status, - .link_reset = ax88172_link_reset, - .reset = ax88172_link_reset, - .flags = FLAG_ETHER, - .data = 0x00130103, -}; - -static const struct driver_info hawking_uf200_info = { - .description = "Hawking UF200 USB Ethernet", - .bind = ax88172_bind, - .status = asix_status, - .link_reset = ax88172_link_reset, - .reset = ax88172_link_reset, - .flags = FLAG_ETHER, - .data = 0x001f1d1f, -}; - -static const struct driver_info ax88772_info = { - .description = "ASIX AX88772 USB 2.0 Ethernet", - .bind = ax88772_bind, - .status = asix_status, - .link_reset = ax88772_link_reset, - .reset = ax88772_link_reset, - .flags = FLAG_ETHER | FLAG_FRAMING_AX, - .rx_fixup = asix_rx_fixup, - .tx_fixup = asix_tx_fixup, -}; - -static const struct driver_info ax88178_info = { - .description = "ASIX AX88178 USB 2.0 Ethernet", - .bind = ax88178_bind, - .status = asix_status, - .link_reset = ax88178_link_reset, - .reset = ax88178_link_reset, - .flags = FLAG_ETHER | FLAG_FRAMING_AX, - .rx_fixup = asix_rx_fixup, - .tx_fixup = asix_tx_fixup, -}; - -static const struct usb_device_id products [] = { -{ - // Linksys USB200M - USB_DEVICE (0x077b, 0x2226), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // Netgear FA120 - USB_DEVICE (0x0846, 0x1040), - .driver_info = (unsigned long) &netgear_fa120_info, -}, { - // DLink DUB-E100 - USB_DEVICE (0x2001, 0x1a00), - .driver_info = (unsigned long) &dlink_dub_e100_info, -}, { - // Intellinet, ST Lab USB Ethernet - USB_DEVICE (0x0b95, 0x1720), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // Hawking UF200, TrendNet TU2-ET100 - USB_DEVICE (0x07b8, 0x420a), - .driver_info = (unsigned long) &hawking_uf200_info, -}, { - // Billionton Systems, USB2AR - USB_DEVICE (0x08dd, 0x90ff), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // ATEN UC210T - USB_DEVICE (0x0557, 0x2009), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // Buffalo LUA-U2-KTX - USB_DEVICE (0x0411, 0x003d), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // Sitecom LN-029 "USB 2.0 10/100 Ethernet adapter" - USB_DEVICE (0x6189, 0x182d), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // corega FEther USB2-TX - USB_DEVICE (0x07aa, 0x0017), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // Surecom EP-1427X-2 - USB_DEVICE (0x1189, 0x0893), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // goodway corp usb gwusb2e - USB_DEVICE (0x1631, 0x6200), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // JVC MP-PRX1 Port Replicator - USB_DEVICE (0x04f1, 0x3008), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // ASIX AX88772 10/100 - USB_DEVICE (0x0b95, 0x7720), - .driver_info = (unsigned long) &ax88772_info, -}, { - // ASIX AX88178 10/100/1000 - USB_DEVICE (0x0b95, 0x1780), - .driver_info = (unsigned long) &ax88178_info, -}, { - // Linksys USB200M Rev 2 - USB_DEVICE (0x13b1, 0x0018), - .driver_info = (unsigned long) &ax88772_info, -}, { - // 0Q0 cable ethernet - USB_DEVICE (0x1557, 0x7720), - .driver_info = (unsigned long) &ax88772_info, -}, { - // DLink DUB-E100 H/W Ver B1 - USB_DEVICE (0x07d1, 0x3c05), - .driver_info = (unsigned long) &ax88772_info, -}, { - // DLink DUB-E100 H/W Ver B1 Alternate - USB_DEVICE (0x2001, 0x3c05), - .driver_info = (unsigned long) &ax88772_info, -}, { - // Linksys USB1000 - USB_DEVICE (0x1737, 0x0039), - .driver_info = (unsigned long) &ax88178_info, -}, { - // IO-DATA ETG-US2 - USB_DEVICE (0x04bb, 0x0930), - .driver_info = (unsigned long) &ax88178_info, -}, - { }, // END -}; -MODULE_DEVICE_TABLE(usb, products); - -static struct usb_driver asix_driver = { - .name = "asix", - .id_table = products, - .probe = usbnet_probe, - .suspend = usbnet_suspend, - .resume = usbnet_resume, - .disconnect = usbnet_disconnect, -}; - -static int __init asix_init(void) -{ - return usb_register(&asix_driver); -} -module_init(asix_init); - -static void __exit asix_exit(void) -{ - usb_deregister(&asix_driver); -} -module_exit(asix_exit); - -MODULE_AUTHOR("David Hollis"); -MODULE_DESCRIPTION("ASIX AX8817X based USB 2.0 Ethernet Devices"); -MODULE_LICENSE("GPL"); - diff --git a/drivers/usb/net/catc.c b/drivers/usb/net/catc.c deleted file mode 100644 index 86e90c59d551..000000000000 --- a/drivers/usb/net/catc.c +++ /dev/null @@ -1,963 +0,0 @@ -/* - * Copyright (c) 2001 Vojtech Pavlik - * - * CATC EL1210A NetMate USB Ethernet driver - * - * Sponsored by SuSE - * - * Based on the work of - * Donald Becker - * - * Old chipset support added by Simon Evans <spse@secret.org.uk> 2002 - * - adds support for Belkin F5U011 - */ - -/* - * 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 - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail: - * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/slab.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <linux/spinlock.h> -#include <linux/ethtool.h> -#include <linux/crc32.h> -#include <linux/bitops.h> -#include <asm/uaccess.h> - -#undef DEBUG - -#include <linux/usb.h> - -/* - * Version information. - */ - -#define DRIVER_VERSION "v2.8" -#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@suse.cz>" -#define DRIVER_DESC "CATC EL1210A NetMate USB Ethernet driver" -#define SHORT_DRIVER_DESC "EL1210A NetMate USB Ethernet" - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -static const char driver_name[] = "catc"; - -/* - * Some defines. - */ - -#define STATS_UPDATE (HZ) /* Time between stats updates */ -#define TX_TIMEOUT (5*HZ) /* Max time the queue can be stopped */ -#define PKT_SZ 1536 /* Max Ethernet packet size */ -#define RX_MAX_BURST 15 /* Max packets per rx buffer (> 0, < 16) */ -#define TX_MAX_BURST 15 /* Max full sized packets per tx buffer (> 0) */ -#define CTRL_QUEUE 16 /* Max control requests in flight (power of two) */ -#define RX_PKT_SZ 1600 /* Max size of receive packet for F5U011 */ - -/* - * Control requests. - */ - -enum control_requests { - ReadMem = 0xf1, - GetMac = 0xf2, - Reset = 0xf4, - SetMac = 0xf5, - SetRxMode = 0xf5, /* F5U011 only */ - WriteROM = 0xf8, - SetReg = 0xfa, - GetReg = 0xfb, - WriteMem = 0xfc, - ReadROM = 0xfd, -}; - -/* - * Registers. - */ - -enum register_offsets { - TxBufCount = 0x20, - RxBufCount = 0x21, - OpModes = 0x22, - TxQed = 0x23, - RxQed = 0x24, - MaxBurst = 0x25, - RxUnit = 0x60, - EthStatus = 0x61, - StationAddr0 = 0x67, - EthStats = 0x69, - LEDCtrl = 0x81, -}; - -enum eth_stats { - TxSingleColl = 0x00, - TxMultiColl = 0x02, - TxExcessColl = 0x04, - RxFramErr = 0x06, -}; - -enum op_mode_bits { - Op3MemWaits = 0x03, - OpLenInclude = 0x08, - OpRxMerge = 0x10, - OpTxMerge = 0x20, - OpWin95bugfix = 0x40, - OpLoopback = 0x80, -}; - -enum rx_filter_bits { - RxEnable = 0x01, - RxPolarity = 0x02, - RxForceOK = 0x04, - RxMultiCast = 0x08, - RxPromisc = 0x10, - AltRxPromisc = 0x20, /* F5U011 uses different bit */ -}; - -enum led_values { - LEDFast = 0x01, - LEDSlow = 0x02, - LEDFlash = 0x03, - LEDPulse = 0x04, - LEDLink = 0x08, -}; - -enum link_status { - LinkNoChange = 0, - LinkGood = 1, - LinkBad = 2 -}; - -/* - * The catc struct. - */ - -#define CTRL_RUNNING 0 -#define RX_RUNNING 1 -#define TX_RUNNING 2 - -struct catc { - struct net_device *netdev; - struct usb_device *usbdev; - - struct net_device_stats stats; - unsigned long flags; - - unsigned int tx_ptr, tx_idx; - unsigned int ctrl_head, ctrl_tail; - spinlock_t tx_lock, ctrl_lock; - - u8 tx_buf[2][TX_MAX_BURST * (PKT_SZ + 2)]; - u8 rx_buf[RX_MAX_BURST * (PKT_SZ + 2)]; - u8 irq_buf[2]; - u8 ctrl_buf[64]; - struct usb_ctrlrequest ctrl_dr; - - struct timer_list timer; - u8 stats_buf[8]; - u16 stats_vals[4]; - unsigned long last_stats; - - u8 multicast[64]; - - struct ctrl_queue { - u8 dir; - u8 request; - u16 value; - u16 index; - void *buf; - int len; - void (*callback)(struct catc *catc, struct ctrl_queue *q); - } ctrl_queue[CTRL_QUEUE]; - - struct urb *tx_urb, *rx_urb, *irq_urb, *ctrl_urb; - - u8 is_f5u011; /* Set if device is an F5U011 */ - u8 rxmode[2]; /* Used for F5U011 */ - atomic_t recq_sz; /* Used for F5U011 - counter of waiting rx packets */ -}; - -/* - * Useful macros. - */ - -#define catc_get_mac(catc, mac) catc_ctrl_msg(catc, USB_DIR_IN, GetMac, 0, 0, mac, 6) -#define catc_reset(catc) catc_ctrl_msg(catc, USB_DIR_OUT, Reset, 0, 0, NULL, 0) -#define catc_set_reg(catc, reg, val) catc_ctrl_msg(catc, USB_DIR_OUT, SetReg, val, reg, NULL, 0) -#define catc_get_reg(catc, reg, buf) catc_ctrl_msg(catc, USB_DIR_IN, GetReg, 0, reg, buf, 1) -#define catc_write_mem(catc, addr, buf, size) catc_ctrl_msg(catc, USB_DIR_OUT, WriteMem, 0, addr, buf, size) -#define catc_read_mem(catc, addr, buf, size) catc_ctrl_msg(catc, USB_DIR_IN, ReadMem, 0, addr, buf, size) - -#define f5u011_rxmode(catc, rxmode) catc_ctrl_msg(catc, USB_DIR_OUT, SetRxMode, 0, 1, rxmode, 2) -#define f5u011_rxmode_async(catc, rxmode) catc_ctrl_async(catc, USB_DIR_OUT, SetRxMode, 0, 1, &rxmode, 2, NULL) -#define f5u011_mchash_async(catc, hash) catc_ctrl_async(catc, USB_DIR_OUT, SetRxMode, 0, 2, &hash, 8, NULL) - -#define catc_set_reg_async(catc, reg, val) catc_ctrl_async(catc, USB_DIR_OUT, SetReg, val, reg, NULL, 0, NULL) -#define catc_get_reg_async(catc, reg, cb) catc_ctrl_async(catc, USB_DIR_IN, GetReg, 0, reg, NULL, 1, cb) -#define catc_write_mem_async(catc, addr, buf, size) catc_ctrl_async(catc, USB_DIR_OUT, WriteMem, 0, addr, buf, size, NULL) - -/* - * Receive routines. - */ - -static void catc_rx_done(struct urb *urb) -{ - struct catc *catc = urb->context; - u8 *pkt_start = urb->transfer_buffer; - struct sk_buff *skb; - int pkt_len, pkt_offset = 0; - - if (!catc->is_f5u011) { - clear_bit(RX_RUNNING, &catc->flags); - pkt_offset = 2; - } - - if (urb->status) { - dbg("rx_done, status %d, length %d", urb->status, urb->actual_length); - return; - } - - do { - if(!catc->is_f5u011) { - pkt_len = le16_to_cpup((__le16*)pkt_start); - if (pkt_len > urb->actual_length) { - catc->stats.rx_length_errors++; - catc->stats.rx_errors++; - break; - } - } else { - pkt_len = urb->actual_length; - } - - if (!(skb = dev_alloc_skb(pkt_len))) - return; - - eth_copy_and_sum(skb, pkt_start + pkt_offset, pkt_len, 0); - skb_put(skb, pkt_len); - - skb->protocol = eth_type_trans(skb, catc->netdev); - netif_rx(skb); - - catc->stats.rx_packets++; - catc->stats.rx_bytes += pkt_len; - - /* F5U011 only does one packet per RX */ - if (catc->is_f5u011) - break; - pkt_start += (((pkt_len + 1) >> 6) + 1) << 6; - - } while (pkt_start - (u8 *) urb->transfer_buffer < urb->actual_length); - - catc->netdev->last_rx = jiffies; - - if (catc->is_f5u011) { - if (atomic_read(&catc->recq_sz)) { - int status; - atomic_dec(&catc->recq_sz); - dbg("getting extra packet"); - urb->dev = catc->usbdev; - if ((status = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { - dbg("submit(rx_urb) status %d", status); - } - } else { - clear_bit(RX_RUNNING, &catc->flags); - } - } -} - -static void catc_irq_done(struct urb *urb) -{ - struct catc *catc = urb->context; - u8 *data = urb->transfer_buffer; - int status; - unsigned int hasdata = 0, linksts = LinkNoChange; - - if (!catc->is_f5u011) { - hasdata = data[1] & 0x80; - if (data[1] & 0x40) - linksts = LinkGood; - else if (data[1] & 0x20) - linksts = LinkBad; - } else { - hasdata = (unsigned int)(be16_to_cpup((__be16*)data) & 0x0fff); - if (data[0] == 0x90) - linksts = LinkGood; - else if (data[0] == 0xA0) - linksts = LinkBad; - } - - switch (urb->status) { - case 0: /* success */ - break; - case -ECONNRESET: /* unlink */ - case -ENOENT: - case -ESHUTDOWN: - return; - /* -EPIPE: should clear the halt */ - default: /* error */ - dbg("irq_done, status %d, data %02x %02x.", urb->status, data[0], data[1]); - goto resubmit; - } - - if (linksts == LinkGood) { - netif_carrier_on(catc->netdev); - dbg("link ok"); - } - - if (linksts == LinkBad) { - netif_carrier_off(catc->netdev); - dbg("link bad"); - } - - if (hasdata) { - if (test_and_set_bit(RX_RUNNING, &catc->flags)) { - if (catc->is_f5u011) - atomic_inc(&catc->recq_sz); - } else { - catc->rx_urb->dev = catc->usbdev; - if ((status = usb_submit_urb(catc->rx_urb, GFP_ATOMIC)) < 0) { - err("submit(rx_urb) status %d", status); - } - } - } -resubmit: - status = usb_submit_urb (urb, GFP_ATOMIC); - if (status) - err ("can't resubmit intr, %s-%s, status %d", - catc->usbdev->bus->bus_name, - catc->usbdev->devpath, status); -} - -/* - * Transmit routines. - */ - -static int catc_tx_run(struct catc *catc) -{ - int status; - - if (catc->is_f5u011) - catc->tx_ptr = (catc->tx_ptr + 63) & ~63; - - catc->tx_urb->transfer_buffer_length = catc->tx_ptr; - catc->tx_urb->transfer_buffer = catc->tx_buf[catc->tx_idx]; - catc->tx_urb->dev = catc->usbdev; - - if ((status = usb_submit_urb(catc->tx_urb, GFP_ATOMIC)) < 0) - err("submit(tx_urb), status %d", status); - - catc->tx_idx = !catc->tx_idx; - catc->tx_ptr = 0; - - catc->netdev->trans_start = jiffies; - return status; -} - -static void catc_tx_done(struct urb *urb) -{ - struct catc *catc = urb->context; - unsigned long flags; - int r; - - if (urb->status == -ECONNRESET) { - dbg("Tx Reset."); - urb->status = 0; - catc->netdev->trans_start = jiffies; - catc->stats.tx_errors++; - clear_bit(TX_RUNNING, &catc->flags); - netif_wake_queue(catc->netdev); - return; - } - - if (urb->status) { - dbg("tx_done, status %d, length %d", urb->status, urb->actual_length); - return; - } - - spin_lock_irqsave(&catc->tx_lock, flags); - - if (catc->tx_ptr) { - r = catc_tx_run(catc); - if (unlikely(r < 0)) - clear_bit(TX_RUNNING, &catc->flags); - } else { - clear_bit(TX_RUNNING, &catc->flags); - } - - netif_wake_queue(catc->netdev); - - spin_unlock_irqrestore(&catc->tx_lock, flags); -} - -static int catc_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev) -{ - struct catc *catc = netdev_priv(netdev); - unsigned long flags; - int r = 0; - char *tx_buf; - - spin_lock_irqsave(&catc->tx_lock, flags); - - catc->tx_ptr = (((catc->tx_ptr - 1) >> 6) + 1) << 6; - tx_buf = catc->tx_buf[catc->tx_idx] + catc->tx_ptr; - *((u16*)tx_buf) = (catc->is_f5u011) ? cpu_to_be16((u16)skb->len) : cpu_to_le16((u16)skb->len); - skb_copy_from_linear_data(skb, tx_buf + 2, skb->len); - catc->tx_ptr += skb->len + 2; - - if (!test_and_set_bit(TX_RUNNING, &catc->flags)) { - r = catc_tx_run(catc); - if (r < 0) - clear_bit(TX_RUNNING, &catc->flags); - } - - if ((catc->is_f5u011 && catc->tx_ptr) - || (catc->tx_ptr >= ((TX_MAX_BURST - 1) * (PKT_SZ + 2)))) - netif_stop_queue(netdev); - - spin_unlock_irqrestore(&catc->tx_lock, flags); - - if (r >= 0) { - catc->stats.tx_bytes += skb->len; - catc->stats.tx_packets++; - } - - dev_kfree_skb(skb); - - return 0; -} - -static void catc_tx_timeout(struct net_device *netdev) -{ - struct catc *catc = netdev_priv(netdev); - - warn("Transmit timed out."); - usb_unlink_urb(catc->tx_urb); -} - -/* - * Control messages. - */ - -static int catc_ctrl_msg(struct catc *catc, u8 dir, u8 request, u16 value, u16 index, void *buf, int len) -{ - int retval = usb_control_msg(catc->usbdev, - dir ? usb_rcvctrlpipe(catc->usbdev, 0) : usb_sndctrlpipe(catc->usbdev, 0), - request, 0x40 | dir, value, index, buf, len, 1000); - return retval < 0 ? retval : 0; -} - -static void catc_ctrl_run(struct catc *catc) -{ - struct ctrl_queue *q = catc->ctrl_queue + catc->ctrl_tail; - struct usb_device *usbdev = catc->usbdev; - struct urb *urb = catc->ctrl_urb; - struct usb_ctrlrequest *dr = &catc->ctrl_dr; - int status; - - dr->bRequest = q->request; - dr->bRequestType = 0x40 | q->dir; - dr->wValue = cpu_to_le16(q->value); - dr->wIndex = cpu_to_le16(q->index); - dr->wLength = cpu_to_le16(q->len); - - urb->pipe = q->dir ? usb_rcvctrlpipe(usbdev, 0) : usb_sndctrlpipe(usbdev, 0); - urb->transfer_buffer_length = q->len; - urb->transfer_buffer = catc->ctrl_buf; - urb->setup_packet = (void *) dr; - urb->dev = usbdev; - - if (!q->dir && q->buf && q->len) - memcpy(catc->ctrl_buf, q->buf, q->len); - - if ((status = usb_submit_urb(catc->ctrl_urb, GFP_KERNEL))) - err("submit(ctrl_urb) status %d", status); -} - -static void catc_ctrl_done(struct urb *urb) -{ - struct catc *catc = urb->context; - struct ctrl_queue *q; - unsigned long flags; - - if (urb->status) - dbg("ctrl_done, status %d, len %d.", urb->status, urb->actual_length); - - spin_lock_irqsave(&catc->ctrl_lock, flags); - - q = catc->ctrl_queue + catc->ctrl_tail; - - if (q->dir) { - if (q->buf && q->len) - memcpy(q->buf, catc->ctrl_buf, q->len); - else - q->buf = catc->ctrl_buf; - } - - if (q->callback) - q->callback(catc, q); - - catc->ctrl_tail = (catc->ctrl_tail + 1) & (CTRL_QUEUE - 1); - - if (catc->ctrl_head != catc->ctrl_tail) - catc_ctrl_run(catc); - else - clear_bit(CTRL_RUNNING, &catc->flags); - - spin_unlock_irqrestore(&catc->ctrl_lock, flags); -} - -static int catc_ctrl_async(struct catc *catc, u8 dir, u8 request, u16 value, - u16 index, void *buf, int len, void (*callback)(struct catc *catc, struct ctrl_queue *q)) -{ - struct ctrl_queue *q; - int retval = 0; - unsigned long flags; - - spin_lock_irqsave(&catc->ctrl_lock, flags); - - q = catc->ctrl_queue + catc->ctrl_head; - - q->dir = dir; - q->request = request; - q->value = value; - q->index = index; - q->buf = buf; - q->len = len; - q->callback = callback; - - catc->ctrl_head = (catc->ctrl_head + 1) & (CTRL_QUEUE - 1); - - if (catc->ctrl_head == catc->ctrl_tail) { - err("ctrl queue full"); - catc->ctrl_tail = (catc->ctrl_tail + 1) & (CTRL_QUEUE - 1); - retval = -1; - } - - if (!test_and_set_bit(CTRL_RUNNING, &catc->flags)) - catc_ctrl_run(catc); - - spin_unlock_irqrestore(&catc->ctrl_lock, flags); - - return retval; -} - -/* - * Statistics. - */ - -static void catc_stats_done(struct catc *catc, struct ctrl_queue *q) -{ - int index = q->index - EthStats; - u16 data, last; - - catc->stats_buf[index] = *((char *)q->buf); - - if (index & 1) - return; - - data = ((u16)catc->stats_buf[index] << 8) | catc->stats_buf[index + 1]; - last = catc->stats_vals[index >> 1]; - - switch (index) { - case TxSingleColl: - case TxMultiColl: - catc->stats.collisions += data - last; - break; - case TxExcessColl: - catc->stats.tx_aborted_errors += data - last; - catc->stats.tx_errors += data - last; - break; - case RxFramErr: - catc->stats.rx_frame_errors += data - last; - catc->stats.rx_errors += data - last; - break; - } - - catc->stats_vals[index >> 1] = data; -} - -static void catc_stats_timer(unsigned long data) -{ - struct catc *catc = (void *) data; - int i; - - for (i = 0; i < 8; i++) - catc_get_reg_async(catc, EthStats + 7 - i, catc_stats_done); - - mod_timer(&catc->timer, jiffies + STATS_UPDATE); -} - -static struct net_device_stats *catc_get_stats(struct net_device *netdev) -{ - struct catc *catc = netdev_priv(netdev); - return &catc->stats; -} - -/* - * Receive modes. Broadcast, Multicast, Promisc. - */ - -static void catc_multicast(unsigned char *addr, u8 *multicast) -{ - u32 crc; - - crc = ether_crc_le(6, addr); - multicast[(crc >> 3) & 0x3f] |= 1 << (crc & 7); -} - -static void catc_set_multicast_list(struct net_device *netdev) -{ - struct catc *catc = netdev_priv(netdev); - struct dev_mc_list *mc; - u8 broadcast[6]; - u8 rx = RxEnable | RxPolarity | RxMultiCast; - int i; - - memset(broadcast, 0xff, 6); - memset(catc->multicast, 0, 64); - - catc_multicast(broadcast, catc->multicast); - catc_multicast(netdev->dev_addr, catc->multicast); - - if (netdev->flags & IFF_PROMISC) { - memset(catc->multicast, 0xff, 64); - rx |= (!catc->is_f5u011) ? RxPromisc : AltRxPromisc; - } - - if (netdev->flags & IFF_ALLMULTI) { - memset(catc->multicast, 0xff, 64); - } else { - for (i = 0, mc = netdev->mc_list; mc && i < netdev->mc_count; i++, mc = mc->next) { - u32 crc = ether_crc_le(6, mc->dmi_addr); - if (!catc->is_f5u011) { - catc->multicast[(crc >> 3) & 0x3f] |= 1 << (crc & 7); - } else { - catc->multicast[7-(crc >> 29)] |= 1 << ((crc >> 26) & 7); - } - } - } - if (!catc->is_f5u011) { - catc_set_reg_async(catc, RxUnit, rx); - catc_write_mem_async(catc, 0xfa80, catc->multicast, 64); - } else { - f5u011_mchash_async(catc, catc->multicast); - if (catc->rxmode[0] != rx) { - catc->rxmode[0] = rx; - dbg("Setting RX mode to %2.2X %2.2X", catc->rxmode[0], catc->rxmode[1]); - f5u011_rxmode_async(catc, catc->rxmode); - } - } -} - -static void catc_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - struct catc *catc = netdev_priv(dev); - strncpy(info->driver, driver_name, ETHTOOL_BUSINFO_LEN); - strncpy(info->version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN); - usb_make_path (catc->usbdev, info->bus_info, sizeof info->bus_info); -} - -static int catc_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct catc *catc = netdev_priv(dev); - if (!catc->is_f5u011) - return -EOPNOTSUPP; - - cmd->supported = SUPPORTED_10baseT_Half | SUPPORTED_TP; - cmd->advertising = ADVERTISED_10baseT_Half | ADVERTISED_TP; - cmd->speed = SPEED_10; - cmd->duplex = DUPLEX_HALF; - cmd->port = PORT_TP; - cmd->phy_address = 0; - cmd->transceiver = XCVR_INTERNAL; - cmd->autoneg = AUTONEG_DISABLE; - cmd->maxtxpkt = 1; - cmd->maxrxpkt = 1; - return 0; -} - -static struct ethtool_ops ops = { - .get_drvinfo = catc_get_drvinfo, - .get_settings = catc_get_settings, - .get_link = ethtool_op_get_link -}; - -/* - * Open, close. - */ - -static int catc_open(struct net_device *netdev) -{ - struct catc *catc = netdev_priv(netdev); - int status; - - catc->irq_urb->dev = catc->usbdev; - if ((status = usb_submit_urb(catc->irq_urb, GFP_KERNEL)) < 0) { - err("submit(irq_urb) status %d", status); - return -1; - } - - netif_start_queue(netdev); - - if (!catc->is_f5u011) - mod_timer(&catc->timer, jiffies + STATS_UPDATE); - - return 0; -} - -static int catc_stop(struct net_device *netdev) -{ - struct catc *catc = netdev_priv(netdev); - - netif_stop_queue(netdev); - - if (!catc->is_f5u011) - del_timer_sync(&catc->timer); - - usb_kill_urb(catc->rx_urb); - usb_kill_urb(catc->tx_urb); - usb_kill_urb(catc->irq_urb); - usb_kill_urb(catc->ctrl_urb); - - return 0; -} - -/* - * USB probe, disconnect. - */ - -static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id) -{ - struct usb_device *usbdev = interface_to_usbdev(intf); - struct net_device *netdev; - struct catc *catc; - u8 broadcast[6]; - int i, pktsz; - - if (usb_set_interface(usbdev, - intf->altsetting->desc.bInterfaceNumber, 1)) { - err("Can't set altsetting 1."); - return -EIO; - } - - netdev = alloc_etherdev(sizeof(struct catc)); - if (!netdev) - return -ENOMEM; - - catc = netdev_priv(netdev); - - netdev->open = catc_open; - netdev->hard_start_xmit = catc_hard_start_xmit; - netdev->stop = catc_stop; - netdev->get_stats = catc_get_stats; - netdev->tx_timeout = catc_tx_timeout; - netdev->watchdog_timeo = TX_TIMEOUT; - netdev->set_multicast_list = catc_set_multicast_list; - SET_ETHTOOL_OPS(netdev, &ops); - - catc->usbdev = usbdev; - catc->netdev = netdev; - - spin_lock_init(&catc->tx_lock); - spin_lock_init(&catc->ctrl_lock); - - init_timer(&catc->timer); - catc->timer.data = (long) catc; - catc->timer.function = catc_stats_timer; - - catc->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL); - catc->tx_urb = usb_alloc_urb(0, GFP_KERNEL); - catc->rx_urb = usb_alloc_urb(0, GFP_KERNEL); - catc->irq_urb = usb_alloc_urb(0, GFP_KERNEL); - if ((!catc->ctrl_urb) || (!catc->tx_urb) || - (!catc->rx_urb) || (!catc->irq_urb)) { - err("No free urbs available."); - usb_free_urb(catc->ctrl_urb); - usb_free_urb(catc->tx_urb); - usb_free_urb(catc->rx_urb); - usb_free_urb(catc->irq_urb); - free_netdev(netdev); - return -ENOMEM; - } - - /* The F5U011 has the same vendor/product as the netmate but a device version of 0x130 */ - if (le16_to_cpu(usbdev->descriptor.idVendor) == 0x0423 && - le16_to_cpu(usbdev->descriptor.idProduct) == 0xa && - le16_to_cpu(catc->usbdev->descriptor.bcdDevice) == 0x0130) { - dbg("Testing for f5u011"); - catc->is_f5u011 = 1; - atomic_set(&catc->recq_sz, 0); - pktsz = RX_PKT_SZ; - } else { - pktsz = RX_MAX_BURST * (PKT_SZ + 2); - } - - usb_fill_control_urb(catc->ctrl_urb, usbdev, usb_sndctrlpipe(usbdev, 0), - NULL, NULL, 0, catc_ctrl_done, catc); - - usb_fill_bulk_urb(catc->tx_urb, usbdev, usb_sndbulkpipe(usbdev, 1), - NULL, 0, catc_tx_done, catc); - - usb_fill_bulk_urb(catc->rx_urb, usbdev, usb_rcvbulkpipe(usbdev, 1), - catc->rx_buf, pktsz, catc_rx_done, catc); - - usb_fill_int_urb(catc->irq_urb, usbdev, usb_rcvintpipe(usbdev, 2), - catc->irq_buf, 2, catc_irq_done, catc, 1); - - if (!catc->is_f5u011) { - dbg("Checking memory size\n"); - - i = 0x12345678; - catc_write_mem(catc, 0x7a80, &i, 4); - i = 0x87654321; - catc_write_mem(catc, 0xfa80, &i, 4); - catc_read_mem(catc, 0x7a80, &i, 4); - - switch (i) { - case 0x12345678: - catc_set_reg(catc, TxBufCount, 8); - catc_set_reg(catc, RxBufCount, 32); - dbg("64k Memory\n"); - break; - default: - warn("Couldn't detect memory size, assuming 32k"); - case 0x87654321: - catc_set_reg(catc, TxBufCount, 4); - catc_set_reg(catc, RxBufCount, 16); - dbg("32k Memory\n"); - break; - } - - dbg("Getting MAC from SEEROM."); - - catc_get_mac(catc, netdev->dev_addr); - - dbg("Setting MAC into registers."); - - for (i = 0; i < 6; i++) - catc_set_reg(catc, StationAddr0 - i, netdev->dev_addr[i]); - - dbg("Filling the multicast list."); - - memset(broadcast, 0xff, 6); - catc_multicast(broadcast, catc->multicast); - catc_multicast(netdev->dev_addr, catc->multicast); - catc_write_mem(catc, 0xfa80, catc->multicast, 64); - - dbg("Clearing error counters."); - - for (i = 0; i < 8; i++) - catc_set_reg(catc, EthStats + i, 0); - catc->last_stats = jiffies; - - dbg("Enabling."); - - catc_set_reg(catc, MaxBurst, RX_MAX_BURST); - catc_set_reg(catc, OpModes, OpTxMerge | OpRxMerge | OpLenInclude | Op3MemWaits); - catc_set_reg(catc, LEDCtrl, LEDLink); - catc_set_reg(catc, RxUnit, RxEnable | RxPolarity | RxMultiCast); - } else { - dbg("Performing reset\n"); - catc_reset(catc); - catc_get_mac(catc, netdev->dev_addr); - - dbg("Setting RX Mode"); - catc->rxmode[0] = RxEnable | RxPolarity | RxMultiCast; - catc->rxmode[1] = 0; - f5u011_rxmode(catc, catc->rxmode); - } - dbg("Init done."); - printk(KERN_INFO "%s: %s USB Ethernet at usb-%s-%s, ", - netdev->name, (catc->is_f5u011) ? "Belkin F5U011" : "CATC EL1210A NetMate", - usbdev->bus->bus_name, usbdev->devpath); - for (i = 0; i < 5; i++) printk("%2.2x:", netdev->dev_addr[i]); - printk("%2.2x.\n", netdev->dev_addr[i]); - usb_set_intfdata(intf, catc); - - SET_NETDEV_DEV(netdev, &intf->dev); - if (register_netdev(netdev) != 0) { - usb_set_intfdata(intf, NULL); - usb_free_urb(catc->ctrl_urb); - usb_free_urb(catc->tx_urb); - usb_free_urb(catc->rx_urb); - usb_free_urb(catc->irq_urb); - free_netdev(netdev); - return -EIO; - } - return 0; -} - -static void catc_disconnect(struct usb_interface *intf) -{ - struct catc *catc = usb_get_intfdata(intf); - - usb_set_intfdata(intf, NULL); - if (catc) { - unregister_netdev(catc->netdev); - usb_free_urb(catc->ctrl_urb); - usb_free_urb(catc->tx_urb); - usb_free_urb(catc->rx_urb); - usb_free_urb(catc->irq_urb); - free_netdev(catc->netdev); - } -} - -/* - * Module functions and tables. - */ - -static struct usb_device_id catc_id_table [] = { - { USB_DEVICE(0x0423, 0xa) }, /* CATC Netmate, Belkin F5U011 */ - { USB_DEVICE(0x0423, 0xc) }, /* CATC Netmate II, Belkin F5U111 */ - { USB_DEVICE(0x08d1, 0x1) }, /* smartBridges smartNIC */ - { } -}; - -MODULE_DEVICE_TABLE(usb, catc_id_table); - -static struct usb_driver catc_driver = { - .name = driver_name, - .probe = catc_probe, - .disconnect = catc_disconnect, - .id_table = catc_id_table, -}; - -static int __init catc_init(void) -{ - int result = usb_register(&catc_driver); - if (result == 0) - info(DRIVER_VERSION " " DRIVER_DESC); - return result; -} - -static void __exit catc_exit(void) -{ - usb_deregister(&catc_driver); -} - -module_init(catc_init); -module_exit(catc_exit); diff --git a/drivers/usb/net/cdc_ether.c b/drivers/usb/net/cdc_ether.c deleted file mode 100644 index 5a21f06bf8a5..000000000000 --- a/drivers/usb/net/cdc_ether.c +++ /dev/null @@ -1,570 +0,0 @@ -/* - * CDC Ethernet based networking peripherals - * Copyright (C) 2003-2005 by David Brownell - * Copyright (C) 2006 by Ole Andre Vadla Ravnas (ActiveSync) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -// #define DEBUG // error path messages, extra info -// #define VERBOSE // more; success messages - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/ctype.h> -#include <linux/ethtool.h> -#include <linux/workqueue.h> -#include <linux/mii.h> -#include <linux/usb.h> -#include <linux/usb/cdc.h> - -#include "usbnet.h" - - -#if defined(CONFIG_USB_NET_RNDIS_HOST) || defined(CONFIG_USB_NET_RNDIS_HOST_MODULE) - -static int is_rndis(struct usb_interface_descriptor *desc) -{ - return desc->bInterfaceClass == USB_CLASS_COMM - && desc->bInterfaceSubClass == 2 - && desc->bInterfaceProtocol == 0xff; -} - -static int is_activesync(struct usb_interface_descriptor *desc) -{ - return desc->bInterfaceClass == USB_CLASS_MISC - && desc->bInterfaceSubClass == 1 - && desc->bInterfaceProtocol == 1; -} - -#else - -#define is_rndis(desc) 0 -#define is_activesync(desc) 0 - -#endif - -/* - * probes control interface, claims data interface, collects the bulk - * endpoints, activates data interface (if needed), maybe sets MTU. - * all pure cdc, except for certain firmware workarounds, and knowing - * that rndis uses one different rule. - */ -int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) -{ - u8 *buf = intf->cur_altsetting->extra; - int len = intf->cur_altsetting->extralen; - struct usb_interface_descriptor *d; - struct cdc_state *info = (void *) &dev->data; - int status; - int rndis; - struct usb_driver *driver = driver_of(intf); - - if (sizeof dev->data < sizeof *info) - return -EDOM; - - /* expect strict spec conformance for the descriptors, but - * cope with firmware which stores them in the wrong place - */ - if (len == 0 && dev->udev->actconfig->extralen) { - /* Motorola SB4100 (and others: Brad Hards says it's - * from a Broadcom design) put CDC descriptors here - */ - buf = dev->udev->actconfig->extra; - len = dev->udev->actconfig->extralen; - if (len) - dev_dbg(&intf->dev, - "CDC descriptors on config\n"); - } - - /* this assumes that if there's a non-RNDIS vendor variant - * of cdc-acm, it'll fail RNDIS requests cleanly. - */ - rndis = is_rndis(&intf->cur_altsetting->desc) - || is_activesync(&intf->cur_altsetting->desc); - - memset(info, 0, sizeof *info); - info->control = intf; - while (len > 3) { - if (buf [1] != USB_DT_CS_INTERFACE) - goto next_desc; - - /* use bDescriptorSubType to identify the CDC descriptors. - * We expect devices with CDC header and union descriptors. - * For CDC Ethernet we need the ethernet descriptor. - * For RNDIS, ignore two (pointless) CDC modem descriptors - * in favor of a complicated OID-based RPC scheme doing what - * CDC Ethernet achieves with a simple descriptor. - */ - switch (buf [2]) { - case USB_CDC_HEADER_TYPE: - if (info->header) { - dev_dbg(&intf->dev, "extra CDC header\n"); - goto bad_desc; - } - info->header = (void *) buf; - if (info->header->bLength != sizeof *info->header) { - dev_dbg(&intf->dev, "CDC header len %u\n", - info->header->bLength); - goto bad_desc; - } - break; - case USB_CDC_ACM_TYPE: - /* paranoia: disambiguate a "real" vendor-specific - * modem interface from an RNDIS non-modem. - */ - if (rndis) { - struct usb_cdc_acm_descriptor *d; - - d = (void *) buf; - if (d->bmCapabilities) { - dev_dbg(&intf->dev, - "ACM capabilities %02x, " - "not really RNDIS?\n", - d->bmCapabilities); - goto bad_desc; - } - } - break; - case USB_CDC_UNION_TYPE: - if (info->u) { - dev_dbg(&intf->dev, "extra CDC union\n"); - goto bad_desc; - } - info->u = (void *) buf; - if (info->u->bLength != sizeof *info->u) { - dev_dbg(&intf->dev, "CDC union len %u\n", - info->u->bLength); - goto bad_desc; - } - - /* we need a master/control interface (what we're - * probed with) and a slave/data interface; union - * descriptors sort this all out. - */ - info->control = usb_ifnum_to_if(dev->udev, - info->u->bMasterInterface0); - info->data = usb_ifnum_to_if(dev->udev, - info->u->bSlaveInterface0); - if (!info->control || !info->data) { - dev_dbg(&intf->dev, - "master #%u/%p slave #%u/%p\n", - info->u->bMasterInterface0, - info->control, - info->u->bSlaveInterface0, - info->data); - goto bad_desc; - } - if (info->control != intf) { - dev_dbg(&intf->dev, "bogus CDC Union\n"); - /* Ambit USB Cable Modem (and maybe others) - * interchanges master and slave interface. - */ - if (info->data == intf) { - info->data = info->control; - info->control = intf; - } else - goto bad_desc; - } - - /* a data interface altsetting does the real i/o */ - d = &info->data->cur_altsetting->desc; - if (d->bInterfaceClass != USB_CLASS_CDC_DATA) { - dev_dbg(&intf->dev, "slave class %u\n", - d->bInterfaceClass); - goto bad_desc; - } - break; - case USB_CDC_ETHERNET_TYPE: - if (info->ether) { - dev_dbg(&intf->dev, "extra CDC ether\n"); - goto bad_desc; - } - info->ether = (void *) buf; - if (info->ether->bLength != sizeof *info->ether) { - dev_dbg(&intf->dev, "CDC ether len %u\n", - info->ether->bLength); - goto bad_desc; - } - dev->hard_mtu = le16_to_cpu( - info->ether->wMaxSegmentSize); - /* because of Zaurus, we may be ignoring the host - * side link address we were given. - */ - break; - } -next_desc: - len -= buf [0]; /* bLength */ - buf += buf [0]; - } - - /* Microsoft ActiveSync based RNDIS devices lack the CDC descriptors, - * so we'll hard-wire the interfaces and not check for descriptors. - */ - if (is_activesync(&intf->cur_altsetting->desc) && !info->u) { - info->control = usb_ifnum_to_if(dev->udev, 0); - info->data = usb_ifnum_to_if(dev->udev, 1); - if (!info->control || !info->data) { - dev_dbg(&intf->dev, - "activesync: master #0/%p slave #1/%p\n", - info->control, - info->data); - goto bad_desc; - } - - } else if (!info->header || !info->u || (!rndis && !info->ether)) { - dev_dbg(&intf->dev, "missing cdc %s%s%sdescriptor\n", - info->header ? "" : "header ", - info->u ? "" : "union ", - info->ether ? "" : "ether "); - goto bad_desc; - } - - /* claim data interface and set it up ... with side effects. - * network traffic can't flow until an altsetting is enabled. - */ - status = usb_driver_claim_interface(driver, info->data, dev); - if (status < 0) - return status; - status = usbnet_get_endpoints(dev, info->data); - if (status < 0) { - /* ensure immediate exit from usbnet_disconnect */ - usb_set_intfdata(info->data, NULL); - usb_driver_release_interface(driver, info->data); - return status; - } - - /* status endpoint: optional for CDC Ethernet, not RNDIS (or ACM) */ - dev->status = NULL; - if (info->control->cur_altsetting->desc.bNumEndpoints == 1) { - struct usb_endpoint_descriptor *desc; - - dev->status = &info->control->cur_altsetting->endpoint [0]; - desc = &dev->status->desc; - if (!usb_endpoint_is_int_in(desc) - || (le16_to_cpu(desc->wMaxPacketSize) - < sizeof(struct usb_cdc_notification)) - || !desc->bInterval) { - dev_dbg(&intf->dev, "bad notification endpoint\n"); - dev->status = NULL; - } - } - if (rndis && !dev->status) { - dev_dbg(&intf->dev, "missing RNDIS status endpoint\n"); - usb_set_intfdata(info->data, NULL); - usb_driver_release_interface(driver, info->data); - return -ENODEV; - } - return 0; - -bad_desc: - dev_info(&dev->udev->dev, "bad CDC descriptors\n"); - return -ENODEV; -} -EXPORT_SYMBOL_GPL(usbnet_generic_cdc_bind); - -void usbnet_cdc_unbind(struct usbnet *dev, struct usb_interface *intf) -{ - struct cdc_state *info = (void *) &dev->data; - struct usb_driver *driver = driver_of(intf); - - /* disconnect master --> disconnect slave */ - if (intf == info->control && info->data) { - /* ensure immediate exit from usbnet_disconnect */ - usb_set_intfdata(info->data, NULL); - usb_driver_release_interface(driver, info->data); - info->data = NULL; - } - - /* and vice versa (just in case) */ - else if (intf == info->data && info->control) { - /* ensure immediate exit from usbnet_disconnect */ - usb_set_intfdata(info->control, NULL); - usb_driver_release_interface(driver, info->control); - info->control = NULL; - } -} -EXPORT_SYMBOL_GPL(usbnet_cdc_unbind); - - -/*------------------------------------------------------------------------- - * - * Communications Device Class, Ethernet Control model - * - * Takes two interfaces. The DATA interface is inactive till an altsetting - * is selected. Configuration data includes class descriptors. There's - * an optional status endpoint on the control interface. - * - * This should interop with whatever the 2.4 "CDCEther.c" driver - * (by Brad Hards) talked with, with more functionality. - * - *-------------------------------------------------------------------------*/ - -static void dumpspeed(struct usbnet *dev, __le32 *speeds) -{ - if (netif_msg_timer(dev)) - devinfo(dev, "link speeds: %u kbps up, %u kbps down", - __le32_to_cpu(speeds[0]) / 1000, - __le32_to_cpu(speeds[1]) / 1000); -} - -static void cdc_status(struct usbnet *dev, struct urb *urb) -{ - struct usb_cdc_notification *event; - - if (urb->actual_length < sizeof *event) - return; - - /* SPEED_CHANGE can get split into two 8-byte packets */ - if (test_and_clear_bit(EVENT_STS_SPLIT, &dev->flags)) { - dumpspeed(dev, (__le32 *) urb->transfer_buffer); - return; - } - - event = urb->transfer_buffer; - switch (event->bNotificationType) { - case USB_CDC_NOTIFY_NETWORK_CONNECTION: - if (netif_msg_timer(dev)) - devdbg(dev, "CDC: carrier %s", - event->wValue ? "on" : "off"); - if (event->wValue) - netif_carrier_on(dev->net); - else - netif_carrier_off(dev->net); - break; - case USB_CDC_NOTIFY_SPEED_CHANGE: /* tx/rx rates */ - if (netif_msg_timer(dev)) - devdbg(dev, "CDC: speed change (len %d)", - urb->actual_length); - if (urb->actual_length != (sizeof *event + 8)) - set_bit(EVENT_STS_SPLIT, &dev->flags); - else - dumpspeed(dev, (__le32 *) &event[1]); - break; - /* USB_CDC_NOTIFY_RESPONSE_AVAILABLE can happen too (e.g. RNDIS), - * but there are no standard formats for the response data. - */ - default: - deverr(dev, "CDC: unexpected notification %02x!", - event->bNotificationType); - break; - } -} - -static u8 nibble(unsigned char c) -{ - if (likely(isdigit(c))) - return c - '0'; - c = toupper(c); - if (likely(isxdigit(c))) - return 10 + c - 'A'; - return 0; -} - -static inline int -get_ethernet_addr(struct usbnet *dev, struct usb_cdc_ether_desc *e) -{ - int tmp, i; - unsigned char buf [13]; - - tmp = usb_string(dev->udev, e->iMACAddress, buf, sizeof buf); - if (tmp != 12) { - dev_dbg(&dev->udev->dev, - "bad MAC string %d fetch, %d\n", e->iMACAddress, tmp); - if (tmp >= 0) - tmp = -EINVAL; - return tmp; - } - for (i = tmp = 0; i < 6; i++, tmp += 2) - dev->net->dev_addr [i] = - (nibble(buf [tmp]) << 4) + nibble(buf [tmp + 1]); - return 0; -} - -static int cdc_bind(struct usbnet *dev, struct usb_interface *intf) -{ - int status; - struct cdc_state *info = (void *) &dev->data; - - status = usbnet_generic_cdc_bind(dev, intf); - if (status < 0) - return status; - - status = get_ethernet_addr(dev, info->ether); - if (status < 0) { - usb_set_intfdata(info->data, NULL); - usb_driver_release_interface(driver_of(intf), info->data); - return status; - } - - /* FIXME cdc-ether has some multicast code too, though it complains - * in routine cases. info->ether describes the multicast support. - * Implement that here, manipulating the cdc filter as needed. - */ - return 0; -} - -static const struct driver_info cdc_info = { - .description = "CDC Ethernet Device", - .flags = FLAG_ETHER, - // .check_connect = cdc_check_connect, - .bind = cdc_bind, - .unbind = usbnet_cdc_unbind, - .status = cdc_status, -}; - -/*-------------------------------------------------------------------------*/ - - -static const struct usb_device_id products [] = { -/* - * BLACKLIST !! - * - * First blacklist any products that are egregiously nonconformant - * with the CDC Ethernet specs. Minor braindamage we cope with; when - * they're not even trying, needing a separate driver is only the first - * of the differences to show up. - */ - -#define ZAURUS_MASTER_INTERFACE \ - .bInterfaceClass = USB_CLASS_COMM, \ - .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, \ - .bInterfaceProtocol = USB_CDC_PROTO_NONE - -/* SA-1100 based Sharp Zaurus ("collie"), or compatible; - * wire-incompatible with true CDC Ethernet implementations. - * (And, it seems, needlessly so...) - */ -{ - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x04DD, - .idProduct = 0x8004, - ZAURUS_MASTER_INTERFACE, - .driver_info = 0, -}, - -/* PXA-25x based Sharp Zaurii. Note that it seems some of these - * (later models especially) may have shipped only with firmware - * advertising false "CDC MDLM" compatibility ... but we're not - * clear which models did that, so for now let's assume the worst. - */ -{ - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x04DD, - .idProduct = 0x8005, /* A-300 */ - ZAURUS_MASTER_INTERFACE, - .driver_info = 0, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x04DD, - .idProduct = 0x8006, /* B-500/SL-5600 */ - ZAURUS_MASTER_INTERFACE, - .driver_info = 0, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x04DD, - .idProduct = 0x8007, /* C-700 */ - ZAURUS_MASTER_INTERFACE, - .driver_info = 0, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x04DD, - .idProduct = 0x9031, /* C-750 C-760 */ - ZAURUS_MASTER_INTERFACE, - .driver_info = 0, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x04DD, - .idProduct = 0x9032, /* SL-6000 */ - ZAURUS_MASTER_INTERFACE, - .driver_info = 0, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x04DD, - /* reported with some C860 units */ - .idProduct = 0x9050, /* C-860 */ - ZAURUS_MASTER_INTERFACE, - .driver_info = 0, -}, - -/* Olympus has some models with a Zaurus-compatible option. - * R-1000 uses a FreeScale i.MXL cpu (ARMv4T) - */ -{ - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x07B4, - .idProduct = 0x0F02, /* R-1000 */ - ZAURUS_MASTER_INTERFACE, - .driver_info = 0, -}, - -/* - * WHITELIST!!! - * - * CDC Ether uses two interfaces, not necessarily consecutive. - * We match the main interface, ignoring the optional device - * class so we could handle devices that aren't exclusively - * CDC ether. - * - * NOTE: this match must come AFTER entries blacklisting devices - * because of bugs/quirks in a given product (like Zaurus, above). - */ -{ - USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET, - USB_CDC_PROTO_NONE), - .driver_info = (unsigned long) &cdc_info, -}, - { }, // END -}; -MODULE_DEVICE_TABLE(usb, products); - -static struct usb_driver cdc_driver = { - .name = "cdc_ether", - .id_table = products, - .probe = usbnet_probe, - .disconnect = usbnet_disconnect, - .suspend = usbnet_suspend, - .resume = usbnet_resume, -}; - - -static int __init cdc_init(void) -{ - BUILD_BUG_ON((sizeof(((struct usbnet *)0)->data) - < sizeof(struct cdc_state))); - - return usb_register(&cdc_driver); -} -module_init(cdc_init); - -static void __exit cdc_exit(void) -{ - usb_deregister(&cdc_driver); -} -module_exit(cdc_exit); - -MODULE_AUTHOR("David Brownell"); -MODULE_DESCRIPTION("USB CDC Ethernet devices"); -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/net/cdc_subset.c b/drivers/usb/net/cdc_subset.c deleted file mode 100644 index bc62b012602b..000000000000 --- a/drivers/usb/net/cdc_subset.c +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Simple "CDC Subset" USB Networking Links - * Copyright (C) 2000-2005 by David Brownell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <linux/module.h> -#include <linux/kmod.h> -#include <linux/init.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/ethtool.h> -#include <linux/workqueue.h> -#include <linux/mii.h> -#include <linux/usb.h> - -#include "usbnet.h" - - -/* - * This supports simple USB network links that don't require any special - * framing or hardware control operations. The protocol used here is a - * strict subset of CDC Ethernet, with three basic differences reflecting - * the goal that almost any hardware should run it: - * - * - Minimal runtime control: one interface, no altsettings, and - * no vendor or class specific control requests. If a device is - * configured, it is allowed to exchange packets with the host. - * Fancier models would mean not working on some hardware. - * - * - Minimal manufacturing control: no IEEE "Organizationally - * Unique ID" required, or an EEPROMs to store one. Each host uses - * one random "locally assigned" Ethernet address instead, which can - * of course be overridden using standard tools like "ifconfig". - * (With 2^46 such addresses, same-net collisions are quite rare.) - * - * - There is no additional framing data for USB. Packets are written - * exactly as in CDC Ethernet, starting with an Ethernet header and - * terminated by a short packet. However, the host will never send a - * zero length packet; some systems can't handle those robustly. - * - * Anything that can transmit and receive USB bulk packets can implement - * this protocol. That includes both smart peripherals and quite a lot - * of "host-to-host" USB cables (which embed two devices back-to-back). - * - * Note that although Linux may use many of those host-to-host links - * with this "cdc_subset" framing, that doesn't mean there may not be a - * better approach. Handling the "other end unplugs/replugs" scenario - * well tends to require chip-specific vendor requests. Also, Windows - * peers at the other end of host-to-host cables may expect their own - * framing to be used rather than this "cdc_subset" model. - */ - -#if defined(CONFIG_USB_EPSON2888) || defined(CONFIG_USB_ARMLINUX) -/* PDA style devices are always connected if present */ -static int always_connected (struct usbnet *dev) -{ - return 0; -} -#endif - -#ifdef CONFIG_USB_ALI_M5632 -#define HAVE_HARDWARE - -/*------------------------------------------------------------------------- - * - * ALi M5632 driver ... does high speed - * - * NOTE that the MS-Windows drivers for this chip use some funky and - * (naturally) undocumented 7-byte prefix to each packet, so this is a - * case where we don't currently interoperate. Also, once you unplug - * one end of the cable, you need to replug the other end too ... since - * chip docs are unavailable, there's no way to reset the relevant state - * short of a power cycle. - * - *-------------------------------------------------------------------------*/ - -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_BELKIN -#define HAVE_HARDWARE - -/*------------------------------------------------------------------------- - * - * Belkin F5U104 ... two NetChip 2280 devices + Atmel AVR microcontroller - * - * ... also two eTEK designs, including one sold as "Advance USBNET" - * - *-------------------------------------------------------------------------*/ - -static const struct driver_info belkin_info = { - .description = "Belkin, eTEK, or compatible", -}; - -#endif /* CONFIG_USB_BELKIN */ - - - -#ifdef CONFIG_USB_EPSON2888 -#define HAVE_HARDWARE - -/*------------------------------------------------------------------------- - * - * EPSON USB clients - * - * This is the same idea as Linux PDAs (below) except the firmware in the - * device might not be Tux-powered. Epson provides reference firmware that - * implements this interface. Product developers can reuse or modify that - * code, such as by using their own product and vendor codes. - * - * Support was from Juro Bystricky <bystricky.juro@erd.epson.com> - * - *-------------------------------------------------------------------------*/ - -static const struct driver_info epson2888_info = { - .description = "Epson USB Device", - .check_connect = always_connected, - - .in = 4, .out = 3, -}; - -#endif /* CONFIG_USB_EPSON2888 */ - - -/*------------------------------------------------------------------------- - * - * info from Jonathan McDowell <noodles@earth.li> - * - *-------------------------------------------------------------------------*/ -#ifdef CONFIG_USB_KC2190 -#define HAVE_HARDWARE -static const struct driver_info kc2190_info = { - .description = "KC Technology KC-190", -}; -#endif /* CONFIG_USB_KC2190 */ - - -#ifdef CONFIG_USB_ARMLINUX -#define HAVE_HARDWARE - -/*------------------------------------------------------------------------- - * - * Intel's SA-1100 chip integrates basic USB support, and is used - * in PDAs like some iPaqs, the Yopy, some Zaurus models, and more. - * When they run Linux, arch/arm/mach-sa1100/usb-eth.c may be used to - * network using minimal USB framing data. - * - * This describes the driver currently in standard ARM Linux kernels. - * The Zaurus uses a different driver (see later). - * - * PXA25x and PXA210 use XScale cores (ARM v5TE) with better USB support - * and different USB endpoint numbering than the SA1100 devices. The - * mach-pxa/usb-eth.c driver re-uses the device ids from mach-sa1100 - * so we rely on the endpoint descriptors. - * - *-------------------------------------------------------------------------*/ - -static const struct driver_info linuxdev_info = { - .description = "Linux Device", - .check_connect = always_connected, -}; - -static const struct driver_info yopy_info = { - .description = "Yopy", - .check_connect = always_connected, -}; - -static const struct driver_info blob_info = { - .description = "Boot Loader OBject", - .check_connect = always_connected, -}; - -#endif /* CONFIG_USB_ARMLINUX */ - - -/*-------------------------------------------------------------------------*/ - -#ifndef HAVE_HARDWARE -#error You need to configure some hardware for this driver -#endif - -/* - * chip vendor names won't normally be on the cables, and - * may not be on the device. - */ - -static const struct usb_device_id products [] = { - -#ifdef CONFIG_USB_ALI_M5632 -{ - USB_DEVICE (0x0402, 0x5632), // ALi defaults - .driver_info = (unsigned long) &ali_m5632_info, -}, -{ - USB_DEVICE (0x182d,0x207c), // SiteCom CN-124 - .driver_info = (unsigned long) &ali_m5632_info, -}, -#endif - -#ifdef CONFIG_USB_AN2720 -{ - USB_DEVICE (0x0547, 0x2720), // AnchorChips defaults - .driver_info = (unsigned long) &an2720_info, -}, { - USB_DEVICE (0x0547, 0x2727), // Xircom PGUNET - .driver_info = (unsigned long) &an2720_info, -}, -#endif - -#ifdef CONFIG_USB_BELKIN -{ - USB_DEVICE (0x050d, 0x0004), // Belkin - .driver_info = (unsigned long) &belkin_info, -}, { - USB_DEVICE (0x056c, 0x8100), // eTEK - .driver_info = (unsigned long) &belkin_info, -}, { - USB_DEVICE (0x0525, 0x9901), // Advance USBNET (eTEK) - .driver_info = (unsigned long) &belkin_info, -}, -#endif - -#ifdef CONFIG_USB_EPSON2888 -{ - USB_DEVICE (0x0525, 0x2888), // EPSON USB client - .driver_info = (unsigned long) &epson2888_info, -}, -#endif - -#ifdef CONFIG_USB_KC2190 -{ - USB_DEVICE (0x050f, 0x0190), // KC-190 - .driver_info = (unsigned long) &kc2190_info, -}, -#endif - -#ifdef CONFIG_USB_ARMLINUX -/* - * SA-1100 using standard ARM Linux kernels, or compatible. - * Often used when talking to Linux PDAs (iPaq, Yopy, etc). - * The sa-1100 "usb-eth" driver handles the basic framing. - * - * PXA25x or PXA210 ... these use a "usb-eth" driver much like - * the sa1100 one, but hardware uses different endpoint numbers. - * - * Or the Linux "Ethernet" gadget on hardware that can't talk - * CDC Ethernet (e.g., no altsettings), in either of two modes: - * - acting just like the old "usb-eth" firmware, though - * the implementation is different - * - supporting RNDIS as the first/default configuration for - * MS-Windows interop; Linux needs to use the other config - */ -{ - // 1183 = 0x049F, both used as hex values? - // Compaq "Itsy" vendor/product id - USB_DEVICE (0x049F, 0x505A), // usb-eth, or compatible - .driver_info = (unsigned long) &linuxdev_info, -}, { - USB_DEVICE (0x0E7E, 0x1001), // G.Mate "Yopy" - .driver_info = (unsigned long) &yopy_info, -}, { - USB_DEVICE (0x8086, 0x07d3), // "blob" bootloader - .driver_info = (unsigned long) &blob_info, -}, { - // Linux Ethernet/RNDIS gadget on pxa210/25x/26x, second config - // e.g. Gumstix, current OpenZaurus, ... - USB_DEVICE_VER (0x0525, 0xa4a2, 0x0203, 0x0203), - .driver_info = (unsigned long) &linuxdev_info, -}, -#endif - - { }, // END -}; -MODULE_DEVICE_TABLE(usb, products); - -/*-------------------------------------------------------------------------*/ - -static struct usb_driver cdc_subset_driver = { - .name = "cdc_subset", - .probe = usbnet_probe, - .suspend = usbnet_suspend, - .resume = usbnet_resume, - .disconnect = usbnet_disconnect, - .id_table = products, -}; - -static int __init cdc_subset_init(void) -{ - return usb_register(&cdc_subset_driver); -} -module_init(cdc_subset_init); - -static void __exit cdc_subset_exit(void) -{ - usb_deregister(&cdc_subset_driver); -} -module_exit(cdc_subset_exit); - -MODULE_AUTHOR("David Brownell"); -MODULE_DESCRIPTION("Simple 'CDC Subset' USB networking links"); -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/net/dm9601.c b/drivers/usb/net/dm9601.c deleted file mode 100644 index a67638601477..000000000000 --- a/drivers/usb/net/dm9601.c +++ /dev/null @@ -1,619 +0,0 @@ -/* - * Davicom DM9601 USB 1.1 10/100Mbps ethernet devices - * - * Peter Korsgaard <jacmet@sunsite.dk> - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - -//#define DEBUG - -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/stddef.h> -#include <linux/init.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/ethtool.h> -#include <linux/mii.h> -#include <linux/usb.h> -#include <linux/crc32.h> - -#include "usbnet.h" - -/* datasheet: - http://www.davicom.com.tw/big5/download/Data%20Sheet/DM9601-DS-P01-930914.pdf -*/ - -/* control requests */ -#define DM_READ_REGS 0x00 -#define DM_WRITE_REGS 0x01 -#define DM_READ_MEMS 0x02 -#define DM_WRITE_REG 0x03 -#define DM_WRITE_MEMS 0x05 -#define DM_WRITE_MEM 0x07 - -/* registers */ -#define DM_NET_CTRL 0x00 -#define DM_RX_CTRL 0x05 -#define DM_SHARED_CTRL 0x0b -#define DM_SHARED_ADDR 0x0c -#define DM_SHARED_DATA 0x0d /* low + high */ -#define DM_PHY_ADDR 0x10 /* 6 bytes */ -#define DM_MCAST_ADDR 0x16 /* 8 bytes */ -#define DM_GPR_CTRL 0x1e -#define DM_GPR_DATA 0x1f - -#define DM_MAX_MCAST 64 -#define DM_MCAST_SIZE 8 -#define DM_EEPROM_LEN 256 -#define DM_TX_OVERHEAD 2 /* 2 byte header */ -#define DM_RX_OVERHEAD 7 /* 3 byte header + 4 byte crc tail */ -#define DM_TIMEOUT 1000 - - -static int dm_read(struct usbnet *dev, u8 reg, u16 length, void *data) -{ - devdbg(dev, "dm_read() reg=0x%02x length=%d", reg, length); - return usb_control_msg(dev->udev, - usb_rcvctrlpipe(dev->udev, 0), - DM_READ_REGS, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, reg, data, length, USB_CTRL_SET_TIMEOUT); -} - -static int dm_read_reg(struct usbnet *dev, u8 reg, u8 *value) -{ - return dm_read(dev, reg, 1, 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); - return usb_control_msg(dev->udev, - usb_sndctrlpipe(dev->udev, 0), - DM_WRITE_REGS, - USB_DIR_OUT | USB_TYPE_VENDOR |USB_RECIP_DEVICE, - 0, reg, data, length, USB_CTRL_SET_TIMEOUT); -} - -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); - return usb_control_msg(dev->udev, - usb_sndctrlpipe(dev->udev, 0), - DM_WRITE_REG, - USB_DIR_OUT | USB_TYPE_VENDOR |USB_RECIP_DEVICE, - value, reg, NULL, 0, USB_CTRL_SET_TIMEOUT); -} - -static void dm_write_async_callback(struct urb *urb) -{ - struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; - - if (urb->status < 0) - printk(KERN_DEBUG "dm_write_async_callback() failed with %d", - urb->status); - - kfree(req); - usb_free_urb(urb); -} - -static void dm_write_async(struct usbnet *dev, u8 reg, u16 length, void *data) -{ - struct usb_ctrlrequest *req; - struct urb *urb; - int status; - - devdbg(dev, "dm_write_async() reg=0x%02x length=%d", reg, length); - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) { - deverr(dev, "Error allocating URB in dm_write_async!"); - return; - } - - req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); - if (!req) { - 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 = DM_WRITE_REGS; - req->wValue = 0; - req->wIndex = cpu_to_le16(reg); - req->wLength = cpu_to_le16(length); - - usb_fill_control_urb(urb, dev->udev, - usb_sndctrlpipe(dev->udev, 0), - (void *)req, data, length, - dm_write_async_callback, req); - - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status < 0) { - deverr(dev, "Error submitting the control message: status=%d", - status); - kfree(req); - usb_free_urb(urb); - } -} - -static void dm_write_reg_async(struct usbnet *dev, u8 reg, u8 value) -{ - struct usb_ctrlrequest *req; - struct urb *urb; - int status; - - devdbg(dev, "dm_write_reg_async() reg=0x%02x value=0x%02x", - reg, value); - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) { - deverr(dev, "Error allocating URB in dm_write_async!"); - return; - } - - req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); - if (!req) { - 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 = DM_WRITE_REG; - req->wValue = cpu_to_le16(value); - req->wIndex = cpu_to_le16(reg); - req->wLength = 0; - - usb_fill_control_urb(urb, dev->udev, - usb_sndctrlpipe(dev->udev, 0), - (void *)req, NULL, 0, dm_write_async_callback, req); - - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status < 0) { - deverr(dev, "Error submitting the control message: status=%d", - status); - kfree(req); - usb_free_urb(urb); - } -} - -static int dm_read_shared_word(struct usbnet *dev, int phy, u8 reg, u16 *value) -{ - int ret, i; - - mutex_lock(&dev->phy_mutex); - - dm_write_reg(dev, DM_SHARED_ADDR, phy ? (reg | 0x40) : reg); - dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0xc : 0x4); - - for (i = 0; i < DM_TIMEOUT; i++) { - u8 tmp; - - udelay(1); - ret = dm_read_reg(dev, DM_SHARED_CTRL, &tmp); - if (ret < 0) - goto out; - - /* ready */ - if ((tmp & 1) == 0) - break; - } - - if (i == DM_TIMEOUT) { - deverr(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); - - devdbg(dev, "read shared %d 0x%02x returned 0x%04x, %d", - phy, reg, *value, ret); - - out: - mutex_unlock(&dev->phy_mutex); - return ret; -} - -static int dm_write_shared_word(struct usbnet *dev, int phy, u8 reg, u16 value) -{ - int ret, i; - - mutex_lock(&dev->phy_mutex); - - ret = dm_write(dev, DM_SHARED_DATA, 2, &value); - if (ret < 0) - goto out; - - dm_write_reg(dev, DM_SHARED_ADDR, phy ? (reg | 0x40) : reg); - dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0x1c : 0x14); - - for (i = 0; i < DM_TIMEOUT; i++) { - u8 tmp; - - udelay(1); - ret = dm_read_reg(dev, DM_SHARED_CTRL, &tmp); - if (ret < 0) - goto out; - - /* ready */ - if ((tmp & 1) == 0) - break; - } - - if (i == DM_TIMEOUT) { - deverr(dev, "%s write timed out!", phy ? "phy" : "eeprom"); - ret = -EIO; - goto out; - } - - dm_write_reg(dev, DM_SHARED_CTRL, 0x0); - -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); -} - - - -static int dm9601_get_eeprom_len(struct net_device *dev) -{ - return DM_EEPROM_LEN; -} - -static int dm9601_get_eeprom(struct net_device *net, - struct ethtool_eeprom *eeprom, u8 * data) -{ - struct usbnet *dev = netdev_priv(net); - u16 *ebuf = (u16 *) data; - int i; - - /* access is 16bit */ - if ((eeprom->offset % 2) || (eeprom->len % 2)) - return -EINVAL; - - for (i = 0; i < eeprom->len / 2; i++) { - if (dm_read_eeprom_word(dev, eeprom->offset / 2 + i, - &ebuf[i]) < 0) - return -EINVAL; - } - return 0; -} - -static int dm9601_mdio_read(struct net_device *netdev, int phy_id, int loc) -{ - struct usbnet *dev = netdev_priv(netdev); - - u16 res; - - if (phy_id) { - devdbg(dev, "Only internal phy supported"); - return 0; - } - - dm_read_shared_word(dev, 1, loc, &res); - - devdbg(dev, - "dm9601_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x", - phy_id, loc, le16_to_cpu(res)); - - return le16_to_cpu(res); -} - -static void dm9601_mdio_write(struct net_device *netdev, int phy_id, int loc, - int val) -{ - struct usbnet *dev = netdev_priv(netdev); - u16 res = cpu_to_le16(val); - - if (phy_id) { - devdbg(dev, "Only internal phy supported"); - return; - } - - devdbg(dev,"dm9601_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x", - phy_id, loc, val); - - dm_write_shared_word(dev, 1, loc, res); -} - -static void dm9601_get_drvinfo(struct net_device *net, - struct ethtool_drvinfo *info) -{ - /* Inherit standard device info */ - usbnet_get_drvinfo(net, info); - info->eedump_len = DM_EEPROM_LEN; -} - -static u32 dm9601_get_link(struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - - return mii_link_ok(&dev->mii); -} - -static int dm9601_ioctl(struct net_device *net, struct ifreq *rq, int cmd) -{ - struct usbnet *dev = netdev_priv(net); - - return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); -} - -static struct ethtool_ops dm9601_ethtool_ops = { - .get_drvinfo = dm9601_get_drvinfo, - .get_link = dm9601_get_link, - .get_msglevel = usbnet_get_msglevel, - .set_msglevel = usbnet_set_msglevel, - .get_eeprom_len = dm9601_get_eeprom_len, - .get_eeprom = dm9601_get_eeprom, - .get_settings = usbnet_get_settings, - .set_settings = usbnet_set_settings, - .nway_reset = usbnet_nway_reset, -}; - -static void dm9601_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 = 0x01; - - 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 || net->mc_count > DM_MAX_MCAST) { - rx_ctl |= 0x04; - } else if (net->mc_count) { - struct dev_mc_list *mc_list = net->mc_list; - int i; - - for (i = 0; i < net->mc_count; i++) { - u32 crc = ether_crc(ETH_ALEN, mc_list->dmi_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); -} - -static int dm9601_bind(struct usbnet *dev, struct usb_interface *intf) -{ - int ret; - - ret = usbnet_get_endpoints(dev, intf); - if (ret) - goto out; - - dev->net->do_ioctl = dm9601_ioctl; - dev->net->set_multicast_list = dm9601_set_multicast; - dev->net->ethtool_ops = &dm9601_ethtool_ops; - dev->net->hard_header_len += DM_TX_OVERHEAD; - dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len; - dev->rx_urb_size = dev->net->mtu + DM_RX_OVERHEAD; - - dev->mii.dev = dev->net; - dev->mii.mdio_read = dm9601_mdio_read; - dev->mii.mdio_write = dm9601_mdio_write; - dev->mii.phy_id_mask = 0x1f; - dev->mii.reg_num_mask = 0x1f; - - /* reset */ - ret = dm_write_reg(dev, DM_NET_CTRL, 1); - udelay(20); - - /* read MAC */ - ret = dm_read(dev, DM_PHY_ADDR, ETH_ALEN, dev->net->dev_addr); - if (ret < 0) { - printk(KERN_ERR "Error reading MAC address\n"); - ret = -ENODEV; - goto out; - } - - - /* power up phy */ - dm_write_reg(dev, DM_GPR_CTRL, 1); - dm_write_reg(dev, DM_GPR_DATA, 0); - - /* receive broadcast packets */ - dm9601_set_multicast(dev->net); - - dm9601_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); - dm9601_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, - ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); - mii_nway_restart(&dev->mii); - -out: - return ret; -} - -static int dm9601_rx_fixup(struct usbnet *dev, struct sk_buff *skb) -{ - u8 status; - int len; - - /* format: - b0: rx status - b1: packet length (incl crc) low - b2: packet length (incl crc) high - b3..n-4: packet data - bn-3..bn: ethernet crc - */ - - if (unlikely(skb->len < DM_RX_OVERHEAD)) { - dev_err(&dev->udev->dev, "unexpected tiny rx frame\n"); - return 0; - } - - status = skb->data[0]; - len = (skb->data[1] | (skb->data[2] << 8)) - 4; - - if (unlikely(status & 0xbf)) { - if (status & 0x01) dev->stats.rx_fifo_errors++; - if (status & 0x02) dev->stats.rx_crc_errors++; - if (status & 0x04) dev->stats.rx_frame_errors++; - if (status & 0x20) dev->stats.rx_missed_errors++; - if (status & 0x90) dev->stats.rx_length_errors++; - return 0; - } - - skb_pull(skb, 3); - skb_trim(skb, len); - - return 1; -} - -static struct sk_buff *dm9601_tx_fixup(struct usbnet *dev, struct sk_buff *skb, - gfp_t flags) -{ - int len; - - /* format: - b0: packet length low - b1: packet length high - b3..n: packet data - */ - - 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; - } - - __skb_push(skb, DM_TX_OVERHEAD); - - len = skb->len; - /* usbnet adds padding if length is a multiple of packet size - if so, adjust length value in header */ - if ((len % dev->maxpacket) == 0) - len++; - - skb->data[0] = len; - skb->data[1] = len >> 8; - - return skb; -} - -static void dm9601_status(struct usbnet *dev, struct urb *urb) -{ - int link; - u8 *buf; - - /* format: - b0: net status - b1: tx status 1 - b2: tx status 2 - b3: rx status - b4: rx overflow - b5: rx count - b6: tx count - b7: gpr - */ - - if (urb->actual_length < 8) - return; - - buf = urb->transfer_buffer; - - link = !!(buf[0] & 0x40); - if (netif_carrier_ok(dev->net) != link) { - if (link) { - netif_carrier_on(dev->net); - usbnet_defer_kevent (dev, EVENT_LINK_RESET); - } - else - netif_carrier_off(dev->net); - devdbg(dev, "Link Status is: %d", link); - } -} - -static int dm9601_link_reset(struct usbnet *dev) -{ - struct ethtool_cmd ecmd; - - mii_check_media(&dev->mii, 1, 1); - mii_ethtool_gset(&dev->mii, &ecmd); - - devdbg(dev, "link_reset() speed: %d duplex: %d", - ecmd.speed, ecmd.duplex); - - return 0; -} - -static const struct driver_info dm9601_info = { - .description = "Davicom DM9601 USB Ethernet", - .flags = FLAG_ETHER, - .bind = dm9601_bind, - .rx_fixup = dm9601_rx_fixup, - .tx_fixup = dm9601_tx_fixup, - .status = dm9601_status, - .link_reset = dm9601_link_reset, - .reset = dm9601_link_reset, -}; - -static const struct usb_device_id products[] = { - { - USB_DEVICE(0x07aa, 0x9601), /* Corega FEther USB-TXC */ - .driver_info = (unsigned long)&dm9601_info, - }, - { - USB_DEVICE(0x0a46, 0x9601), /* Davicom USB-100 */ - .driver_info = (unsigned long)&dm9601_info, - }, - { - USB_DEVICE(0x0a46, 0x6688), /* ZT6688 USB NIC */ - .driver_info = (unsigned long)&dm9601_info, - }, - { - USB_DEVICE(0x0a46, 0x0268), /* ShanTou ST268 USB NIC */ - .driver_info = (unsigned long)&dm9601_info, - }, - {}, // END -}; - -MODULE_DEVICE_TABLE(usb, products); - -static struct usb_driver dm9601_driver = { - .name = "dm9601", - .id_table = products, - .probe = usbnet_probe, - .disconnect = usbnet_disconnect, - .suspend = usbnet_suspend, - .resume = usbnet_resume, -}; - -static int __init dm9601_init(void) -{ - return usb_register(&dm9601_driver); -} - -static void __exit dm9601_exit(void) -{ - usb_deregister(&dm9601_driver); -} - -module_init(dm9601_init); -module_exit(dm9601_exit); - -MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>"); -MODULE_DESCRIPTION("Davicom DM9601 USB 1.1 ethernet devices"); -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/net/gl620a.c b/drivers/usb/net/gl620a.c deleted file mode 100644 index 031cf5ca4dbb..000000000000 --- a/drivers/usb/net/gl620a.c +++ /dev/null @@ -1,245 +0,0 @@ -/* - * GeneSys GL620USB-A based links - * Copyright (C) 2001 by Jiun-Jie Huang <huangjj@genesyslogic.com.tw> - * Copyright (C) 2001 by Stanislav Brabec <utx@penguin.cz> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -// #define DEBUG // error path messages, extra info -// #define VERBOSE // more; success messages - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/ethtool.h> -#include <linux/workqueue.h> -#include <linux/mii.h> -#include <linux/usb.h> - -#include "usbnet.h" - - -/* - * GeneSys GL620USB-A (www.genesyslogic.com.tw) - * - * ... should partially interop with the Win32 driver for this hardware. - * The GeneSys docs imply there's some NDIS issue motivating this framing. - * - * Some info from GeneSys: - * - GL620USB-A is full duplex; GL620USB is only half duplex for bulk. - * (Some cables, like the BAFO-100c, use the half duplex version.) - * - For the full duplex model, the low bit of the version code says - * which side is which ("left/right"). - * - For the half duplex type, a control/interrupt handshake settles - * the transfer direction. (That's disabled here, partially coded.) - * A control URB would block until other side writes an interrupt. - * - * Original code from Jiun-Jie Huang <huangjj@genesyslogic.com.tw> - * and merged into "usbnet" by Stanislav Brabec <utx@penguin.cz>. - */ - -// control msg write command -#define GENELINK_CONNECT_WRITE 0xF0 -// interrupt pipe index -#define GENELINK_INTERRUPT_PIPE 0x03 -// interrupt read buffer size -#define INTERRUPT_BUFSIZE 0x08 -// interrupt pipe interval value -#define GENELINK_INTERRUPT_INTERVAL 0x10 -// max transmit packet number per transmit -#define GL_MAX_TRANSMIT_PACKETS 32 -// max packet length -#define GL_MAX_PACKET_LEN 1514 -// max receive buffer size -#define GL_RCV_BUF_SIZE \ - (((GL_MAX_PACKET_LEN + 4) * GL_MAX_TRANSMIT_PACKETS) + 4) - -struct gl_packet { - __le32 packet_length; - char packet_data [1]; -}; - -struct gl_header { - __le32 packet_count; - struct gl_packet packets; -}; - -static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb) -{ - struct gl_header *header; - struct gl_packet *packet; - struct sk_buff *gl_skb; - u32 size; - u32 count; - - header = (struct gl_header *) skb->data; - - // get the packet count of the received skb - count = le32_to_cpu(header->packet_count); - if (count > GL_MAX_TRANSMIT_PACKETS) { - dbg("genelink: invalid received packet count %u", count); - return 0; - } - - // set the current packet pointer to the first packet - packet = &header->packets; - - // decrement the length for the packet count size 4 bytes - skb_pull(skb, 4); - - while (count > 1) { - // get the packet length - size = le32_to_cpu(packet->packet_length); - - // this may be a broken packet - if (size > GL_MAX_PACKET_LEN) { - dbg("genelink: invalid rx length %d", size); - return 0; - } - - // allocate the skb for the individual packet - gl_skb = alloc_skb(size, GFP_ATOMIC); - if (gl_skb) { - - // copy the packet data to the new skb - memcpy(skb_put(gl_skb, size), - packet->packet_data, size); - usbnet_skb_return(dev, gl_skb); - } - - // advance to the next packet - packet = (struct gl_packet *)&packet->packet_data[size]; - count--; - - // shift the data pointer to the next gl_packet - skb_pull(skb, size + 4); - } - - // skip the packet length field 4 bytes - skb_pull(skb, 4); - - if (skb->len > GL_MAX_PACKET_LEN) { - dbg("genelink: invalid rx length %d", skb->len); - return 0; - } - return 1; -} - -static struct sk_buff * -genelink_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) -{ - int padlen; - int length = skb->len; - int headroom = skb_headroom(skb); - int tailroom = skb_tailroom(skb); - __le32 *packet_count; - __le32 *packet_len; - - // FIXME: magic numbers, bleech - padlen = ((skb->len + (4 + 4*1)) % 64) ? 0 : 1; - - if ((!skb_cloned(skb)) - && ((headroom + tailroom) >= (padlen + (4 + 4*1)))) { - if ((headroom < (4 + 4*1)) || (tailroom < padlen)) { - skb->data = memmove(skb->head + (4 + 4*1), - skb->data, skb->len); - skb_set_tail_pointer(skb, skb->len); - } - } else { - struct sk_buff *skb2; - skb2 = skb_copy_expand(skb, (4 + 4*1) , padlen, flags); - dev_kfree_skb_any(skb); - skb = skb2; - if (!skb) - return NULL; - } - - // attach the packet count to the header - packet_count = (__le32 *) skb_push(skb, (4 + 4*1)); - packet_len = packet_count + 1; - - *packet_count = cpu_to_le32(1); - *packet_len = cpu_to_le32(length); - - // add padding byte - if ((skb->len % dev->maxpacket) == 0) - skb_put(skb, 1); - - return skb; -} - -static int genelink_bind(struct usbnet *dev, struct usb_interface *intf) -{ - dev->hard_mtu = GL_RCV_BUF_SIZE; - dev->net->hard_header_len += 4; - dev->in = usb_rcvbulkpipe(dev->udev, dev->driver_info->in); - dev->out = usb_sndbulkpipe(dev->udev, dev->driver_info->out); - return 0; -} - -static const struct driver_info genelink_info = { - .description = "Genesys GeneLink", - .flags = FLAG_FRAMING_GL | FLAG_NO_SETINT, - .bind = genelink_bind, - .rx_fixup = genelink_rx_fixup, - .tx_fixup = genelink_tx_fixup, - - .in = 1, .out = 2, - -#ifdef GENELINK_ACK - .check_connect =genelink_check_connect, -#endif -}; - -static const struct usb_device_id products [] = { - -{ - USB_DEVICE(0x05e3, 0x0502), // GL620USB-A - .driver_info = (unsigned long) &genelink_info, -}, - /* NOT: USB_DEVICE(0x05e3, 0x0501), // GL620USB - * that's half duplex, not currently supported - */ - { }, // END -}; -MODULE_DEVICE_TABLE(usb, products); - -static struct usb_driver gl620a_driver = { - .name = "gl620a", - .id_table = products, - .probe = usbnet_probe, - .disconnect = usbnet_disconnect, - .suspend = usbnet_suspend, - .resume = usbnet_resume, -}; - -static int __init usbnet_init(void) -{ - return usb_register(&gl620a_driver); -} -module_init(usbnet_init); - -static void __exit usbnet_exit(void) -{ - usb_deregister(&gl620a_driver); -} -module_exit(usbnet_exit); - -MODULE_AUTHOR("Jiun-Jie Huang"); -MODULE_DESCRIPTION("GL620-USB-A Host-to-Host Link cables"); -MODULE_LICENSE("GPL"); - diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c deleted file mode 100644 index 60d29440f316..000000000000 --- a/drivers/usb/net/kaweth.c +++ /dev/null @@ -1,1337 +0,0 @@ -/**************************************************************** - * - * kaweth.c - driver for KL5KUSB101 based USB->Ethernet - * - * (c) 2000 Interlan Communications - * (c) 2000 Stephane Alnet - * (C) 2001 Brad Hards - * (C) 2002 Oliver Neukum - * - * Original author: The Zapman <zapman@interlan.net> - * Inspired by, and much credit goes to Michael Rothwell - * <rothwell@interlan.net> for the test equipment, help, and patience - * Based off of (and with thanks to) Petko Manolov's pegaus.c driver. - * Also many thanks to Joel Silverman and Ed Surprenant at Kawasaki - * for providing the firmware and driver resources. - * - * 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, 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. - * - ****************************************************************/ - -/* TODO: - * Fix in_interrupt() problem - * Develop test procedures for USB net interfaces - * Run test procedures - * Fix bugs from previous two steps - * Snoop other OSs for any tricks we're not doing - * SMP locking - * Reduce arbitrary timeouts - * Smart multicast support - * Temporary MAC change support - * Tunable SOFs parameter - ioctl()? - * Ethernet stats collection - * Code formatting improvements - */ - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/usb.h> -#include <linux/types.h> -#include <linux/ethtool.h> -#include <linux/dma-mapping.h> -#include <linux/wait.h> -#include <asm/uaccess.h> -#include <asm/semaphore.h> -#include <asm/byteorder.h> - -#undef DEBUG - -#include "kawethfw.h" - -#define KAWETH_MTU 1514 -#define KAWETH_BUF_SIZE 1664 -#define KAWETH_TX_TIMEOUT (5 * HZ) -#define KAWETH_SCRATCH_SIZE 32 -#define KAWETH_FIRMWARE_BUF_SIZE 4096 -#define KAWETH_CONTROL_TIMEOUT (30 * HZ) - -#define KAWETH_STATUS_BROKEN 0x0000001 -#define KAWETH_STATUS_CLOSING 0x0000002 -#define KAWETH_STATUS_SUSPENDING 0x0000004 - -#define KAWETH_STATUS_BLOCKED (KAWETH_STATUS_CLOSING | KAWETH_STATUS_SUSPENDING) - -#define KAWETH_PACKET_FILTER_PROMISCUOUS 0x01 -#define KAWETH_PACKET_FILTER_ALL_MULTICAST 0x02 -#define KAWETH_PACKET_FILTER_DIRECTED 0x04 -#define KAWETH_PACKET_FILTER_BROADCAST 0x08 -#define KAWETH_PACKET_FILTER_MULTICAST 0x10 - -/* Table 7 */ -#define KAWETH_COMMAND_GET_ETHERNET_DESC 0x00 -#define KAWETH_COMMAND_MULTICAST_FILTERS 0x01 -#define KAWETH_COMMAND_SET_PACKET_FILTER 0x02 -#define KAWETH_COMMAND_STATISTICS 0x03 -#define KAWETH_COMMAND_SET_TEMP_MAC 0x06 -#define KAWETH_COMMAND_GET_TEMP_MAC 0x07 -#define KAWETH_COMMAND_SET_URB_SIZE 0x08 -#define KAWETH_COMMAND_SET_SOFS_WAIT 0x09 -#define KAWETH_COMMAND_SCAN 0xFF - -#define KAWETH_SOFS_TO_WAIT 0x05 - -#define INTBUFFERSIZE 4 - -#define STATE_OFFSET 0 -#define STATE_MASK 0x40 -#define STATE_SHIFT 5 - -#define IS_BLOCKED(s) (s & KAWETH_STATUS_BLOCKED) - - -MODULE_AUTHOR("Michael Zappe <zapman@interlan.net>, Stephane Alnet <stephane@u-picardie.fr>, Brad Hards <bhards@bigpond.net.au> and Oliver Neukum <oliver@neukum.org>"); -MODULE_DESCRIPTION("KL5USB101 USB Ethernet driver"); -MODULE_LICENSE("GPL"); - -static const char driver_name[] = "kaweth"; - -static int kaweth_probe( - struct usb_interface *intf, - const struct usb_device_id *id /* from id_table */ - ); -static void kaweth_disconnect(struct usb_interface *intf); -static int kaweth_internal_control_msg(struct usb_device *usb_dev, - unsigned int pipe, - struct usb_ctrlrequest *cmd, void *data, - int len, int timeout); -static int kaweth_suspend(struct usb_interface *intf, pm_message_t message); -static int kaweth_resume(struct usb_interface *intf); - -/**************************************************************** - * usb_device_id - ****************************************************************/ -static struct usb_device_id usb_klsi_table[] = { - { USB_DEVICE(0x03e8, 0x0008) }, /* AOX Endpoints USB Ethernet */ - { USB_DEVICE(0x04bb, 0x0901) }, /* I-O DATA USB-ET/T */ - { USB_DEVICE(0x0506, 0x03e8) }, /* 3Com 3C19250 */ - { USB_DEVICE(0x0506, 0x11f8) }, /* 3Com 3C460 */ - { USB_DEVICE(0x0557, 0x2002) }, /* ATEN USB Ethernet */ - { USB_DEVICE(0x0557, 0x4000) }, /* D-Link DSB-650C */ - { USB_DEVICE(0x0565, 0x0002) }, /* Peracom Enet */ - { USB_DEVICE(0x0565, 0x0003) }, /* Optus@Home UEP1045A */ - { USB_DEVICE(0x0565, 0x0005) }, /* Peracom Enet2 */ - { USB_DEVICE(0x05e9, 0x0008) }, /* KLSI KL5KUSB101B */ - { USB_DEVICE(0x05e9, 0x0009) }, /* KLSI KL5KUSB101B (Board change) */ - { USB_DEVICE(0x066b, 0x2202) }, /* Linksys USB10T */ - { USB_DEVICE(0x06e1, 0x0008) }, /* ADS USB-10BT */ - { USB_DEVICE(0x06e1, 0x0009) }, /* ADS USB-10BT */ - { USB_DEVICE(0x0707, 0x0100) }, /* SMC 2202USB */ - { USB_DEVICE(0x07aa, 0x0001) }, /* Correga K.K. */ - { USB_DEVICE(0x07b8, 0x4000) }, /* D-Link DU-E10 */ - { USB_DEVICE(0x0846, 0x1001) }, /* NetGear EA-101 */ - { USB_DEVICE(0x0846, 0x1002) }, /* NetGear EA-101 */ - { USB_DEVICE(0x085a, 0x0008) }, /* PortGear Ethernet Adapter */ - { USB_DEVICE(0x085a, 0x0009) }, /* PortGear Ethernet Adapter */ - { USB_DEVICE(0x087d, 0x5704) }, /* Jaton USB Ethernet Device Adapter */ - { USB_DEVICE(0x0951, 0x0008) }, /* Kingston Technology USB Ethernet Adapter */ - { USB_DEVICE(0x095a, 0x3003) }, /* Portsmith Express Ethernet Adapter */ - { USB_DEVICE(0x10bd, 0x1427) }, /* ASANTE USB To Ethernet Adapter */ - { USB_DEVICE(0x1342, 0x0204) }, /* Mobility USB-Ethernet Adapter */ - { USB_DEVICE(0x13d2, 0x0400) }, /* Shark Pocket Adapter */ - { USB_DEVICE(0x1485, 0x0001) }, /* Silicom U2E */ - { USB_DEVICE(0x1485, 0x0002) }, /* Psion Dacom Gold Port Ethernet */ - { USB_DEVICE(0x1645, 0x0005) }, /* Entrega E45 */ - { USB_DEVICE(0x1645, 0x0008) }, /* Entrega USB Ethernet Adapter */ - { USB_DEVICE(0x1645, 0x8005) }, /* PortGear Ethernet Adapter */ - { USB_DEVICE(0x1668, 0x0323) }, /* Actiontec USB Ethernet */ - { USB_DEVICE(0x2001, 0x4000) }, /* D-link DSB-650C */ - {} /* Null terminator */ -}; - -MODULE_DEVICE_TABLE (usb, usb_klsi_table); - -/**************************************************************** - * kaweth_driver - ****************************************************************/ -static struct usb_driver kaweth_driver = { - .name = driver_name, - .probe = kaweth_probe, - .disconnect = kaweth_disconnect, - .suspend = kaweth_suspend, - .resume = kaweth_resume, - .id_table = usb_klsi_table, - .supports_autosuspend = 1, -}; - -typedef __u8 eth_addr_t[6]; - -/**************************************************************** - * usb_eth_dev - ****************************************************************/ -struct usb_eth_dev { - char *name; - __u16 vendor; - __u16 device; - void *pdata; -}; - -/**************************************************************** - * kaweth_ethernet_configuration - * Refer Table 8 - ****************************************************************/ -struct kaweth_ethernet_configuration -{ - __u8 size; - __u8 reserved1; - __u8 reserved2; - eth_addr_t hw_addr; - __u32 statistics_mask; - __le16 segment_size; - __u16 max_multicast_filters; - __u8 reserved3; -} __attribute__ ((packed)); - -/**************************************************************** - * kaweth_device - ****************************************************************/ -struct kaweth_device -{ - spinlock_t device_lock; - - __u32 status; - int end; - int suspend_lowmem_rx; - int suspend_lowmem_ctrl; - int linkstate; - int opened; - struct delayed_work lowmem_work; - - struct usb_device *dev; - struct usb_interface *intf; - struct net_device *net; - wait_queue_head_t term_wait; - - struct urb *rx_urb; - struct urb *tx_urb; - struct urb *irq_urb; - - dma_addr_t intbufferhandle; - __u8 *intbuffer; - dma_addr_t rxbufferhandle; - __u8 *rx_buf; - - - struct sk_buff *tx_skb; - - __u8 *firmware_buf; - __u8 scratch[KAWETH_SCRATCH_SIZE]; - __u16 packet_filter_bitmap; - - struct kaweth_ethernet_configuration configuration; - - struct net_device_stats stats; -}; - - -/**************************************************************** - * kaweth_control - ****************************************************************/ -static int kaweth_control(struct kaweth_device *kaweth, - unsigned int pipe, - __u8 request, - __u8 requesttype, - __u16 value, - __u16 index, - void *data, - __u16 size, - int timeout) -{ - struct usb_ctrlrequest *dr; - - dbg("kaweth_control()"); - - if(in_interrupt()) { - dbg("in_interrupt()"); - return -EBUSY; - } - - dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); - - if (!dr) { - dbg("kmalloc() failed"); - return -ENOMEM; - } - - dr->bRequestType= requesttype; - dr->bRequest = request; - dr->wValue = cpu_to_le16p(&value); - dr->wIndex = cpu_to_le16p(&index); - dr->wLength = cpu_to_le16p(&size); - - return kaweth_internal_control_msg(kaweth->dev, - pipe, - dr, - data, - size, - timeout); -} - -/**************************************************************** - * kaweth_read_configuration - ****************************************************************/ -static int kaweth_read_configuration(struct kaweth_device *kaweth) -{ - int retval; - - dbg("Reading kaweth configuration"); - - retval = kaweth_control(kaweth, - usb_rcvctrlpipe(kaweth->dev, 0), - KAWETH_COMMAND_GET_ETHERNET_DESC, - USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE, - 0, - 0, - (void *)&kaweth->configuration, - sizeof(kaweth->configuration), - KAWETH_CONTROL_TIMEOUT); - - return retval; -} - -/**************************************************************** - * kaweth_set_urb_size - ****************************************************************/ -static int kaweth_set_urb_size(struct kaweth_device *kaweth, __u16 urb_size) -{ - int retval; - - dbg("Setting URB size to %d", (unsigned)urb_size); - - retval = kaweth_control(kaweth, - usb_sndctrlpipe(kaweth->dev, 0), - KAWETH_COMMAND_SET_URB_SIZE, - USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, - urb_size, - 0, - (void *)&kaweth->scratch, - 0, - KAWETH_CONTROL_TIMEOUT); - - return retval; -} - -/**************************************************************** - * kaweth_set_sofs_wait - ****************************************************************/ -static int kaweth_set_sofs_wait(struct kaweth_device *kaweth, __u16 sofs_wait) -{ - int retval; - - dbg("Set SOFS wait to %d", (unsigned)sofs_wait); - - retval = kaweth_control(kaweth, - usb_sndctrlpipe(kaweth->dev, 0), - KAWETH_COMMAND_SET_SOFS_WAIT, - USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, - sofs_wait, - 0, - (void *)&kaweth->scratch, - 0, - KAWETH_CONTROL_TIMEOUT); - - return retval; -} - -/**************************************************************** - * kaweth_set_receive_filter - ****************************************************************/ -static int kaweth_set_receive_filter(struct kaweth_device *kaweth, - __u16 receive_filter) -{ - int retval; - - dbg("Set receive filter to %d", (unsigned)receive_filter); - - retval = kaweth_control(kaweth, - usb_sndctrlpipe(kaweth->dev, 0), - KAWETH_COMMAND_SET_PACKET_FILTER, - USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, - receive_filter, - 0, - (void *)&kaweth->scratch, - 0, - KAWETH_CONTROL_TIMEOUT); - - return retval; -} - -/**************************************************************** - * kaweth_download_firmware - ****************************************************************/ -static int kaweth_download_firmware(struct kaweth_device *kaweth, - __u8 *data, - __u16 data_len, - __u8 interrupt, - __u8 type) -{ - if(data_len > KAWETH_FIRMWARE_BUF_SIZE) { - err("Firmware too big: %d", data_len); - return -ENOSPC; - } - - memcpy(kaweth->firmware_buf, data, data_len); - - kaweth->firmware_buf[2] = (data_len & 0xFF) - 7; - kaweth->firmware_buf[3] = data_len >> 8; - kaweth->firmware_buf[4] = type; - kaweth->firmware_buf[5] = interrupt; - - dbg("High: %i, Low:%i", kaweth->firmware_buf[3], - kaweth->firmware_buf[2]); - - dbg("Downloading firmware at %p to kaweth device at %p", - data, - kaweth); - dbg("Firmware length: %d", data_len); - - return kaweth_control(kaweth, - usb_sndctrlpipe(kaweth->dev, 0), - KAWETH_COMMAND_SCAN, - USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, - 0, - 0, - (void *)kaweth->firmware_buf, - data_len, - KAWETH_CONTROL_TIMEOUT); -} - -/**************************************************************** - * kaweth_trigger_firmware - ****************************************************************/ -static int kaweth_trigger_firmware(struct kaweth_device *kaweth, - __u8 interrupt) -{ - kaweth->firmware_buf[0] = 0xB6; - kaweth->firmware_buf[1] = 0xC3; - kaweth->firmware_buf[2] = 0x01; - kaweth->firmware_buf[3] = 0x00; - kaweth->firmware_buf[4] = 0x06; - kaweth->firmware_buf[5] = interrupt; - kaweth->firmware_buf[6] = 0x00; - kaweth->firmware_buf[7] = 0x00; - - dbg("Triggering firmware"); - - return kaweth_control(kaweth, - usb_sndctrlpipe(kaweth->dev, 0), - KAWETH_COMMAND_SCAN, - USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, - 0, - 0, - (void *)kaweth->firmware_buf, - 8, - KAWETH_CONTROL_TIMEOUT); -} - -/**************************************************************** - * kaweth_reset - ****************************************************************/ -static int kaweth_reset(struct kaweth_device *kaweth) -{ - int result; - - dbg("kaweth_reset(%p)", kaweth); - result = kaweth_control(kaweth, - usb_sndctrlpipe(kaweth->dev, 0), - USB_REQ_SET_CONFIGURATION, - 0, - kaweth->dev->config[0].desc.bConfigurationValue, - 0, - NULL, - 0, - KAWETH_CONTROL_TIMEOUT); - - mdelay(10); - - dbg("kaweth_reset() returns %d.",result); - - return result; -} - -static void kaweth_usb_receive(struct urb *); -static int kaweth_resubmit_rx_urb(struct kaweth_device *, gfp_t); - -/**************************************************************** - int_callback -*****************************************************************/ - -static void kaweth_resubmit_int_urb(struct kaweth_device *kaweth, gfp_t mf) -{ - int status; - - status = usb_submit_urb (kaweth->irq_urb, mf); - if (unlikely(status == -ENOMEM)) { - kaweth->suspend_lowmem_ctrl = 1; - schedule_delayed_work(&kaweth->lowmem_work, HZ/4); - } else { - kaweth->suspend_lowmem_ctrl = 0; - } - - if (status) - err ("can't resubmit intr, %s-%s, status %d", - kaweth->dev->bus->bus_name, - kaweth->dev->devpath, status); -} - -static void int_callback(struct urb *u) -{ - struct kaweth_device *kaweth = u->context; - int act_state; - - switch (u->status) { - case 0: /* success */ - break; - case -ECONNRESET: /* unlink */ - case -ENOENT: - case -ESHUTDOWN: - return; - /* -EPIPE: should clear the halt */ - default: /* error */ - goto resubmit; - } - - /* we check the link state to report changes */ - if (kaweth->linkstate != (act_state = ( kaweth->intbuffer[STATE_OFFSET] | STATE_MASK) >> STATE_SHIFT)) { - if (act_state) - netif_carrier_on(kaweth->net); - else - netif_carrier_off(kaweth->net); - - kaweth->linkstate = act_state; - } -resubmit: - kaweth_resubmit_int_urb(kaweth, GFP_ATOMIC); -} - -static void kaweth_resubmit_tl(struct work_struct *work) -{ - struct kaweth_device *kaweth = - container_of(work, struct kaweth_device, lowmem_work.work); - - if (IS_BLOCKED(kaweth->status)) - return; - - if (kaweth->suspend_lowmem_rx) - kaweth_resubmit_rx_urb(kaweth, GFP_NOIO); - - if (kaweth->suspend_lowmem_ctrl) - kaweth_resubmit_int_urb(kaweth, GFP_NOIO); -} - - -/**************************************************************** - * kaweth_resubmit_rx_urb - ****************************************************************/ -static int kaweth_resubmit_rx_urb(struct kaweth_device *kaweth, - gfp_t mem_flags) -{ - int result; - - usb_fill_bulk_urb(kaweth->rx_urb, - kaweth->dev, - usb_rcvbulkpipe(kaweth->dev, 1), - kaweth->rx_buf, - KAWETH_BUF_SIZE, - kaweth_usb_receive, - kaweth); - kaweth->rx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - kaweth->rx_urb->transfer_dma = kaweth->rxbufferhandle; - - if((result = usb_submit_urb(kaweth->rx_urb, mem_flags))) { - if (result == -ENOMEM) { - kaweth->suspend_lowmem_rx = 1; - schedule_delayed_work(&kaweth->lowmem_work, HZ/4); - } - err("resubmitting rx_urb %d failed", result); - } else { - kaweth->suspend_lowmem_rx = 0; - } - - return result; -} - -static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth); - -/**************************************************************** - * kaweth_usb_receive - ****************************************************************/ -static void kaweth_usb_receive(struct urb *urb) -{ - struct kaweth_device *kaweth = urb->context; - struct net_device *net = kaweth->net; - - int count = urb->actual_length; - int count2 = urb->transfer_buffer_length; - - __u16 pkt_len = le16_to_cpup((__le16 *)kaweth->rx_buf); - - struct sk_buff *skb; - - if(unlikely(urb->status == -ECONNRESET || urb->status == -ESHUTDOWN)) - /* we are killed - set a flag and wake the disconnect handler */ - { - kaweth->end = 1; - wake_up(&kaweth->term_wait); - return; - } - - spin_lock(&kaweth->device_lock); - if (IS_BLOCKED(kaweth->status)) { - spin_unlock(&kaweth->device_lock); - return; - } - spin_unlock(&kaweth->device_lock); - - if(urb->status && urb->status != -EREMOTEIO && count != 1) { - err("%s RX status: %d count: %d packet_len: %d", - net->name, - urb->status, - count, - (int)pkt_len); - kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); - return; - } - - if(kaweth->net && (count > 2)) { - if(pkt_len > (count - 2)) { - err("Packet length too long for USB frame (pkt_len: %x, count: %x)",pkt_len, count); - err("Packet len & 2047: %x", pkt_len & 2047); - err("Count 2: %x", count2); - kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); - return; - } - - if(!(skb = dev_alloc_skb(pkt_len+2))) { - kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); - return; - } - - skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - - eth_copy_and_sum(skb, kaweth->rx_buf + 2, pkt_len, 0); - - skb_put(skb, pkt_len); - - skb->protocol = eth_type_trans(skb, net); - - netif_rx(skb); - - kaweth->stats.rx_packets++; - kaweth->stats.rx_bytes += pkt_len; - } - - kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); -} - -/**************************************************************** - * kaweth_open - ****************************************************************/ -static int kaweth_open(struct net_device *net) -{ - struct kaweth_device *kaweth = netdev_priv(net); - int res; - - dbg("Opening network device."); - - res = usb_autopm_get_interface(kaweth->intf); - if (res) { - err("Interface cannot be resumed."); - return -EIO; - } - res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL); - if (res) - goto err_out; - - usb_fill_int_urb( - kaweth->irq_urb, - kaweth->dev, - usb_rcvintpipe(kaweth->dev, 3), - kaweth->intbuffer, - INTBUFFERSIZE, - int_callback, - kaweth, - 250); /* overriding the descriptor */ - kaweth->irq_urb->transfer_dma = kaweth->intbufferhandle; - kaweth->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - - res = usb_submit_urb(kaweth->irq_urb, GFP_KERNEL); - if (res) { - usb_kill_urb(kaweth->rx_urb); - goto err_out; - } - kaweth->opened = 1; - - netif_start_queue(net); - - kaweth_async_set_rx_mode(kaweth); - return 0; - -err_out: - usb_autopm_enable(kaweth->intf); - return -EIO; -} - -/**************************************************************** - * kaweth_kill_urbs - ****************************************************************/ -static void kaweth_kill_urbs(struct kaweth_device *kaweth) -{ - usb_kill_urb(kaweth->irq_urb); - usb_kill_urb(kaweth->rx_urb); - usb_kill_urb(kaweth->tx_urb); - - flush_scheduled_work(); - - /* a scheduled work may have resubmitted, - we hit them again */ - usb_kill_urb(kaweth->irq_urb); - usb_kill_urb(kaweth->rx_urb); -} - -/**************************************************************** - * kaweth_close - ****************************************************************/ -static int kaweth_close(struct net_device *net) -{ - struct kaweth_device *kaweth = netdev_priv(net); - - netif_stop_queue(net); - kaweth->opened = 0; - - kaweth->status |= KAWETH_STATUS_CLOSING; - - kaweth_kill_urbs(kaweth); - - kaweth->status &= ~KAWETH_STATUS_CLOSING; - - usb_autopm_enable(kaweth->intf); - - return 0; -} - -static void kaweth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) -{ - struct kaweth_device *kaweth = netdev_priv(dev); - - strlcpy(info->driver, driver_name, sizeof(info->driver)); - usb_make_path(kaweth->dev, info->bus_info, sizeof (info->bus_info)); -} - -static u32 kaweth_get_link(struct net_device *dev) -{ - struct kaweth_device *kaweth = netdev_priv(dev); - - return kaweth->linkstate; -} - -static struct ethtool_ops ops = { - .get_drvinfo = kaweth_get_drvinfo, - .get_link = kaweth_get_link -}; - -/**************************************************************** - * kaweth_usb_transmit_complete - ****************************************************************/ -static void kaweth_usb_transmit_complete(struct urb *urb) -{ - struct kaweth_device *kaweth = urb->context; - struct sk_buff *skb = kaweth->tx_skb; - - if (unlikely(urb->status != 0)) - if (urb->status != -ENOENT) - dbg("%s: TX status %d.", kaweth->net->name, urb->status); - - netif_wake_queue(kaweth->net); - dev_kfree_skb_irq(skb); -} - -/**************************************************************** - * kaweth_start_xmit - ****************************************************************/ -static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net) -{ - struct kaweth_device *kaweth = netdev_priv(net); - __le16 *private_header; - - int res; - - spin_lock(&kaweth->device_lock); - - kaweth_async_set_rx_mode(kaweth); - netif_stop_queue(net); - if (IS_BLOCKED(kaweth->status)) { - goto skip; - } - - /* We now decide whether we can put our special header into the sk_buff */ - if (skb_cloned(skb) || skb_headroom(skb) < 2) { - /* no such luck - we make our own */ - struct sk_buff *copied_skb; - copied_skb = skb_copy_expand(skb, 2, 0, GFP_ATOMIC); - dev_kfree_skb_irq(skb); - skb = copied_skb; - if (!copied_skb) { - kaweth->stats.tx_errors++; - netif_start_queue(net); - spin_unlock(&kaweth->device_lock); - return 0; - } - } - - private_header = (__le16 *)__skb_push(skb, 2); - *private_header = cpu_to_le16(skb->len-2); - kaweth->tx_skb = skb; - - usb_fill_bulk_urb(kaweth->tx_urb, - kaweth->dev, - usb_sndbulkpipe(kaweth->dev, 2), - private_header, - skb->len, - kaweth_usb_transmit_complete, - kaweth); - kaweth->end = 0; - - if((res = usb_submit_urb(kaweth->tx_urb, GFP_ATOMIC))) - { - warn("kaweth failed tx_urb %d", res); -skip: - kaweth->stats.tx_errors++; - - netif_start_queue(net); - dev_kfree_skb_irq(skb); - } - else - { - kaweth->stats.tx_packets++; - kaweth->stats.tx_bytes += skb->len; - net->trans_start = jiffies; - } - - spin_unlock(&kaweth->device_lock); - - return 0; -} - -/**************************************************************** - * kaweth_set_rx_mode - ****************************************************************/ -static void kaweth_set_rx_mode(struct net_device *net) -{ - struct kaweth_device *kaweth = netdev_priv(net); - - __u16 packet_filter_bitmap = KAWETH_PACKET_FILTER_DIRECTED | - KAWETH_PACKET_FILTER_BROADCAST | - KAWETH_PACKET_FILTER_MULTICAST; - - dbg("Setting Rx mode to %d", packet_filter_bitmap); - - netif_stop_queue(net); - - if (net->flags & IFF_PROMISC) { - packet_filter_bitmap |= KAWETH_PACKET_FILTER_PROMISCUOUS; - } - else if ((net->mc_count) || (net->flags & IFF_ALLMULTI)) { - packet_filter_bitmap |= KAWETH_PACKET_FILTER_ALL_MULTICAST; - } - - kaweth->packet_filter_bitmap = packet_filter_bitmap; - netif_wake_queue(net); -} - -/**************************************************************** - * kaweth_async_set_rx_mode - ****************************************************************/ -static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth) -{ - __u16 packet_filter_bitmap = kaweth->packet_filter_bitmap; - kaweth->packet_filter_bitmap = 0; - if (packet_filter_bitmap == 0) - return; - - { - int result; - result = kaweth_control(kaweth, - usb_sndctrlpipe(kaweth->dev, 0), - KAWETH_COMMAND_SET_PACKET_FILTER, - USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, - packet_filter_bitmap, - 0, - (void *)&kaweth->scratch, - 0, - KAWETH_CONTROL_TIMEOUT); - - if(result < 0) { - err("Failed to set Rx mode: %d", result); - } - else { - dbg("Set Rx mode to %d", packet_filter_bitmap); - } - } -} - -/**************************************************************** - * kaweth_netdev_stats - ****************************************************************/ -static struct net_device_stats *kaweth_netdev_stats(struct net_device *dev) -{ - struct kaweth_device *kaweth = netdev_priv(dev); - return &kaweth->stats; -} - -/**************************************************************** - * kaweth_tx_timeout - ****************************************************************/ -static void kaweth_tx_timeout(struct net_device *net) -{ - struct kaweth_device *kaweth = netdev_priv(net); - - warn("%s: Tx timed out. Resetting.", net->name); - kaweth->stats.tx_errors++; - net->trans_start = jiffies; - - usb_unlink_urb(kaweth->tx_urb); -} - -/**************************************************************** - * kaweth_suspend - ****************************************************************/ -static int kaweth_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct kaweth_device *kaweth = usb_get_intfdata(intf); - unsigned long flags; - - dbg("Suspending device"); - spin_lock_irqsave(&kaweth->device_lock, flags); - kaweth->status |= KAWETH_STATUS_SUSPENDING; - spin_unlock_irqrestore(&kaweth->device_lock, flags); - - kaweth_kill_urbs(kaweth); - return 0; -} - -/**************************************************************** - * kaweth_resume - ****************************************************************/ -static int kaweth_resume(struct usb_interface *intf) -{ - struct kaweth_device *kaweth = usb_get_intfdata(intf); - unsigned long flags; - - dbg("Resuming device"); - spin_lock_irqsave(&kaweth->device_lock, flags); - kaweth->status &= ~KAWETH_STATUS_SUSPENDING; - spin_unlock_irqrestore(&kaweth->device_lock, flags); - - if (!kaweth->opened) - return 0; - kaweth_resubmit_rx_urb(kaweth, GFP_NOIO); - kaweth_resubmit_int_urb(kaweth, GFP_NOIO); - - return 0; -} - -/**************************************************************** - * kaweth_probe - ****************************************************************/ -static int kaweth_probe( - struct usb_interface *intf, - const struct usb_device_id *id /* from id_table */ - ) -{ - struct usb_device *dev = interface_to_usbdev(intf); - struct kaweth_device *kaweth; - struct net_device *netdev; - const eth_addr_t bcast_addr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; - int result = 0; - - dbg("Kawasaki Device Probe (Device number:%d): 0x%4.4x:0x%4.4x:0x%4.4x", - dev->devnum, - le16_to_cpu(dev->descriptor.idVendor), - le16_to_cpu(dev->descriptor.idProduct), - le16_to_cpu(dev->descriptor.bcdDevice)); - - dbg("Device at %p", dev); - - dbg("Descriptor length: %x type: %x", - (int)dev->descriptor.bLength, - (int)dev->descriptor.bDescriptorType); - - netdev = alloc_etherdev(sizeof(*kaweth)); - if (!netdev) - return -ENOMEM; - - kaweth = netdev_priv(netdev); - kaweth->dev = dev; - kaweth->net = netdev; - - spin_lock_init(&kaweth->device_lock); - init_waitqueue_head(&kaweth->term_wait); - - dbg("Resetting."); - - kaweth_reset(kaweth); - - /* - * If high byte of bcdDevice is nonzero, firmware is already - * downloaded. Don't try to do it again, or we'll hang the device. - */ - - if (le16_to_cpu(dev->descriptor.bcdDevice) >> 8) { - info("Firmware present in device."); - } else { - /* Download the firmware */ - info("Downloading firmware..."); - kaweth->firmware_buf = (__u8 *)__get_free_page(GFP_KERNEL); - if ((result = kaweth_download_firmware(kaweth, - kaweth_new_code, - len_kaweth_new_code, - 100, - 2)) < 0) { - err("Error downloading firmware (%d)", result); - goto err_fw; - } - - if ((result = kaweth_download_firmware(kaweth, - kaweth_new_code_fix, - len_kaweth_new_code_fix, - 100, - 3)) < 0) { - err("Error downloading firmware fix (%d)", result); - goto err_fw; - } - - if ((result = kaweth_download_firmware(kaweth, - kaweth_trigger_code, - len_kaweth_trigger_code, - 126, - 2)) < 0) { - err("Error downloading trigger code (%d)", result); - goto err_fw; - - } - - if ((result = kaweth_download_firmware(kaweth, - kaweth_trigger_code_fix, - len_kaweth_trigger_code_fix, - 126, - 3)) < 0) { - err("Error downloading trigger code fix (%d)", result); - goto err_fw; - } - - - if ((result = kaweth_trigger_firmware(kaweth, 126)) < 0) { - err("Error triggering firmware (%d)", result); - goto err_fw; - } - - /* Device will now disappear for a moment... */ - info("Firmware loaded. I'll be back..."); -err_fw: - free_page((unsigned long)kaweth->firmware_buf); - free_netdev(netdev); - return -EIO; - } - - result = kaweth_read_configuration(kaweth); - - if(result < 0) { - err("Error reading configuration (%d), no net device created", result); - goto err_free_netdev; - } - - info("Statistics collection: %x", kaweth->configuration.statistics_mask); - info("Multicast filter limit: %x", kaweth->configuration.max_multicast_filters & ((1 << 15) - 1)); - info("MTU: %d", le16_to_cpu(kaweth->configuration.segment_size)); - info("Read MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", - (int)kaweth->configuration.hw_addr[0], - (int)kaweth->configuration.hw_addr[1], - (int)kaweth->configuration.hw_addr[2], - (int)kaweth->configuration.hw_addr[3], - (int)kaweth->configuration.hw_addr[4], - (int)kaweth->configuration.hw_addr[5]); - - if(!memcmp(&kaweth->configuration.hw_addr, - &bcast_addr, - sizeof(bcast_addr))) { - err("Firmware not functioning properly, no net device created"); - goto err_free_netdev; - } - - if(kaweth_set_urb_size(kaweth, KAWETH_BUF_SIZE) < 0) { - dbg("Error setting URB size"); - goto err_free_netdev; - } - - if(kaweth_set_sofs_wait(kaweth, KAWETH_SOFS_TO_WAIT) < 0) { - err("Error setting SOFS wait"); - goto err_free_netdev; - } - - result = kaweth_set_receive_filter(kaweth, - KAWETH_PACKET_FILTER_DIRECTED | - KAWETH_PACKET_FILTER_BROADCAST | - KAWETH_PACKET_FILTER_MULTICAST); - - if(result < 0) { - err("Error setting receive filter"); - goto err_free_netdev; - } - - dbg("Initializing net device."); - - kaweth->intf = intf; - - kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!kaweth->tx_urb) - goto err_free_netdev; - kaweth->rx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!kaweth->rx_urb) - goto err_only_tx; - kaweth->irq_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!kaweth->irq_urb) - goto err_tx_and_rx; - - kaweth->intbuffer = usb_buffer_alloc( kaweth->dev, - INTBUFFERSIZE, - GFP_KERNEL, - &kaweth->intbufferhandle); - if (!kaweth->intbuffer) - goto err_tx_and_rx_and_irq; - kaweth->rx_buf = usb_buffer_alloc( kaweth->dev, - KAWETH_BUF_SIZE, - GFP_KERNEL, - &kaweth->rxbufferhandle); - if (!kaweth->rx_buf) - goto err_all_but_rxbuf; - - memcpy(netdev->broadcast, &bcast_addr, sizeof(bcast_addr)); - memcpy(netdev->dev_addr, &kaweth->configuration.hw_addr, - sizeof(kaweth->configuration.hw_addr)); - - netdev->open = kaweth_open; - netdev->stop = kaweth_close; - - netdev->watchdog_timeo = KAWETH_TX_TIMEOUT; - netdev->tx_timeout = kaweth_tx_timeout; - - netdev->hard_start_xmit = kaweth_start_xmit; - netdev->set_multicast_list = kaweth_set_rx_mode; - netdev->get_stats = kaweth_netdev_stats; - netdev->mtu = le16_to_cpu(kaweth->configuration.segment_size); - SET_ETHTOOL_OPS(netdev, &ops); - - /* kaweth is zeroed as part of alloc_netdev */ - - INIT_DELAYED_WORK(&kaweth->lowmem_work, kaweth_resubmit_tl); - - SET_MODULE_OWNER(netdev); - - usb_set_intfdata(intf, kaweth); - -#if 0 -// dma_supported() is deeply broken on almost all architectures - if (dma_supported (&intf->dev, 0xffffffffffffffffULL)) - kaweth->net->features |= NETIF_F_HIGHDMA; -#endif - - SET_NETDEV_DEV(netdev, &intf->dev); - if (register_netdev(netdev) != 0) { - err("Error registering netdev."); - goto err_intfdata; - } - - info("kaweth interface created at %s", kaweth->net->name); - - dbg("Kaweth probe returning."); - - return 0; - -err_intfdata: - usb_set_intfdata(intf, NULL); - usb_buffer_free(kaweth->dev, KAWETH_BUF_SIZE, (void *)kaweth->rx_buf, kaweth->rxbufferhandle); -err_all_but_rxbuf: - usb_buffer_free(kaweth->dev, INTBUFFERSIZE, (void *)kaweth->intbuffer, kaweth->intbufferhandle); -err_tx_and_rx_and_irq: - usb_free_urb(kaweth->irq_urb); -err_tx_and_rx: - usb_free_urb(kaweth->rx_urb); -err_only_tx: - usb_free_urb(kaweth->tx_urb); -err_free_netdev: - free_netdev(netdev); - - return -EIO; -} - -/**************************************************************** - * kaweth_disconnect - ****************************************************************/ -static void kaweth_disconnect(struct usb_interface *intf) -{ - struct kaweth_device *kaweth = usb_get_intfdata(intf); - struct net_device *netdev; - - info("Unregistering"); - - usb_set_intfdata(intf, NULL); - if (!kaweth) { - warn("unregistering non-existant device"); - return; - } - netdev = kaweth->net; - - dbg("Unregistering net device"); - unregister_netdev(netdev); - - usb_free_urb(kaweth->rx_urb); - usb_free_urb(kaweth->tx_urb); - usb_free_urb(kaweth->irq_urb); - - usb_buffer_free(kaweth->dev, KAWETH_BUF_SIZE, (void *)kaweth->rx_buf, kaweth->rxbufferhandle); - usb_buffer_free(kaweth->dev, INTBUFFERSIZE, (void *)kaweth->intbuffer, kaweth->intbufferhandle); - - free_netdev(netdev); -} - - -// FIXME this completion stuff is a modified clone of -// an OLD version of some stuff in usb.c ... -struct usb_api_data { - wait_queue_head_t wqh; - int done; -}; - -/*-------------------------------------------------------------------* - * completion handler for compatibility wrappers (sync control/bulk) * - *-------------------------------------------------------------------*/ -static void usb_api_blocking_completion(struct urb *urb) -{ - struct usb_api_data *awd = (struct usb_api_data *)urb->context; - - awd->done=1; - wake_up(&awd->wqh); -} - -/*-------------------------------------------------------------------* - * COMPATIBILITY STUFF * - *-------------------------------------------------------------------*/ - -// Starts urb and waits for completion or timeout -static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length) -{ - struct usb_api_data awd; - int status; - - init_waitqueue_head(&awd.wqh); - awd.done = 0; - - urb->context = &awd; - status = usb_submit_urb(urb, GFP_NOIO); - if (status) { - // something went wrong - usb_free_urb(urb); - return status; - } - - if (!wait_event_timeout(awd.wqh, awd.done, timeout)) { - // timeout - warn("usb_control/bulk_msg: timeout"); - usb_kill_urb(urb); // remove urb safely - status = -ETIMEDOUT; - } - else { - status = urb->status; - } - - if (actual_length) { - *actual_length = urb->actual_length; - } - - usb_free_urb(urb); - return status; -} - -/*-------------------------------------------------------------------*/ -// returns status (negative) or length (positive) -static int kaweth_internal_control_msg(struct usb_device *usb_dev, - unsigned int pipe, - struct usb_ctrlrequest *cmd, void *data, - int len, int timeout) -{ - struct urb *urb; - int retv; - int length = 0; /* shut up GCC */ - - urb = usb_alloc_urb(0, GFP_NOIO); - if (!urb) - return -ENOMEM; - - usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char*)cmd, data, - len, usb_api_blocking_completion, NULL); - - retv = usb_start_wait_urb(urb, timeout, &length); - if (retv < 0) { - return retv; - } - else { - return length; - } -} - - -/**************************************************************** - * kaweth_init - ****************************************************************/ -static int __init kaweth_init(void) -{ - dbg("Driver loading"); - return usb_register(&kaweth_driver); -} - -/**************************************************************** - * kaweth_exit - ****************************************************************/ -static void __exit kaweth_exit(void) -{ - usb_deregister(&kaweth_driver); -} - -module_init(kaweth_init); -module_exit(kaweth_exit); - - - - - - - - - diff --git a/drivers/usb/net/kawethfw.h b/drivers/usb/net/kawethfw.h deleted file mode 100644 index cf85fcb0d1a6..000000000000 --- a/drivers/usb/net/kawethfw.h +++ /dev/null @@ -1,557 +0,0 @@ -/******************************************/ -/* NOTE: B6/C3 is data header signature */ -/* 0xAA/0xBB is data length = total */ -/* bytes - 7, 0xCC is type, 0xDD is */ -/* interrupt to use. */ -/******************************************/ - -/**************************************************************** - * kaweth_trigger_code - ****************************************************************/ -static __u8 kaweth_trigger_code[] = -{ - 0xB6, 0xC3, 0xAA, 0xBB, 0xCC, 0xDD, - 0xc8, 0x07, 0xa0, 0x00, 0xf0, 0x07, 0x5e, 0x00, - 0x06, 0x00, 0xf0, 0x07, 0x0a, 0x00, 0x08, 0x00, - 0xf0, 0x09, 0x00, 0x00, 0x02, 0x00, 0xe7, 0x07, - 0x36, 0x00, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, - 0x04, 0x00, 0xe7, 0x07, 0x50, 0xc3, 0x10, 0xc0, - 0xf0, 0x09, 0x0e, 0xc0, 0x00, 0x00, 0xe7, 0x87, - 0x01, 0x00, 0x0e, 0xc0, 0x97, 0xcf, 0xd7, 0x09, - 0x00, 0xc0, 0x17, 0x02, 0xc8, 0x07, 0xa0, 0x00, - 0xe7, 0x17, 0x50, 0xc3, 0x10, 0xc0, 0x30, 0xd8, - 0x04, 0x00, 0x30, 0x5c, 0x08, 0x00, 0x04, 0x00, - 0xb0, 0xc0, 0x06, 0x00, 0xc8, 0x05, 0xe7, 0x05, - 0x00, 0xc0, 0xc0, 0xdf, 0x97, 0xcf, 0x49, 0xaf, - 0xc0, 0x07, 0x00, 0x00, 0x60, 0xaf, 0x4a, 0xaf, - 0x00, 0x0c, 0x0c, 0x00, 0x40, 0xd2, 0x00, 0x1c, - 0x0c, 0x00, 0x40, 0xd2, 0x30, 0x00, 0x08, 0x00, - 0xf0, 0x07, 0x00, 0x00, 0x04, 0x00, 0xf0, 0x07, - 0x86, 0x00, 0x06, 0x00, 0x67, 0xcf, 0x27, 0x0c, - 0x02, 0x00, 0x00, 0x00, 0x27, 0x0c, 0x00, 0x00, - 0x0e, 0xc0, 0x49, 0xaf, 0x64, 0xaf, 0xc0, 0x07, - 0x00, 0x00, 0x4b, 0xaf, 0x4a, 0xaf, 0x5a, 0xcf, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x94, 0x00, 0x05, 0x00, - 0x00, 0x00 -}; -/**************************************************************** - * kaweth_trigger_code_fix - ****************************************************************/ -static __u8 kaweth_trigger_code_fix[] = -{ - 0xB6, 0xC3, 0xAA, 0xBB, 0xCC, 0xDD, - 0x02, 0x00, 0x06, 0x00, 0x18, 0x00, 0x3e, 0x00, - 0x80, 0x00, 0x98, 0x00, 0xaa, 0x00, - 0x00, 0x00 -}; - -/**************************************************************** - * kaweth_new_code - ****************************************************************/ -static __u8 kaweth_new_code[] = -{ - 0xB6, 0xC3, 0xAA, 0xBB, 0xCC, 0xDD, - 0x9f, 0xcf, 0xde, 0x06, 0xe7, 0x57, 0x00, 0x00, - 0xc4, 0x06, 0x97, 0xc1, 0xe7, 0x67, 0xff, 0x1f, - 0x28, 0xc0, 0xe7, 0x87, 0x00, 0x04, 0x24, 0xc0, - 0xe7, 0x67, 0xff, 0xf9, 0x22, 0xc0, 0x97, 0xcf, - 0xd7, 0x09, 0x00, 0xc0, 0xe7, 0x09, 0xa2, 0xc0, - 0xbe, 0x06, 0x9f, 0xaf, 0x36, 0x00, 0xe7, 0x05, - 0x00, 0xc0, 0xa7, 0xcf, 0xbc, 0x06, 0x97, 0xcf, - 0xe7, 0x57, 0x00, 0x00, 0xb8, 0x06, 0xa7, 0xa1, - 0xb8, 0x06, 0x97, 0xcf, 0xe7, 0x57, 0x00, 0x00, - 0x14, 0x08, 0x0a, 0xc0, 0xe7, 0x57, 0x00, 0x00, - 0xa4, 0xc0, 0xa7, 0xc0, 0x7a, 0x06, 0x9f, 0xaf, - 0x92, 0x07, 0xe7, 0x07, 0x00, 0x00, 0x14, 0x08, - 0xe7, 0x57, 0xff, 0xff, 0xba, 0x06, 0x9f, 0xa0, - 0x38, 0x00, 0xe7, 0x59, 0xba, 0x06, 0xbe, 0x06, - 0x9f, 0xa0, 0x38, 0x00, 0xc8, 0x09, 0xca, 0x06, - 0x08, 0x62, 0x9f, 0xa1, 0x36, 0x08, 0xc0, 0x09, - 0x76, 0x06, 0x00, 0x60, 0xa7, 0xc0, 0x7a, 0x06, - 0x9f, 0xaf, 0xcc, 0x02, 0xe7, 0x57, 0x00, 0x00, - 0xb8, 0x06, 0xa7, 0xc1, 0x7a, 0x06, 0x9f, 0xaf, - 0x04, 0x00, 0xe7, 0x57, 0x00, 0x00, 0x8e, 0x06, - 0x0a, 0xc1, 0xe7, 0x09, 0x20, 0xc0, 0x10, 0x08, - 0xe7, 0xd0, 0x10, 0x08, 0xe7, 0x67, 0x40, 0x00, - 0x10, 0x08, 0x9f, 0xaf, 0x92, 0x0c, 0xc0, 0x09, - 0xd0, 0x06, 0x00, 0x60, 0x05, 0xc4, 0xc0, 0x59, - 0xbe, 0x06, 0x02, 0xc0, 0x9f, 0xaf, 0xec, 0x00, - 0x9f, 0xaf, 0x34, 0x02, 0xe7, 0x57, 0x00, 0x00, - 0xa6, 0x06, 0x9f, 0xa0, 0x7a, 0x02, 0xa7, 0xcf, - 0x7a, 0x06, 0x48, 0x02, 0xe7, 0x09, 0xbe, 0x06, - 0xd0, 0x06, 0xc8, 0x37, 0x04, 0x00, 0x9f, 0xaf, - 0x08, 0x03, 0x97, 0xcf, 0xe7, 0x57, 0x00, 0x00, - 0xce, 0x06, 0x97, 0xc0, 0xd7, 0x09, 0x00, 0xc0, - 0xc1, 0xdf, 0xc8, 0x09, 0xc6, 0x06, 0x08, 0x62, - 0x14, 0xc0, 0x27, 0x04, 0xc6, 0x06, 0x10, 0x94, - 0xf0, 0x07, 0x10, 0x08, 0x02, 0x00, 0xc1, 0x07, - 0x01, 0x00, 0x70, 0x00, 0x04, 0x00, 0xf0, 0x07, - 0x30, 0x01, 0x06, 0x00, 0x50, 0xaf, 0xe7, 0x07, - 0xff, 0xff, 0xd0, 0x06, 0xe7, 0x07, 0x00, 0x00, - 0xce, 0x06, 0xe7, 0x05, 0x00, 0xc0, 0x97, 0xcf, - 0xd7, 0x09, 0x00, 0xc0, 0xc1, 0xdf, 0x48, 0x02, - 0xd0, 0x09, 0xc6, 0x06, 0x27, 0x02, 0xc6, 0x06, - 0xe7, 0x05, 0x00, 0xc0, 0x97, 0xcf, 0x48, 0x02, - 0xc8, 0x37, 0x04, 0x00, 0x00, 0x0c, 0x0c, 0x00, - 0x00, 0x60, 0x21, 0xc0, 0xc0, 0x37, 0x3e, 0x00, - 0x23, 0xc9, 0xc0, 0x57, 0xb4, 0x05, 0x1b, 0xc8, - 0xc0, 0x17, 0x3f, 0x00, 0xc0, 0x67, 0xc0, 0xff, - 0x30, 0x00, 0x08, 0x00, 0xf0, 0x07, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x02, 0xc0, 0x17, 0x4c, 0x00, - 0x30, 0x00, 0x06, 0x00, 0xf0, 0x07, 0xa0, 0x01, - 0x0a, 0x00, 0x48, 0x02, 0xc1, 0x07, 0x02, 0x00, - 0xd7, 0x09, 0x00, 0xc0, 0xc1, 0xdf, 0x51, 0xaf, - 0xe7, 0x05, 0x00, 0xc0, 0x97, 0xcf, 0x9f, 0xaf, - 0x08, 0x03, 0x9f, 0xaf, 0x7a, 0x02, 0x97, 0xcf, - 0x9f, 0xaf, 0x7a, 0x02, 0xc9, 0x37, 0x04, 0x00, - 0xc1, 0xdf, 0xc8, 0x09, 0xa2, 0x06, 0x50, 0x02, - 0x67, 0x02, 0xa2, 0x06, 0xd1, 0x07, 0x00, 0x00, - 0x27, 0xd8, 0xaa, 0x06, 0xc0, 0xdf, 0x9f, 0xaf, - 0xc4, 0x01, 0x97, 0xcf, 0xe7, 0x57, 0x00, 0x00, - 0xd2, 0x06, 0x97, 0xc1, 0xe7, 0x57, 0x01, 0x00, - 0xa8, 0x06, 0x97, 0xc0, 0xc8, 0x09, 0xa0, 0x06, - 0x08, 0x62, 0x97, 0xc0, 0x00, 0x02, 0xc0, 0x17, - 0x0e, 0x00, 0x27, 0x00, 0x34, 0x01, 0x27, 0x0c, - 0x0c, 0x00, 0x36, 0x01, 0xe7, 0x07, 0x50, 0xc3, - 0x12, 0xc0, 0xe7, 0x07, 0xcc, 0x0b, 0x02, 0x00, - 0xe7, 0x07, 0x01, 0x00, 0xa8, 0x06, 0xe7, 0x07, - 0x05, 0x00, 0x90, 0xc0, 0x97, 0xcf, 0xc8, 0x09, - 0xa4, 0x06, 0x08, 0x62, 0x02, 0xc0, 0x10, 0x64, - 0x07, 0xc1, 0xe7, 0x07, 0x00, 0x00, 0x9e, 0x06, - 0xe7, 0x07, 0x72, 0x04, 0x24, 0x00, 0x97, 0xcf, - 0x27, 0x04, 0xa4, 0x06, 0xc8, 0x17, 0x0e, 0x00, - 0x27, 0x02, 0x9e, 0x06, 0xe7, 0x07, 0x80, 0x04, - 0x24, 0x00, 0x97, 0xcf, 0xd7, 0x09, 0x00, 0xc0, - 0xc1, 0xdf, 0xe7, 0x57, 0x00, 0x00, 0x90, 0x06, - 0x13, 0xc1, 0x9f, 0xaf, 0x06, 0x02, 0xe7, 0x57, - 0x00, 0x00, 0x9e, 0x06, 0x13, 0xc0, 0xe7, 0x09, - 0x9e, 0x06, 0x30, 0x01, 0xe7, 0x07, 0xf2, 0x05, - 0x32, 0x01, 0xe7, 0x07, 0x10, 0x00, 0x96, 0xc0, - 0xe7, 0x09, 0x9e, 0x06, 0x90, 0x06, 0x04, 0xcf, - 0xe7, 0x57, 0x00, 0x00, 0x9e, 0x06, 0x02, 0xc1, - 0x9f, 0xaf, 0x06, 0x02, 0xe7, 0x05, 0x00, 0xc0, - 0x97, 0xcf, 0xd7, 0x09, 0x00, 0xc0, 0xc1, 0xdf, - 0x08, 0x92, 0xe7, 0x57, 0x02, 0x00, 0xaa, 0x06, - 0x02, 0xc3, 0xc8, 0x09, 0xa4, 0x06, 0x27, 0x02, - 0xa6, 0x06, 0x08, 0x62, 0x03, 0xc1, 0xe7, 0x05, - 0x00, 0xc0, 0x97, 0xcf, 0x27, 0x04, 0xa4, 0x06, - 0xe7, 0x05, 0x00, 0xc0, 0xf0, 0x07, 0x40, 0x00, - 0x08, 0x00, 0xf0, 0x07, 0x00, 0x00, 0x04, 0x00, - 0x00, 0x02, 0xc0, 0x17, 0x0c, 0x00, 0x30, 0x00, - 0x06, 0x00, 0xf0, 0x07, 0x46, 0x01, 0x0a, 0x00, - 0xc8, 0x17, 0x04, 0x00, 0xc1, 0x07, 0x02, 0x00, - 0x51, 0xaf, 0x97, 0xcf, 0xe7, 0x57, 0x00, 0x00, - 0x96, 0x06, 0x97, 0xc0, 0xc1, 0xdf, 0xc8, 0x09, - 0x96, 0x06, 0x27, 0x04, 0x96, 0x06, 0x27, 0x52, - 0x98, 0x06, 0x03, 0xc1, 0xe7, 0x07, 0x96, 0x06, - 0x98, 0x06, 0xc0, 0xdf, 0x17, 0x02, 0xc8, 0x17, - 0x0e, 0x00, 0x9f, 0xaf, 0xba, 0x03, 0xc8, 0x05, - 0x00, 0x60, 0x03, 0xc0, 0x9f, 0xaf, 0x24, 0x03, - 0x97, 0xcf, 0x9f, 0xaf, 0x08, 0x03, 0x97, 0xcf, - 0x57, 0x02, 0xc9, 0x07, 0xa4, 0x06, 0xd7, 0x09, - 0x00, 0xc0, 0xc1, 0xdf, 0x08, 0x62, 0x1b, 0xc0, - 0x50, 0x04, 0x11, 0x02, 0xe7, 0x05, 0x00, 0xc0, - 0xc9, 0x05, 0x97, 0xcf, 0x97, 0x02, 0xca, 0x09, - 0xd6, 0x06, 0xf2, 0x17, 0x01, 0x00, 0x04, 0x00, - 0xf2, 0x27, 0x00, 0x00, 0x06, 0x00, 0xca, 0x17, - 0x2c, 0x00, 0xf8, 0x77, 0x01, 0x00, 0x0e, 0x00, - 0x06, 0xc0, 0xca, 0xd9, 0xf8, 0x57, 0xff, 0x00, - 0x0e, 0x00, 0x01, 0xc1, 0xca, 0xd9, 0x22, 0x1c, - 0x0c, 0x00, 0xe2, 0x27, 0x00, 0x00, 0xe2, 0x17, - 0x01, 0x00, 0xe2, 0x27, 0x00, 0x00, 0xca, 0x05, - 0x00, 0x0c, 0x0c, 0x00, 0xc0, 0x17, 0x41, 0x00, - 0xc0, 0x67, 0xc0, 0xff, 0x30, 0x00, 0x08, 0x00, - 0x00, 0x02, 0xc0, 0x17, 0x0c, 0x00, 0x30, 0x00, - 0x06, 0x00, 0xf0, 0x07, 0xda, 0x00, 0x0a, 0x00, - 0xf0, 0x07, 0x00, 0x00, 0x04, 0x00, 0x00, 0x0c, - 0x08, 0x00, 0x40, 0xd1, 0x01, 0x00, 0xc0, 0x19, - 0xce, 0x06, 0xc0, 0x59, 0xc2, 0x06, 0x04, 0xc9, - 0x49, 0xaf, 0x9f, 0xaf, 0xec, 0x00, 0x4a, 0xaf, - 0x67, 0x10, 0xce, 0x06, 0xc8, 0x17, 0x04, 0x00, - 0xc1, 0x07, 0x01, 0x00, 0xd7, 0x09, 0x00, 0xc0, - 0xc1, 0xdf, 0x50, 0xaf, 0xe7, 0x05, 0x00, 0xc0, - 0x97, 0xcf, 0xc0, 0x07, 0x01, 0x00, 0xc1, 0x09, - 0xac, 0x06, 0xc1, 0x77, 0x01, 0x00, 0x97, 0xc1, - 0xd8, 0x77, 0x01, 0x00, 0x12, 0xc0, 0xc9, 0x07, - 0x6a, 0x06, 0x9f, 0xaf, 0x08, 0x04, 0x04, 0xc1, - 0xc1, 0x77, 0x08, 0x00, 0x13, 0xc0, 0x97, 0xcf, - 0xc1, 0x77, 0x02, 0x00, 0x97, 0xc1, 0xc1, 0x77, - 0x10, 0x00, 0x0c, 0xc0, 0x9f, 0xaf, 0x2c, 0x04, - 0x97, 0xcf, 0xc1, 0x77, 0x04, 0x00, 0x06, 0xc0, - 0xc9, 0x07, 0x70, 0x06, 0x9f, 0xaf, 0x08, 0x04, - 0x97, 0xc0, 0x00, 0xcf, 0x00, 0x90, 0x97, 0xcf, - 0x50, 0x54, 0x97, 0xc1, 0x70, 0x5c, 0x02, 0x00, - 0x02, 0x00, 0x97, 0xc1, 0x70, 0x5c, 0x04, 0x00, - 0x04, 0x00, 0x97, 0xcf, 0x80, 0x01, 0xc0, 0x00, - 0x60, 0x00, 0x30, 0x00, 0x18, 0x00, 0x0c, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xcb, 0x09, 0xb2, 0x06, - 0xcc, 0x09, 0xb4, 0x06, 0x0b, 0x53, 0x11, 0xc0, - 0xc9, 0x02, 0xca, 0x07, 0x1c, 0x04, 0x9f, 0xaf, - 0x08, 0x04, 0x97, 0xc0, 0x0a, 0xc8, 0x82, 0x08, - 0x0a, 0xcf, 0x82, 0x08, 0x9f, 0xaf, 0x08, 0x04, - 0x97, 0xc0, 0x05, 0xc2, 0x89, 0x30, 0x82, 0x60, - 0x78, 0xc1, 0x00, 0x90, 0x97, 0xcf, 0x89, 0x10, - 0x09, 0x53, 0x79, 0xc2, 0x89, 0x30, 0x82, 0x08, - 0x7a, 0xcf, 0xc0, 0xdf, 0x97, 0xcf, 0xc0, 0xdf, - 0x97, 0xcf, 0xe7, 0x09, 0x96, 0xc0, 0x92, 0x06, - 0xe7, 0x09, 0x98, 0xc0, 0x94, 0x06, 0x0f, 0xcf, - 0xe7, 0x09, 0x96, 0xc0, 0x92, 0x06, 0xe7, 0x09, - 0x98, 0xc0, 0x94, 0x06, 0xe7, 0x09, 0x9e, 0x06, - 0x30, 0x01, 0xe7, 0x07, 0xf2, 0x05, 0x32, 0x01, - 0xe7, 0x07, 0x10, 0x00, 0x96, 0xc0, 0xd7, 0x09, - 0x00, 0xc0, 0x17, 0x02, 0xc8, 0x09, 0x90, 0x06, - 0xc8, 0x37, 0x0e, 0x00, 0xe7, 0x77, 0x2a, 0x00, - 0x92, 0x06, 0x30, 0xc0, 0x97, 0x02, 0xca, 0x09, - 0xd6, 0x06, 0xe7, 0x77, 0x20, 0x00, 0x92, 0x06, - 0x0e, 0xc0, 0xf2, 0x17, 0x01, 0x00, 0x10, 0x00, - 0xf2, 0x27, 0x00, 0x00, 0x12, 0x00, 0xe7, 0x77, - 0x0a, 0x00, 0x92, 0x06, 0xca, 0x05, 0x1e, 0xc0, - 0x97, 0x02, 0xca, 0x09, 0xd6, 0x06, 0xf2, 0x17, - 0x01, 0x00, 0x0c, 0x00, 0xf2, 0x27, 0x00, 0x00, - 0x0e, 0x00, 0xe7, 0x77, 0x02, 0x00, 0x92, 0x06, - 0x07, 0xc0, 0xf2, 0x17, 0x01, 0x00, 0x44, 0x00, - 0xf2, 0x27, 0x00, 0x00, 0x46, 0x00, 0x06, 0xcf, - 0xf2, 0x17, 0x01, 0x00, 0x60, 0x00, 0xf2, 0x27, - 0x00, 0x00, 0x62, 0x00, 0xca, 0x05, 0x9f, 0xaf, - 0x08, 0x03, 0x0f, 0xcf, 0x57, 0x02, 0x09, 0x02, - 0xf1, 0x09, 0x94, 0x06, 0x0c, 0x00, 0xf1, 0xda, - 0x0c, 0x00, 0xc8, 0x09, 0x98, 0x06, 0x50, 0x02, - 0x67, 0x02, 0x98, 0x06, 0xd1, 0x07, 0x00, 0x00, - 0xc9, 0x05, 0xe7, 0x09, 0x9e, 0x06, 0x90, 0x06, - 0xe7, 0x57, 0x00, 0x00, 0x90, 0x06, 0x02, 0xc0, - 0x9f, 0xaf, 0x06, 0x02, 0xc8, 0x05, 0xe7, 0x05, - 0x00, 0xc0, 0xc0, 0xdf, 0x97, 0xcf, 0xd7, 0x09, - 0x00, 0xc0, 0x17, 0x00, 0x17, 0x02, 0x97, 0x02, - 0xc0, 0x09, 0x92, 0xc0, 0xe7, 0x07, 0x04, 0x00, - 0x90, 0xc0, 0xca, 0x09, 0xd6, 0x06, 0xe7, 0x07, - 0x00, 0x00, 0xa8, 0x06, 0xe7, 0x07, 0x6a, 0x04, - 0x02, 0x00, 0xc0, 0x77, 0x02, 0x00, 0x08, 0xc0, - 0xf2, 0x17, 0x01, 0x00, 0x50, 0x00, 0xf2, 0x27, - 0x00, 0x00, 0x52, 0x00, 0x9f, 0xcf, 0x24, 0x06, - 0xc0, 0x77, 0x10, 0x00, 0x06, 0xc0, 0xf2, 0x17, - 0x01, 0x00, 0x58, 0x00, 0xf2, 0x27, 0x00, 0x00, - 0x5a, 0x00, 0xc0, 0x77, 0x80, 0x00, 0x06, 0xc0, - 0xf2, 0x17, 0x01, 0x00, 0x70, 0x00, 0xf2, 0x27, - 0x00, 0x00, 0x72, 0x00, 0xc0, 0x77, 0x08, 0x00, - 0x1d, 0xc1, 0xf2, 0x17, 0x01, 0x00, 0x08, 0x00, - 0xf2, 0x27, 0x00, 0x00, 0x0a, 0x00, 0xc0, 0x77, - 0x00, 0x02, 0x06, 0xc0, 0xf2, 0x17, 0x01, 0x00, - 0x64, 0x00, 0xf2, 0x27, 0x00, 0x00, 0x66, 0x00, - 0xc0, 0x77, 0x40, 0x00, 0x06, 0xc0, 0xf2, 0x17, - 0x01, 0x00, 0x5c, 0x00, 0xf2, 0x27, 0x00, 0x00, - 0x5e, 0x00, 0xc0, 0x77, 0x01, 0x00, 0x01, 0xc0, - 0x1b, 0xcf, 0x1a, 0xcf, 0xf2, 0x17, 0x01, 0x00, - 0x00, 0x00, 0xf2, 0x27, 0x00, 0x00, 0x02, 0x00, - 0xc8, 0x09, 0x34, 0x01, 0xca, 0x17, 0x14, 0x00, - 0xd8, 0x77, 0x01, 0x00, 0x05, 0xc0, 0xca, 0xd9, - 0xd8, 0x57, 0xff, 0x00, 0x01, 0xc0, 0xca, 0xd9, - 0xe2, 0x19, 0x94, 0xc0, 0xe2, 0x27, 0x00, 0x00, - 0xe2, 0x17, 0x01, 0x00, 0xe2, 0x27, 0x00, 0x00, - 0x9f, 0xaf, 0x40, 0x06, 0x9f, 0xaf, 0xc4, 0x01, - 0xe7, 0x57, 0x00, 0x00, 0xd2, 0x06, 0x9f, 0xa1, - 0x0e, 0x0a, 0xca, 0x05, 0xc8, 0x05, 0xc0, 0x05, - 0xe7, 0x05, 0x00, 0xc0, 0xc0, 0xdf, 0x97, 0xcf, - 0xc8, 0x09, 0xa0, 0x06, 0x08, 0x62, 0x97, 0xc0, - 0x27, 0x04, 0xa0, 0x06, 0x27, 0x52, 0xa2, 0x06, - 0x03, 0xc1, 0xe7, 0x07, 0xa0, 0x06, 0xa2, 0x06, - 0x9f, 0xaf, 0x08, 0x03, 0xe7, 0x57, 0x00, 0x00, - 0xaa, 0x06, 0x02, 0xc0, 0x27, 0xda, 0xaa, 0x06, - 0x97, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xfb, 0x13, 0xe7, 0x57, - 0x00, 0x80, 0xb2, 0x00, 0x06, 0xc2, 0xe7, 0x07, - 0xee, 0x0b, 0x12, 0x00, 0xe7, 0x07, 0x34, 0x0c, - 0xb2, 0x00, 0xe7, 0x07, 0xc6, 0x07, 0xf2, 0x02, - 0xc8, 0x09, 0xb4, 0x00, 0xf8, 0x07, 0x02, 0x00, - 0x0d, 0x00, 0xd7, 0x09, 0x0e, 0xc0, 0xe7, 0x07, - 0x00, 0x00, 0x0e, 0xc0, 0xc8, 0x09, 0xde, 0x00, - 0xc8, 0x17, 0x09, 0x00, 0xc9, 0x07, 0xda, 0x06, - 0xc0, 0x07, 0x04, 0x00, 0x68, 0x0a, 0x00, 0xda, - 0x7d, 0xc1, 0xe7, 0x09, 0xc0, 0x00, 0x7c, 0x06, - 0xe7, 0x09, 0xbe, 0x00, 0x78, 0x06, 0xe7, 0x09, - 0x10, 0x00, 0xbc, 0x06, 0xc8, 0x07, 0xd6, 0x07, - 0x9f, 0xaf, 0xae, 0x07, 0x9f, 0xaf, 0x00, 0x0a, - 0xc8, 0x09, 0xde, 0x00, 0x00, 0x0e, 0x0f, 0x00, - 0x41, 0x90, 0x9f, 0xde, 0x06, 0x00, 0x44, 0xaf, - 0x27, 0x00, 0xb2, 0x06, 0x27, 0x00, 0xb4, 0x06, - 0x27, 0x00, 0xb6, 0x06, 0xc0, 0x07, 0x74, 0x00, - 0x44, 0xaf, 0x27, 0x00, 0xd6, 0x06, 0x08, 0x00, - 0x00, 0x90, 0xc1, 0x07, 0x3a, 0x00, 0x20, 0x00, - 0x01, 0xda, 0x7d, 0xc1, 0x9f, 0xaf, 0xba, 0x09, - 0xc0, 0x07, 0x44, 0x00, 0x48, 0xaf, 0x27, 0x00, - 0x7a, 0x06, 0x9f, 0xaf, 0x96, 0x0a, 0xe7, 0x07, - 0x01, 0x00, 0xc0, 0x06, 0xe7, 0x05, 0x0e, 0xc0, - 0x97, 0xcf, 0x49, 0xaf, 0xe7, 0x87, 0x43, 0x00, - 0x0e, 0xc0, 0xe7, 0x07, 0xff, 0xff, 0xbe, 0x06, - 0x9f, 0xaf, 0xae, 0x0a, 0xc0, 0x07, 0x01, 0x00, - 0x60, 0xaf, 0x4a, 0xaf, 0x97, 0xcf, 0x00, 0x08, - 0x09, 0x08, 0x11, 0x08, 0x00, 0xda, 0x7c, 0xc1, - 0x97, 0xcf, 0x67, 0x04, 0xcc, 0x02, 0xc0, 0xdf, - 0x51, 0x94, 0xb1, 0xaf, 0x06, 0x00, 0xc1, 0xdf, - 0xc9, 0x09, 0xcc, 0x02, 0x49, 0x62, 0x75, 0xc1, - 0xc0, 0xdf, 0xa7, 0xcf, 0xd6, 0x02, 0x0e, 0x00, - 0x24, 0x00, 0x80, 0x04, 0x22, 0x00, 0x4e, 0x05, - 0xd0, 0x00, 0x0e, 0x0a, 0xaa, 0x00, 0x30, 0x08, - 0xbe, 0x00, 0x4a, 0x0a, 0x10, 0x00, 0x20, 0x00, - 0x04, 0x00, 0x6e, 0x04, 0x02, 0x00, 0x6a, 0x04, - 0x06, 0x00, 0x00, 0x00, 0x24, 0xc0, 0x04, 0x04, - 0x28, 0xc0, 0xfe, 0xfb, 0x1e, 0xc0, 0x00, 0x04, - 0x22, 0xc0, 0xff, 0xf4, 0xc0, 0x00, 0x90, 0x09, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x56, 0x08, - 0x60, 0x08, 0xd0, 0x08, 0xda, 0x08, 0x00, 0x09, - 0x04, 0x09, 0x08, 0x09, 0x32, 0x09, 0x42, 0x09, - 0x50, 0x09, 0x52, 0x09, 0x5a, 0x09, 0x5a, 0x09, - 0x27, 0x02, 0xca, 0x06, 0x97, 0xcf, 0xe7, 0x07, - 0x00, 0x00, 0xca, 0x06, 0x0a, 0x0e, 0x01, 0x00, - 0xca, 0x57, 0x0e, 0x00, 0x9f, 0xc3, 0x5a, 0x09, - 0xca, 0x37, 0x00, 0x00, 0x9f, 0xc2, 0x5a, 0x09, - 0x0a, 0xd2, 0xb2, 0xcf, 0x16, 0x08, 0xc8, 0x09, - 0xde, 0x00, 0x07, 0x06, 0x9f, 0xcf, 0x6c, 0x09, - 0x17, 0x02, 0xc8, 0x09, 0xde, 0x00, 0x00, 0x0e, - 0x0f, 0x00, 0x41, 0x90, 0x9f, 0xde, 0x06, 0x00, - 0xc8, 0x05, 0x30, 0x50, 0x06, 0x00, 0x9f, 0xc8, - 0x5a, 0x09, 0x27, 0x0c, 0x02, 0x00, 0xb0, 0x06, - 0xc0, 0x09, 0xb2, 0x06, 0x27, 0x00, 0xb4, 0x06, - 0xe7, 0x07, 0x00, 0x00, 0xae, 0x06, 0x27, 0x00, - 0x80, 0x06, 0x00, 0x1c, 0x06, 0x00, 0x27, 0x00, - 0xb6, 0x06, 0x41, 0x90, 0x67, 0x50, 0xb0, 0x06, - 0x0d, 0xc0, 0x67, 0x00, 0x7e, 0x06, 0x27, 0x0c, - 0x06, 0x00, 0x82, 0x06, 0xe7, 0x07, 0xbc, 0x08, - 0x84, 0x06, 0xc8, 0x07, 0x7e, 0x06, 0x41, 0x90, - 0x51, 0xaf, 0x97, 0xcf, 0x9f, 0xaf, 0x48, 0x0c, - 0xe7, 0x09, 0xb6, 0x06, 0xb4, 0x06, 0xe7, 0x09, - 0xb0, 0x06, 0xae, 0x06, 0x59, 0xaf, 0x97, 0xcf, - 0x27, 0x0c, 0x02, 0x00, 0xac, 0x06, 0x59, 0xaf, - 0x97, 0xcf, 0x09, 0x0c, 0x02, 0x00, 0x09, 0xda, - 0x49, 0xd2, 0xc9, 0x19, 0xd6, 0x06, 0xc8, 0x07, - 0x7e, 0x06, 0xe0, 0x07, 0x00, 0x00, 0x60, 0x02, - 0xe0, 0x07, 0x04, 0x00, 0xd0, 0x07, 0xcc, 0x08, - 0x48, 0xdb, 0x41, 0x90, 0x50, 0xaf, 0x97, 0xcf, - 0x59, 0xaf, 0x97, 0xcf, 0x59, 0xaf, 0x97, 0xcf, - 0xf0, 0x57, 0x06, 0x00, 0x06, 0x00, 0x25, 0xc1, - 0xe7, 0x07, 0x70, 0x06, 0x80, 0x06, 0x41, 0x90, - 0x67, 0x00, 0x7e, 0x06, 0x27, 0x0c, 0x06, 0x00, - 0x82, 0x06, 0xe7, 0x07, 0x8c, 0x09, 0x84, 0x06, - 0xc8, 0x07, 0x7e, 0x06, 0x41, 0x90, 0x51, 0xaf, - 0x97, 0xcf, 0x07, 0x0c, 0x06, 0x00, 0xc7, 0x57, - 0x06, 0x00, 0x0f, 0xc1, 0xc8, 0x07, 0x70, 0x06, - 0x15, 0xcf, 0x00, 0x0c, 0x02, 0x00, 0x00, 0xda, - 0x40, 0xd1, 0x27, 0x00, 0xc2, 0x06, 0x1e, 0xcf, - 0x1d, 0xcf, 0x27, 0x0c, 0x02, 0x00, 0xcc, 0x06, - 0x19, 0xcf, 0x27, 0x02, 0x20, 0x01, 0xe7, 0x07, - 0x08, 0x00, 0x22, 0x01, 0xe7, 0x07, 0x13, 0x00, - 0xb0, 0xc0, 0x97, 0xcf, 0x41, 0x90, 0x67, 0x00, - 0x7e, 0x06, 0xe7, 0x01, 0x82, 0x06, 0x27, 0x02, - 0x80, 0x06, 0xe7, 0x07, 0x8c, 0x09, 0x84, 0x06, - 0xc8, 0x07, 0x7e, 0x06, 0xc1, 0x07, 0x00, 0x80, - 0x50, 0xaf, 0x97, 0xcf, 0x59, 0xaf, 0x97, 0xcf, - 0x00, 0x60, 0x05, 0xc0, 0xe7, 0x07, 0x00, 0x00, - 0xc4, 0x06, 0xa7, 0xcf, 0x7c, 0x06, 0x9f, 0xaf, - 0x00, 0x0a, 0xe7, 0x07, 0x01, 0x00, 0xc4, 0x06, - 0x49, 0xaf, 0xd7, 0x09, 0x00, 0xc0, 0x07, 0xaf, - 0xe7, 0x05, 0x00, 0xc0, 0x4a, 0xaf, 0xa7, 0xcf, - 0x7c, 0x06, 0xc0, 0x07, 0xfe, 0x7f, 0x44, 0xaf, - 0x40, 0x00, 0xc0, 0x37, 0x00, 0x01, 0x41, 0x90, - 0xc0, 0x37, 0x08, 0x00, 0xdf, 0xde, 0x50, 0x06, - 0xc0, 0x57, 0x10, 0x00, 0x02, 0xc2, 0xc0, 0x07, - 0x10, 0x00, 0x27, 0x00, 0x9a, 0x06, 0x41, 0x90, - 0x9f, 0xde, 0x40, 0x06, 0x44, 0xaf, 0x27, 0x00, - 0x9c, 0x06, 0xc0, 0x09, 0x9a, 0x06, 0x41, 0x90, - 0x00, 0xd2, 0x00, 0xd8, 0x9f, 0xde, 0x08, 0x00, - 0x44, 0xaf, 0x27, 0x00, 0xc8, 0x06, 0x97, 0xcf, - 0xe7, 0x87, 0x00, 0x84, 0x28, 0xc0, 0xe7, 0x67, - 0xff, 0xfb, 0x24, 0xc0, 0x97, 0xcf, 0xe7, 0x87, - 0x01, 0x00, 0xd2, 0x06, 0xe7, 0x57, 0x00, 0x00, - 0xa8, 0x06, 0x97, 0xc1, 0x9f, 0xaf, 0x00, 0x0a, - 0xe7, 0x87, 0x00, 0x06, 0x22, 0xc0, 0xe7, 0x07, - 0x00, 0x00, 0x90, 0xc0, 0xe7, 0x67, 0xfe, 0xff, - 0x3e, 0xc0, 0xe7, 0x07, 0x26, 0x00, 0x0a, 0xc0, - 0xe7, 0x87, 0x01, 0x00, 0x3e, 0xc0, 0xe7, 0x07, - 0xff, 0xff, 0xbe, 0x06, 0x9f, 0xaf, 0x10, 0x0b, - 0x97, 0xcf, 0x17, 0x00, 0xa7, 0xaf, 0x78, 0x06, - 0xc0, 0x05, 0x27, 0x00, 0x76, 0x06, 0xe7, 0x87, - 0x01, 0x00, 0xd2, 0x06, 0x9f, 0xaf, 0x00, 0x0a, - 0xe7, 0x07, 0x0c, 0x00, 0x40, 0xc0, 0x9f, 0xaf, - 0x10, 0x0b, 0x00, 0x90, 0x27, 0x00, 0xa6, 0x06, - 0x27, 0x00, 0xaa, 0x06, 0xe7, 0x09, 0xb2, 0x06, - 0xb4, 0x06, 0x27, 0x00, 0xae, 0x06, 0x27, 0x00, - 0xac, 0x06, 0x9f, 0xaf, 0xae, 0x0a, 0xc0, 0x07, - 0x00, 0x00, 0x27, 0x00, 0xb2, 0x02, 0x27, 0x00, - 0xb4, 0x02, 0x27, 0x00, 0x8e, 0x06, 0xc0, 0x07, - 0x06, 0x00, 0xc8, 0x09, 0xde, 0x00, 0xc8, 0x17, - 0x03, 0x00, 0xc9, 0x07, 0x70, 0x06, 0x29, 0x0a, - 0x00, 0xda, 0x7d, 0xc1, 0x97, 0xcf, 0xd7, 0x09, - 0x00, 0xc0, 0xc1, 0xdf, 0x00, 0x90, 0x27, 0x00, - 0x96, 0x06, 0xe7, 0x07, 0x96, 0x06, 0x98, 0x06, - 0x27, 0x00, 0xa0, 0x06, 0xe7, 0x07, 0xa0, 0x06, - 0xa2, 0x06, 0x27, 0x00, 0xa6, 0x06, 0x27, 0x00, - 0x90, 0x06, 0x27, 0x00, 0x9e, 0x06, 0xc8, 0x09, - 0x9c, 0x06, 0xc1, 0x09, 0x9a, 0x06, 0xc9, 0x07, - 0xa4, 0x06, 0x11, 0x02, 0x09, 0x02, 0xc8, 0x17, - 0x40, 0x06, 0x01, 0xda, 0x7a, 0xc1, 0x51, 0x94, - 0xc8, 0x09, 0xc8, 0x06, 0xc9, 0x07, 0xc6, 0x06, - 0xc1, 0x09, 0x9a, 0x06, 0x11, 0x02, 0x09, 0x02, - 0xc8, 0x17, 0x08, 0x00, 0x01, 0xda, 0x7a, 0xc1, - 0x51, 0x94, 0xe7, 0x05, 0x00, 0xc0, 0x97, 0xcf, - 0xe7, 0x57, 0x00, 0x00, 0x76, 0x06, 0x97, 0xc0, - 0x9f, 0xaf, 0x04, 0x00, 0xe7, 0x09, 0xbe, 0x06, - 0xba, 0x06, 0xe7, 0x57, 0xff, 0xff, 0xba, 0x06, - 0x04, 0xc1, 0xe7, 0x07, 0x10, 0x0b, 0xb8, 0x06, - 0x97, 0xcf, 0xe7, 0x17, 0x32, 0x00, 0xba, 0x06, - 0xe7, 0x67, 0xff, 0x07, 0xba, 0x06, 0xe7, 0x07, - 0x46, 0x0b, 0xb8, 0x06, 0x97, 0xcf, 0xe7, 0x57, - 0x00, 0x00, 0xc0, 0x06, 0x23, 0xc0, 0xe7, 0x07, - 0x04, 0x00, 0x90, 0xc0, 0xe7, 0x07, 0x00, 0x80, - 0x80, 0xc0, 0xe7, 0x07, 0x00, 0x00, 0x80, 0xc0, - 0xe7, 0x07, 0x00, 0x80, 0x80, 0xc0, 0xc0, 0x07, - 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0xc0, 0x07, - 0x00, 0x00, 0xe7, 0x07, 0x00, 0x00, 0x80, 0xc0, - 0xe7, 0x07, 0x00, 0x80, 0x80, 0xc0, 0xe7, 0x07, - 0x00, 0x80, 0x40, 0xc0, 0xc0, 0x07, 0x00, 0x00, - 0xe7, 0x07, 0x00, 0x00, 0x40, 0xc0, 0xe7, 0x07, - 0x00, 0x00, 0x80, 0xc0, 0xe7, 0x07, 0x04, 0x00, - 0x90, 0xc0, 0xe7, 0x07, 0x00, 0x02, 0x40, 0xc0, - 0xe7, 0x07, 0x0c, 0x02, 0x40, 0xc0, 0xe7, 0x07, - 0x00, 0x00, 0xc0, 0x06, 0xe7, 0x07, 0x00, 0x00, - 0xb8, 0x06, 0xe7, 0x07, 0x00, 0x00, 0xd2, 0x06, - 0xd7, 0x09, 0x00, 0xc0, 0xc1, 0xdf, 0x9f, 0xaf, - 0x34, 0x02, 0xe7, 0x05, 0x00, 0xc0, 0x9f, 0xaf, - 0xc4, 0x01, 0x97, 0xcf, 0xd7, 0x09, 0x00, 0xc0, - 0x17, 0x00, 0x17, 0x02, 0x97, 0x02, 0xe7, 0x57, - 0x00, 0x00, 0xa8, 0x06, 0x06, 0xc0, 0xc0, 0x09, - 0x92, 0xc0, 0xc0, 0x77, 0x09, 0x02, 0x9f, 0xc1, - 0x5c, 0x05, 0x9f, 0xcf, 0x32, 0x06, 0xd7, 0x09, - 0x0e, 0xc0, 0xe7, 0x07, 0x00, 0x00, 0x0e, 0xc0, - 0x9f, 0xaf, 0x02, 0x0c, 0xe7, 0x05, 0x0e, 0xc0, - 0x97, 0xcf, 0xd7, 0x09, 0x00, 0xc0, 0x17, 0x02, - 0xc8, 0x09, 0xb0, 0xc0, 0xe7, 0x67, 0xfe, 0x7f, - 0xb0, 0xc0, 0xc8, 0x77, 0x00, 0x20, 0x9f, 0xc1, - 0x64, 0xeb, 0xe7, 0x57, 0x00, 0x00, 0xc8, 0x02, - 0x9f, 0xc1, 0x80, 0xeb, 0xc8, 0x99, 0xca, 0x02, - 0xc8, 0x67, 0x04, 0x00, 0x9f, 0xc1, 0x96, 0xeb, - 0x9f, 0xcf, 0x4c, 0xeb, 0xe7, 0x07, 0x00, 0x00, - 0xa6, 0xc0, 0xe7, 0x09, 0xb0, 0xc0, 0xc8, 0x02, - 0xe7, 0x07, 0x03, 0x00, 0xb0, 0xc0, 0x97, 0xcf, - 0xc0, 0x09, 0xb0, 0x06, 0xc0, 0x37, 0x01, 0x00, - 0x97, 0xc9, 0xc9, 0x09, 0xb2, 0x06, 0x02, 0x00, - 0x41, 0x90, 0x48, 0x02, 0xc9, 0x17, 0x06, 0x00, - 0x9f, 0xaf, 0x08, 0x04, 0x9f, 0xa2, 0x72, 0x0c, - 0x02, 0xda, 0x77, 0xc1, 0x41, 0x60, 0x71, 0xc1, - 0x97, 0xcf, 0x17, 0x02, 0x57, 0x02, 0x43, 0x04, - 0x21, 0x04, 0xe0, 0x00, 0x43, 0x04, 0x21, 0x04, - 0xe0, 0x00, 0x43, 0x04, 0x21, 0x04, 0xe0, 0x00, - 0xc1, 0x07, 0x01, 0x00, 0xc9, 0x05, 0xc8, 0x05, - 0x97, 0xcf, 0xe7, 0x07, 0x01, 0x00, 0x8e, 0x06, - 0xc8, 0x07, 0x86, 0x06, 0xe7, 0x07, 0x00, 0x00, - 0x86, 0x06, 0xe7, 0x07, 0x10, 0x08, 0x88, 0x06, - 0xe7, 0x07, 0x04, 0x00, 0x8a, 0x06, 0xe7, 0x07, - 0xbc, 0x0c, 0x8c, 0x06, 0xc1, 0x07, 0x03, 0x80, - 0x50, 0xaf, 0x97, 0xcf, 0xe7, 0x07, 0x00, 0x00, - 0x8e, 0x06, 0x97, 0xcf, - 0x00, 0x00 -}; - -/**************************************************************** - * kaweth_new_code_fix - ****************************************************************/ -static __u8 kaweth_new_code_fix[] = -{ - 0xB6, 0xC3, 0xAA, 0xBB, 0xCC, 0xDD, - 0x02, 0x00, 0x08, 0x00, 0x28, 0x00, 0x2c, 0x00, - 0x34, 0x00, 0x3c, 0x00, 0x40, 0x00, 0x48, 0x00, - 0x54, 0x00, 0x58, 0x00, 0x5e, 0x00, 0x64, 0x00, - 0x68, 0x00, 0x6e, 0x00, 0x6c, 0x00, 0x72, 0x00, - 0x76, 0x00, 0x7c, 0x00, 0x80, 0x00, 0x86, 0x00, - 0x8a, 0x00, 0x90, 0x00, 0x94, 0x00, 0x98, 0x00, - 0x9e, 0x00, 0xa6, 0x00, 0xaa, 0x00, 0xb0, 0x00, - 0xb4, 0x00, 0xb8, 0x00, 0xc0, 0x00, 0xc6, 0x00, - 0xca, 0x00, 0xd0, 0x00, 0xd4, 0x00, 0xd8, 0x00, - 0xe0, 0x00, 0xde, 0x00, 0xe8, 0x00, 0xf0, 0x00, - 0xfc, 0x00, 0x04, 0x01, 0x0a, 0x01, 0x18, 0x01, - 0x22, 0x01, 0x28, 0x01, 0x3a, 0x01, 0x3e, 0x01, - 0x7e, 0x01, 0x98, 0x01, 0x9c, 0x01, 0xa2, 0x01, - 0xac, 0x01, 0xb2, 0x01, 0xba, 0x01, 0xc0, 0x01, - 0xc8, 0x01, 0xd0, 0x01, 0xd6, 0x01, 0xf4, 0x01, - 0xfc, 0x01, 0x08, 0x02, 0x16, 0x02, 0x1a, 0x02, - 0x22, 0x02, 0x2a, 0x02, 0x2e, 0x02, 0x3e, 0x02, - 0x44, 0x02, 0x4a, 0x02, 0x50, 0x02, 0x64, 0x02, - 0x62, 0x02, 0x6c, 0x02, 0x72, 0x02, 0x86, 0x02, - 0x8c, 0x02, 0x90, 0x02, 0x9e, 0x02, 0xbc, 0x02, - 0xd0, 0x02, 0xd8, 0x02, 0xdc, 0x02, 0xe0, 0x02, - 0xe8, 0x02, 0xe6, 0x02, 0xf4, 0x02, 0xfe, 0x02, - 0x04, 0x03, 0x0c, 0x03, 0x28, 0x03, 0x7c, 0x03, - 0x90, 0x03, 0x94, 0x03, 0x9c, 0x03, 0xa2, 0x03, - 0xc0, 0x03, 0xd0, 0x03, 0xd4, 0x03, 0xee, 0x03, - 0xfa, 0x03, 0xfe, 0x03, 0x2e, 0x04, 0x32, 0x04, - 0x3c, 0x04, 0x40, 0x04, 0x4e, 0x04, 0x76, 0x04, - 0x7c, 0x04, 0x84, 0x04, 0x8a, 0x04, 0x8e, 0x04, - 0xa6, 0x04, 0xb0, 0x04, 0xb8, 0x04, 0xbe, 0x04, - 0xd2, 0x04, 0xdc, 0x04, 0xee, 0x04, 0x10, 0x05, - 0x1a, 0x05, 0x24, 0x05, 0x2a, 0x05, 0x36, 0x05, - 0x34, 0x05, 0x3c, 0x05, 0x42, 0x05, 0x64, 0x05, - 0x6a, 0x05, 0x6e, 0x05, 0x86, 0x05, 0x22, 0x06, - 0x26, 0x06, 0x2c, 0x06, 0x30, 0x06, 0x42, 0x06, - 0x4a, 0x06, 0x4e, 0x06, 0x56, 0x06, 0x54, 0x06, - 0x5a, 0x06, 0x60, 0x06, 0x66, 0x06, 0xe8, 0x06, - 0xee, 0x06, 0xf4, 0x06, 0x16, 0x07, 0x26, 0x07, - 0x2c, 0x07, 0x32, 0x07, 0x36, 0x07, 0x3a, 0x07, - 0x3e, 0x07, 0x52, 0x07, 0x56, 0x07, 0x5a, 0x07, - 0x64, 0x07, 0x76, 0x07, 0x7a, 0x07, 0x80, 0x07, - 0x84, 0x07, 0x8a, 0x07, 0x9e, 0x07, 0xa2, 0x07, - 0xda, 0x07, 0xde, 0x07, 0xe2, 0x07, 0xe6, 0x07, - 0xea, 0x07, 0xee, 0x07, 0xf2, 0x07, 0xf6, 0x07, - 0x0e, 0x08, 0x16, 0x08, 0x18, 0x08, 0x1a, 0x08, - 0x1c, 0x08, 0x1e, 0x08, 0x20, 0x08, 0x22, 0x08, - 0x24, 0x08, 0x26, 0x08, 0x28, 0x08, 0x2a, 0x08, - 0x2c, 0x08, 0x2e, 0x08, 0x32, 0x08, 0x3a, 0x08, - 0x46, 0x08, 0x4e, 0x08, 0x54, 0x08, 0x5e, 0x08, - 0x78, 0x08, 0x7e, 0x08, 0x82, 0x08, 0x86, 0x08, - 0x8c, 0x08, 0x90, 0x08, 0x98, 0x08, 0x9e, 0x08, - 0xa4, 0x08, 0xaa, 0x08, 0xb0, 0x08, 0xae, 0x08, - 0xb4, 0x08, 0xbe, 0x08, 0xc4, 0x08, 0xc2, 0x08, - 0xca, 0x08, 0xc8, 0x08, 0xd4, 0x08, 0xe4, 0x08, - 0xe8, 0x08, 0xf6, 0x08, 0x14, 0x09, 0x12, 0x09, - 0x1a, 0x09, 0x20, 0x09, 0x26, 0x09, 0x24, 0x09, - 0x2a, 0x09, 0x3e, 0x09, 0x4c, 0x09, 0x56, 0x09, - 0x70, 0x09, 0x74, 0x09, 0x78, 0x09, 0x7e, 0x09, - 0x7c, 0x09, 0x82, 0x09, 0x98, 0x09, 0x9c, 0x09, - 0xa0, 0x09, 0xa6, 0x09, 0xb8, 0x09, 0xdc, 0x09, - 0xe8, 0x09, 0xec, 0x09, 0xfc, 0x09, 0x12, 0x0a, - 0x18, 0x0a, 0x1e, 0x0a, 0x42, 0x0a, 0x46, 0x0a, - 0x4e, 0x0a, 0x54, 0x0a, 0x5a, 0x0a, 0x5e, 0x0a, - 0x68, 0x0a, 0x6e, 0x0a, 0x72, 0x0a, 0x78, 0x0a, - 0x76, 0x0a, 0x7c, 0x0a, 0x80, 0x0a, 0x84, 0x0a, - 0x94, 0x0a, 0xa4, 0x0a, 0xb8, 0x0a, 0xbe, 0x0a, - 0xbc, 0x0a, 0xc2, 0x0a, 0xc8, 0x0a, 0xc6, 0x0a, - 0xcc, 0x0a, 0xd0, 0x0a, 0xd4, 0x0a, 0xd8, 0x0a, - 0xdc, 0x0a, 0xe0, 0x0a, 0xf2, 0x0a, 0xf6, 0x0a, - 0xfa, 0x0a, 0x14, 0x0b, 0x1a, 0x0b, 0x20, 0x0b, - 0x1e, 0x0b, 0x26, 0x0b, 0x2e, 0x0b, 0x2c, 0x0b, - 0x36, 0x0b, 0x3c, 0x0b, 0x42, 0x0b, 0x40, 0x0b, - 0x4a, 0x0b, 0xaa, 0x0b, 0xb0, 0x0b, 0xb6, 0x0b, - 0xc0, 0x0b, 0xc8, 0x0b, 0xda, 0x0b, 0xe8, 0x0b, - 0xec, 0x0b, 0xfa, 0x0b, 0x4a, 0x0c, 0x54, 0x0c, - 0x62, 0x0c, 0x66, 0x0c, 0x96, 0x0c, 0x9a, 0x0c, - 0xa0, 0x0c, 0xa6, 0x0c, 0xa4, 0x0c, 0xac, 0x0c, - 0xb2, 0x0c, 0xb0, 0x0c, 0xc0, 0x0c, - 0x00, 0x00 -}; - - -static const int len_kaweth_trigger_code = sizeof(kaweth_trigger_code); -static const int len_kaweth_trigger_code_fix = sizeof(kaweth_trigger_code_fix); -static const int len_kaweth_new_code = sizeof(kaweth_new_code); -static const int len_kaweth_new_code_fix = sizeof(kaweth_new_code_fix); diff --git a/drivers/usb/net/mcs7830.c b/drivers/usb/net/mcs7830.c deleted file mode 100644 index 6240b978fe3d..000000000000 --- a/drivers/usb/net/mcs7830.c +++ /dev/null @@ -1,534 +0,0 @@ -/* - * MosChips MCS7830 based USB 2.0 Ethernet Devices - * - * based on usbnet.c, asix.c and the vendor provided mcs7830 driver - * - * Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de> - * 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 - * 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 - */ - -#include <linux/crc32.h> -#include <linux/etherdevice.h> -#include <linux/ethtool.h> -#include <linux/init.h> -#include <linux/mii.h> -#include <linux/module.h> -#include <linux/netdevice.h> -#include <linux/usb.h> - -#include "usbnet.h" - -/* requests */ -#define MCS7830_RD_BMREQ (USB_DIR_IN | USB_TYPE_VENDOR | \ - USB_RECIP_DEVICE) -#define MCS7830_WR_BMREQ (USB_DIR_OUT | USB_TYPE_VENDOR | \ - USB_RECIP_DEVICE) -#define MCS7830_RD_BREQ 0x0E -#define MCS7830_WR_BREQ 0x0D - -#define MCS7830_CTRL_TIMEOUT 1000 -#define MCS7830_MAX_MCAST 64 - -#define MCS7830_VENDOR_ID 0x9710 -#define MCS7830_PRODUCT_ID 0x7830 - -#define MCS7830_MII_ADVERTISE (ADVERTISE_PAUSE_CAP | ADVERTISE_100FULL | \ - ADVERTISE_100HALF | ADVERTISE_10FULL | \ - ADVERTISE_10HALF | ADVERTISE_CSMA) - -/* HIF_REG_XX coressponding index value */ -enum { - HIF_REG_MULTICAST_HASH = 0x00, - HIF_REG_PACKET_GAP1 = 0x08, - HIF_REG_PACKET_GAP2 = 0x09, - HIF_REG_PHY_DATA = 0x0a, - HIF_REG_PHY_CMD1 = 0x0c, - HIF_REG_PHY_CMD1_READ = 0x40, - HIF_REG_PHY_CMD1_WRITE = 0x20, - HIF_REG_PHY_CMD1_PHYADDR = 0x01, - HIF_REG_PHY_CMD2 = 0x0d, - HIF_REG_PHY_CMD2_PEND_FLAG_BIT = 0x80, - HIF_REG_PHY_CMD2_READY_FLAG_BIT = 0x40, - HIF_REG_CONFIG = 0x0e, - HIF_REG_CONFIG_CFG = 0x80, - HIF_REG_CONFIG_SPEED100 = 0x40, - HIF_REG_CONFIG_FULLDUPLEX_ENABLE = 0x20, - HIF_REG_CONFIG_RXENABLE = 0x10, - HIF_REG_CONFIG_TXENABLE = 0x08, - HIF_REG_CONFIG_SLEEPMODE = 0x04, - HIF_REG_CONFIG_ALLMULTICAST = 0x02, - HIF_REG_CONFIG_PROMISCIOUS = 0x01, - HIF_REG_ETHERNET_ADDR = 0x0f, - HIF_REG_22 = 0x15, - HIF_REG_PAUSE_THRESHOLD = 0x16, - HIF_REG_PAUSE_THRESHOLD_DEFAULT = 0, -}; - -struct mcs7830_data { - u8 multi_filter[8]; - u8 config; -}; - -static const char driver_name[] = "MOSCHIP usb-ethernet driver"; - -static int mcs7830_get_reg(struct usbnet *dev, u16 index, u16 size, void *data) -{ - struct usb_device *xdev = dev->udev; - int ret; - - ret = usb_control_msg(xdev, usb_rcvctrlpipe(xdev, 0), MCS7830_RD_BREQ, - MCS7830_RD_BMREQ, 0x0000, index, data, - size, msecs_to_jiffies(MCS7830_CTRL_TIMEOUT)); - return ret; -} - -static int mcs7830_set_reg(struct usbnet *dev, u16 index, u16 size, void *data) -{ - struct usb_device *xdev = dev->udev; - int ret; - - ret = usb_control_msg(xdev, usb_sndctrlpipe(xdev, 0), MCS7830_WR_BREQ, - MCS7830_WR_BMREQ, 0x0000, index, data, - size, msecs_to_jiffies(MCS7830_CTRL_TIMEOUT)); - return ret; -} - -static void mcs7830_async_cmd_callback(struct urb *urb) -{ - struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; - - if (urb->status < 0) - printk(KERN_DEBUG "mcs7830_async_cmd_callback() failed with %d", - urb->status); - - kfree(req); - usb_free_urb(urb); -} - -static void mcs7830_set_reg_async(struct usbnet *dev, u16 index, u16 size, void *data) -{ - struct usb_ctrlrequest *req; - int ret; - struct urb *urb; - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) { - dev_dbg(&dev->udev->dev, "Error allocating URB " - "in write_cmd_async!"); - return; - } - - req = kmalloc(sizeof *req, GFP_ATOMIC); - if (!req) { - dev_err(&dev->udev->dev, "Failed to allocate memory for " - "control request"); - goto out; - } - req->bRequestType = MCS7830_WR_BMREQ; - req->bRequest = MCS7830_WR_BREQ; - req->wValue = 0; - 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, - mcs7830_async_cmd_callback, req); - - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret < 0) { - dev_err(&dev->udev->dev, "Error submitting the control " - "message: ret=%d", ret); - goto out; - } - return; -out: - kfree(req); - usb_free_urb(urb); -} - -static int mcs7830_get_address(struct usbnet *dev) -{ - int ret; - ret = mcs7830_get_reg(dev, HIF_REG_ETHERNET_ADDR, ETH_ALEN, - dev->net->dev_addr); - if (ret < 0) - return ret; - return 0; -} - -static int mcs7830_read_phy(struct usbnet *dev, u8 index) -{ - int ret; - int i; - __le16 val; - - u8 cmd[2] = { - HIF_REG_PHY_CMD1_READ | HIF_REG_PHY_CMD1_PHYADDR, - HIF_REG_PHY_CMD2_PEND_FLAG_BIT | index, - }; - - mutex_lock(&dev->phy_mutex); - /* write the MII command */ - ret = mcs7830_set_reg(dev, HIF_REG_PHY_CMD1, 2, cmd); - if (ret < 0) - goto out; - - /* wait for the data to become valid, should be within < 1ms */ - for (i = 0; i < 10; i++) { - ret = mcs7830_get_reg(dev, HIF_REG_PHY_CMD1, 2, cmd); - if ((ret < 0) || (cmd[1] & HIF_REG_PHY_CMD2_READY_FLAG_BIT)) - break; - ret = -EIO; - msleep(1); - } - if (ret < 0) - goto out; - - /* read actual register contents */ - ret = mcs7830_get_reg(dev, HIF_REG_PHY_DATA, 2, &val); - if (ret < 0) - goto out; - ret = le16_to_cpu(val); - dev_dbg(&dev->udev->dev, "read PHY reg %02x: %04x (%d tries)\n", - index, val, i); -out: - mutex_unlock(&dev->phy_mutex); - return ret; -} - -static int mcs7830_write_phy(struct usbnet *dev, u8 index, u16 val) -{ - int ret; - int i; - __le16 le_val; - - u8 cmd[2] = { - HIF_REG_PHY_CMD1_WRITE | HIF_REG_PHY_CMD1_PHYADDR, - HIF_REG_PHY_CMD2_PEND_FLAG_BIT | (index & 0x1F), - }; - - mutex_lock(&dev->phy_mutex); - - /* write the new register contents */ - le_val = cpu_to_le16(val); - ret = mcs7830_set_reg(dev, HIF_REG_PHY_DATA, 2, &le_val); - if (ret < 0) - goto out; - - /* write the MII command */ - ret = mcs7830_set_reg(dev, HIF_REG_PHY_CMD1, 2, cmd); - if (ret < 0) - goto out; - - /* wait for the command to be accepted by the PHY */ - for (i = 0; i < 10; i++) { - ret = mcs7830_get_reg(dev, HIF_REG_PHY_CMD1, 2, cmd); - if ((ret < 0) || (cmd[1] & HIF_REG_PHY_CMD2_READY_FLAG_BIT)) - break; - ret = -EIO; - msleep(1); - } - if (ret < 0) - goto out; - - ret = 0; - dev_dbg(&dev->udev->dev, "write PHY reg %02x: %04x (%d tries)\n", - index, val, i); -out: - mutex_unlock(&dev->phy_mutex); - return ret; -} - -/* - * This algorithm comes from the original mcs7830 version 1.4 driver, - * not sure if it is needed. - */ -static int mcs7830_set_autoneg(struct usbnet *dev, int ptrUserPhyMode) -{ - int ret; - /* Enable all media types */ - ret = mcs7830_write_phy(dev, MII_ADVERTISE, MCS7830_MII_ADVERTISE); - - /* First reset BMCR */ - if (!ret) - ret = mcs7830_write_phy(dev, MII_BMCR, 0x0000); - /* Enable Auto Neg */ - if (!ret) - ret = mcs7830_write_phy(dev, MII_BMCR, BMCR_ANENABLE); - /* Restart Auto Neg (Keep the Enable Auto Neg Bit Set) */ - if (!ret) - ret = mcs7830_write_phy(dev, MII_BMCR, - BMCR_ANENABLE | BMCR_ANRESTART ); - return ret < 0 ? : 0; -} - - -/* - * if we can read register 22, the chip revision is C or higher - */ -static int mcs7830_get_rev(struct usbnet *dev) -{ - u8 dummy[2]; - int ret; - ret = mcs7830_get_reg(dev, HIF_REG_22, 2, dummy); - if (ret > 0) - return 2; /* Rev C or later */ - return 1; /* earlier revision */ -} - -/* - * On rev. C we need to set the pause threshold - */ -static void mcs7830_rev_C_fixup(struct usbnet *dev) -{ - u8 pause_threshold = HIF_REG_PAUSE_THRESHOLD_DEFAULT; - int retry; - - for (retry = 0; retry < 2; retry++) { - if (mcs7830_get_rev(dev) == 2) { - dev_info(&dev->udev->dev, "applying rev.C fixup\n"); - mcs7830_set_reg(dev, HIF_REG_PAUSE_THRESHOLD, - 1, &pause_threshold); - } - msleep(1); - } -} - -static int mcs7830_init_dev(struct usbnet *dev) -{ - int ret; - int retry; - - /* Read MAC address from EEPROM */ - ret = -EINVAL; - for (retry = 0; retry < 5 && ret; retry++) - ret = mcs7830_get_address(dev); - if (ret) { - dev_warn(&dev->udev->dev, "Cannot read MAC address\n"); - goto out; - } - - /* Set up PHY */ - ret = mcs7830_set_autoneg(dev, 0); - if (ret) { - dev_info(&dev->udev->dev, "Cannot set autoneg\n"); - goto out; - } - - mcs7830_rev_C_fixup(dev); - ret = 0; -out: - return ret; -} - -static int mcs7830_mdio_read(struct net_device *netdev, int phy_id, - int location) -{ - struct usbnet *dev = netdev->priv; - return mcs7830_read_phy(dev, location); -} - -static void mcs7830_mdio_write(struct net_device *netdev, int phy_id, - int location, int val) -{ - struct usbnet *dev = netdev->priv; - mcs7830_write_phy(dev, location, val); -} - -static int mcs7830_ioctl(struct net_device *net, struct ifreq *rq, int cmd) -{ - struct usbnet *dev = netdev_priv(net); - return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); -} - -/* credits go to asix_set_multicast */ -static void mcs7830_set_multicast(struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - struct mcs7830_data *data = (struct mcs7830_data *)&dev->data; - - data->config = HIF_REG_CONFIG_TXENABLE; - - /* this should not be needed, but it doesn't work otherwise */ - data->config |= HIF_REG_CONFIG_ALLMULTICAST; - - if (net->flags & IFF_PROMISC) { - data->config |= HIF_REG_CONFIG_PROMISCIOUS; - } else if (net->flags & IFF_ALLMULTI - || net->mc_count > MCS7830_MAX_MCAST) { - data->config |= HIF_REG_CONFIG_ALLMULTICAST; - } 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, sizeof data->multi_filter); - - /* 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; - } - - mcs7830_set_reg_async(dev, HIF_REG_MULTICAST_HASH, - sizeof data->multi_filter, - data->multi_filter); - } - - mcs7830_set_reg_async(dev, HIF_REG_CONFIG, 1, &data->config); -} - -static int mcs7830_get_regs_len(struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - - switch (mcs7830_get_rev(dev)) { - case 1: - return 21; - case 2: - return 32; - } - return 0; -} - -static void mcs7830_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *drvinfo) -{ - usbnet_get_drvinfo(net, drvinfo); - drvinfo->regdump_len = mcs7830_get_regs_len(net); -} - -static void mcs7830_get_regs(struct net_device *net, struct ethtool_regs *regs, void *data) -{ - struct usbnet *dev = netdev_priv(net); - - regs->version = mcs7830_get_rev(dev); - mcs7830_get_reg(dev, 0, regs->len, data); -} - -static struct ethtool_ops mcs7830_ethtool_ops = { - .get_drvinfo = mcs7830_get_drvinfo, - .get_regs_len = mcs7830_get_regs_len, - .get_regs = mcs7830_get_regs, - - /* common usbnet calls */ - .get_link = usbnet_get_link, - .get_msglevel = usbnet_get_msglevel, - .set_msglevel = usbnet_set_msglevel, - .get_settings = usbnet_get_settings, - .set_settings = usbnet_set_settings, - .nway_reset = usbnet_nway_reset, -}; - -static int mcs7830_bind(struct usbnet *dev, struct usb_interface *udev) -{ - struct net_device *net = dev->net; - int ret; - - ret = mcs7830_init_dev(dev); - if (ret) - goto out; - - net->do_ioctl = mcs7830_ioctl; - net->ethtool_ops = &mcs7830_ethtool_ops; - net->set_multicast_list = mcs7830_set_multicast; - mcs7830_set_multicast(net); - - /* reserve space for the status byte on rx */ - dev->rx_urb_size = ETH_FRAME_LEN + 1; - - dev->mii.mdio_read = mcs7830_mdio_read; - dev->mii.mdio_write = mcs7830_mdio_write; - dev->mii.dev = net; - dev->mii.phy_id_mask = 0x3f; - dev->mii.reg_num_mask = 0x1f; - dev->mii.phy_id = *((u8 *) net->dev_addr + 1); - - ret = usbnet_get_endpoints(dev, udev); -out: - return ret; -} - -/* The chip always appends a status bytes that we need to strip */ -static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb) -{ - u8 status; - - if (skb->len == 0) { - dev_err(&dev->udev->dev, "unexpected empty rx frame\n"); - return 0; - } - - skb_trim(skb, skb->len - 1); - status = skb->data[skb->len]; - - if (status != 0x20) - dev_dbg(&dev->udev->dev, "rx fixup status %x\n", status); - - return skb->len > 0; -} - -static const struct driver_info moschip_info = { - .description = "MOSCHIP 7830 usb-NET adapter", - .bind = mcs7830_bind, - .rx_fixup = mcs7830_rx_fixup, - .flags = FLAG_ETHER, - .in = 1, - .out = 2, -}; - -static const struct usb_device_id products[] = { - { - USB_DEVICE(MCS7830_VENDOR_ID, MCS7830_PRODUCT_ID), - .driver_info = (unsigned long) &moschip_info, - }, - {}, -}; -MODULE_DEVICE_TABLE(usb, products); - -static struct usb_driver mcs7830_driver = { - .name = driver_name, - .id_table = products, - .probe = usbnet_probe, - .disconnect = usbnet_disconnect, - .suspend = usbnet_suspend, - .resume = usbnet_resume, -}; - -static int __init mcs7830_init(void) -{ - return usb_register(&mcs7830_driver); -} -module_init(mcs7830_init); - -static void __exit mcs7830_exit(void) -{ - usb_deregister(&mcs7830_driver); -} -module_exit(mcs7830_exit); - -MODULE_DESCRIPTION("USB to network adapter MCS7830)"); -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/net/net1080.c b/drivers/usb/net/net1080.c deleted file mode 100644 index 19bf8dae70c9..000000000000 --- a/drivers/usb/net/net1080.c +++ /dev/null @@ -1,615 +0,0 @@ -/* - * Net1080 based USB host-to-host cables - * Copyright (C) 2000-2005 by David Brownell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -// #define DEBUG // error path messages, extra info -// #define VERBOSE // more; success messages - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/ethtool.h> -#include <linux/workqueue.h> -#include <linux/mii.h> -#include <linux/usb.h> - -#include <asm/unaligned.h> - -#include "usbnet.h" - - -/* - * Netchip 1080 driver ... http://www.netchip.com - * (Sept 2004: End-of-life announcement has been sent.) - * Used in (some) LapLink cables - */ - -#define frame_errors data[1] - -/* - * NetChip framing of ethernet packets, supporting additional error - * checks for links that may drop bulk packets from inside messages. - * Odd USB length == always short read for last usb packet. - * - nc_header - * - Ethernet header (14 bytes) - * - payload - * - (optional padding byte, if needed so length becomes odd) - * - nc_trailer - * - * This framing is to be avoided for non-NetChip devices. - */ - -struct nc_header { // packed: - __le16 hdr_len; // sizeof nc_header (LE, all) - __le16 packet_len; // payload size (including ethhdr) - __le16 packet_id; // detects dropped packets -#define MIN_HEADER 6 - - // all else is optional, and must start with: - // __le16 vendorId; // from usb-if - // __le16 productId; -} __attribute__((__packed__)); - -#define PAD_BYTE ((unsigned char)0xAC) - -struct nc_trailer { - __le16 packet_id; -} __attribute__((__packed__)); - -// packets may use FLAG_FRAMING_NC and optional pad -#define FRAMED_SIZE(mtu) (sizeof (struct nc_header) \ - + sizeof (struct ethhdr) \ - + (mtu) \ - + 1 \ - + sizeof (struct nc_trailer)) - -#define MIN_FRAMED FRAMED_SIZE(0) - -/* packets _could_ be up to 64KB... */ -#define NC_MAX_PACKET 32767 - - -/* - * Zero means no timeout; else, how long a 64 byte bulk packet may be queued - * before the hardware drops it. If that's done, the driver will need to - * frame network packets to guard against the dropped USB packets. The win32 - * driver sets this for both sides of the link. - */ -#define NC_READ_TTL_MS ((u8)255) // ms - -/* - * We ignore most registers and EEPROM contents. - */ -#define REG_USBCTL ((u8)0x04) -#define REG_TTL ((u8)0x10) -#define REG_STATUS ((u8)0x11) - -/* - * Vendor specific requests to read/write data - */ -#define REQUEST_REGISTER ((u8)0x10) -#define REQUEST_EEPROM ((u8)0x11) - -static int -nc_vendor_read(struct usbnet *dev, u8 req, u8 regnum, u16 *retval_ptr) -{ - int status = usb_control_msg(dev->udev, - usb_rcvctrlpipe(dev->udev, 0), - req, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, regnum, - retval_ptr, sizeof *retval_ptr, - USB_CTRL_GET_TIMEOUT); - if (status > 0) - status = 0; - if (!status) - le16_to_cpus(retval_ptr); - return status; -} - -static inline int -nc_register_read(struct usbnet *dev, u8 regnum, u16 *retval_ptr) -{ - return nc_vendor_read(dev, REQUEST_REGISTER, regnum, retval_ptr); -} - -// no retval ... can become async, usable in_interrupt() -static void -nc_vendor_write(struct usbnet *dev, u8 req, u8 regnum, u16 value) -{ - usb_control_msg(dev->udev, - usb_sndctrlpipe(dev->udev, 0), - req, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, regnum, - NULL, 0, // data is in setup packet - USB_CTRL_SET_TIMEOUT); -} - -static inline void -nc_register_write(struct usbnet *dev, u8 regnum, u16 value) -{ - nc_vendor_write(dev, REQUEST_REGISTER, regnum, value); -} - - -#if 0 -static void nc_dump_registers(struct usbnet *dev) -{ - u8 reg; - u16 *vp = kmalloc(sizeof (u16)); - - if (!vp) { - dbg("no memory?"); - return; - } - - dbg("%s registers:", dev->net->name); - for (reg = 0; reg < 0x20; reg++) { - int retval; - - // reading some registers is trouble - if (reg >= 0x08 && reg <= 0xf) - continue; - if (reg >= 0x12 && reg <= 0x1e) - continue; - - retval = nc_register_read(dev, reg, vp); - if (retval < 0) - dbg("%s reg [0x%x] ==> error %d", - dev->net->name, reg, retval); - else - dbg("%s reg [0x%x] = 0x%x", - dev->net->name, reg, *vp); - } - kfree(vp); -} -#endif - - -/*-------------------------------------------------------------------------*/ - -/* - * Control register - */ - -#define USBCTL_WRITABLE_MASK 0x1f0f -// bits 15-13 reserved, r/o -#define USBCTL_ENABLE_LANG (1 << 12) -#define USBCTL_ENABLE_MFGR (1 << 11) -#define USBCTL_ENABLE_PROD (1 << 10) -#define USBCTL_ENABLE_SERIAL (1 << 9) -#define USBCTL_ENABLE_DEFAULTS (1 << 8) -// bits 7-4 reserved, r/o -#define USBCTL_FLUSH_OTHER (1 << 3) -#define USBCTL_FLUSH_THIS (1 << 2) -#define USBCTL_DISCONN_OTHER (1 << 1) -#define USBCTL_DISCONN_THIS (1 << 0) - -static inline void nc_dump_usbctl(struct usbnet *dev, u16 usbctl) -{ - if (!netif_msg_link(dev)) - return; - devdbg(dev, "net1080 %s-%s usbctl 0x%x:%s%s%s%s%s;" - " this%s%s;" - " other%s%s; r/o 0x%x", - dev->udev->bus->bus_name, dev->udev->devpath, - usbctl, - (usbctl & USBCTL_ENABLE_LANG) ? " lang" : "", - (usbctl & USBCTL_ENABLE_MFGR) ? " mfgr" : "", - (usbctl & USBCTL_ENABLE_PROD) ? " prod" : "", - (usbctl & USBCTL_ENABLE_SERIAL) ? " serial" : "", - (usbctl & USBCTL_ENABLE_DEFAULTS) ? " defaults" : "", - - (usbctl & USBCTL_FLUSH_OTHER) ? " FLUSH" : "", - (usbctl & USBCTL_DISCONN_OTHER) ? " DIS" : "", - (usbctl & USBCTL_FLUSH_THIS) ? " FLUSH" : "", - (usbctl & USBCTL_DISCONN_THIS) ? " DIS" : "", - usbctl & ~USBCTL_WRITABLE_MASK - ); -} - -/*-------------------------------------------------------------------------*/ - -/* - * Status register - */ - -#define STATUS_PORT_A (1 << 15) - -#define STATUS_CONN_OTHER (1 << 14) -#define STATUS_SUSPEND_OTHER (1 << 13) -#define STATUS_MAILBOX_OTHER (1 << 12) -#define STATUS_PACKETS_OTHER(n) (((n) >> 8) & 0x03) - -#define STATUS_CONN_THIS (1 << 6) -#define STATUS_SUSPEND_THIS (1 << 5) -#define STATUS_MAILBOX_THIS (1 << 4) -#define STATUS_PACKETS_THIS(n) (((n) >> 0) & 0x03) - -#define STATUS_UNSPEC_MASK 0x0c8c -#define STATUS_NOISE_MASK ((u16)~(0x0303|STATUS_UNSPEC_MASK)) - - -static inline void nc_dump_status(struct usbnet *dev, u16 status) -{ - if (!netif_msg_link(dev)) - return; - devdbg(dev, "net1080 %s-%s status 0x%x:" - " this (%c) PKT=%d%s%s%s;" - " other PKT=%d%s%s%s; unspec 0x%x", - dev->udev->bus->bus_name, dev->udev->devpath, - status, - - // XXX the packet counts don't seem right - // (1 at reset, not 0); maybe UNSPEC too - - (status & STATUS_PORT_A) ? 'A' : 'B', - STATUS_PACKETS_THIS(status), - (status & STATUS_CONN_THIS) ? " CON" : "", - (status & STATUS_SUSPEND_THIS) ? " SUS" : "", - (status & STATUS_MAILBOX_THIS) ? " MBOX" : "", - - STATUS_PACKETS_OTHER(status), - (status & STATUS_CONN_OTHER) ? " CON" : "", - (status & STATUS_SUSPEND_OTHER) ? " SUS" : "", - (status & STATUS_MAILBOX_OTHER) ? " MBOX" : "", - - status & STATUS_UNSPEC_MASK - ); -} - -/*-------------------------------------------------------------------------*/ - -/* - * TTL register - */ - -#define TTL_THIS(ttl) (0x00ff & ttl) -#define TTL_OTHER(ttl) (0x00ff & (ttl >> 8)) -#define MK_TTL(this,other) ((u16)(((other)<<8)|(0x00ff&(this)))) - -static inline void nc_dump_ttl(struct usbnet *dev, u16 ttl) -{ - if (netif_msg_link(dev)) - devdbg(dev, "net1080 %s-%s ttl 0x%x this = %d, other = %d", - dev->udev->bus->bus_name, dev->udev->devpath, - ttl, TTL_THIS(ttl), TTL_OTHER(ttl)); -} - -/*-------------------------------------------------------------------------*/ - -static int net1080_reset(struct usbnet *dev) -{ - u16 usbctl, status, ttl; - u16 *vp = kmalloc(sizeof (u16), GFP_KERNEL); - int retval; - - if (!vp) - return -ENOMEM; - - // nc_dump_registers(dev); - - if ((retval = nc_register_read(dev, REG_STATUS, vp)) < 0) { - dbg("can't read %s-%s status: %d", - dev->udev->bus->bus_name, dev->udev->devpath, retval); - goto done; - } - status = *vp; - nc_dump_status(dev, status); - - if ((retval = nc_register_read(dev, REG_USBCTL, vp)) < 0) { - dbg("can't read USBCTL, %d", retval); - goto done; - } - usbctl = *vp; - nc_dump_usbctl(dev, usbctl); - - nc_register_write(dev, REG_USBCTL, - USBCTL_FLUSH_THIS | USBCTL_FLUSH_OTHER); - - if ((retval = nc_register_read(dev, REG_TTL, vp)) < 0) { - dbg("can't read TTL, %d", retval); - goto done; - } - ttl = *vp; - // nc_dump_ttl(dev, ttl); - - nc_register_write(dev, REG_TTL, - MK_TTL(NC_READ_TTL_MS, TTL_OTHER(ttl)) ); - dbg("%s: assigned TTL, %d ms", dev->net->name, NC_READ_TTL_MS); - - if (netif_msg_link(dev)) - devinfo(dev, "port %c, peer %sconnected", - (status & STATUS_PORT_A) ? 'A' : 'B', - (status & STATUS_CONN_OTHER) ? "" : "dis" - ); - retval = 0; - -done: - kfree(vp); - return retval; -} - -static int net1080_check_connect(struct usbnet *dev) -{ - int retval; - u16 status; - u16 *vp = kmalloc(sizeof (u16), GFP_KERNEL); - - if (!vp) - return -ENOMEM; - retval = nc_register_read(dev, REG_STATUS, vp); - status = *vp; - kfree(vp); - if (retval != 0) { - dbg("%s net1080_check_conn read - %d", dev->net->name, retval); - return retval; - } - if ((status & STATUS_CONN_OTHER) != STATUS_CONN_OTHER) - return -ENOLINK; - return 0; -} - -static void nc_flush_complete(struct urb *urb) -{ - kfree(urb->context); - usb_free_urb(urb); -} - -static void nc_ensure_sync(struct usbnet *dev) -{ - dev->frame_errors++; - if (dev->frame_errors > 5) { - struct urb *urb; - struct usb_ctrlrequest *req; - int status; - - /* Send a flush */ - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) - return; - - req = kmalloc(sizeof *req, GFP_ATOMIC); - if (!req) { - usb_free_urb(urb); - return; - } - - req->bRequestType = USB_DIR_OUT - | USB_TYPE_VENDOR - | USB_RECIP_DEVICE; - req->bRequest = REQUEST_REGISTER; - req->wValue = cpu_to_le16(USBCTL_FLUSH_THIS - | USBCTL_FLUSH_OTHER); - req->wIndex = cpu_to_le16(REG_USBCTL); - req->wLength = cpu_to_le16(0); - - /* queue an async control request, we don't need - * to do anything when it finishes except clean up. - */ - usb_fill_control_urb(urb, dev->udev, - usb_sndctrlpipe(dev->udev, 0), - (unsigned char *) req, - NULL, 0, - nc_flush_complete, req); - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status) { - kfree(req); - usb_free_urb(urb); - return; - } - - if (netif_msg_rx_err(dev)) - devdbg(dev, "flush net1080; too many framing errors"); - dev->frame_errors = 0; - } -} - -static int net1080_rx_fixup(struct usbnet *dev, struct sk_buff *skb) -{ - struct nc_header *header; - struct nc_trailer *trailer; - u16 hdr_len, packet_len; - - if (!(skb->len & 0x01)) { -#ifdef DEBUG - struct net_device *net = dev->net; - dbg("rx framesize %d range %d..%d mtu %d", skb->len, - net->hard_header_len, dev->hard_mtu, net->mtu); -#endif - dev->stats.rx_frame_errors++; - nc_ensure_sync(dev); - return 0; - } - - header = (struct nc_header *) skb->data; - hdr_len = le16_to_cpup(&header->hdr_len); - packet_len = le16_to_cpup(&header->packet_len); - if (FRAMED_SIZE(packet_len) > NC_MAX_PACKET) { - dev->stats.rx_frame_errors++; - dbg("packet too big, %d", packet_len); - nc_ensure_sync(dev); - return 0; - } else if (hdr_len < MIN_HEADER) { - dev->stats.rx_frame_errors++; - dbg("header too short, %d", hdr_len); - nc_ensure_sync(dev); - return 0; - } else if (hdr_len > MIN_HEADER) { - // out of band data for us? - dbg("header OOB, %d bytes", hdr_len - MIN_HEADER); - nc_ensure_sync(dev); - // switch (vendor/product ids) { ... } - } - skb_pull(skb, hdr_len); - - trailer = (struct nc_trailer *) - (skb->data + skb->len - sizeof *trailer); - skb_trim(skb, skb->len - sizeof *trailer); - - if ((packet_len & 0x01) == 0) { - if (skb->data [packet_len] != PAD_BYTE) { - dev->stats.rx_frame_errors++; - dbg("bad pad"); - return 0; - } - skb_trim(skb, skb->len - 1); - } - if (skb->len != packet_len) { - dev->stats.rx_frame_errors++; - dbg("bad packet len %d (expected %d)", - skb->len, packet_len); - nc_ensure_sync(dev); - return 0; - } - if (header->packet_id != get_unaligned(&trailer->packet_id)) { - dev->stats.rx_fifo_errors++; - dbg("(2+ dropped) rx packet_id mismatch 0x%x 0x%x", - le16_to_cpu(header->packet_id), - le16_to_cpu(trailer->packet_id)); - return 0; - } -#if 0 - devdbg(dev, "frame <rx h %d p %d id %d", header->hdr_len, - header->packet_len, header->packet_id); -#endif - dev->frame_errors = 0; - return 1; -} - -static struct sk_buff * -net1080_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) -{ - struct sk_buff *skb2; - struct nc_header *header = NULL; - struct nc_trailer *trailer = NULL; - int padlen = sizeof (struct nc_trailer); - int len = skb->len; - - if (!((len + padlen + sizeof (struct nc_header)) & 0x01)) - padlen++; - if (!skb_cloned(skb)) { - int headroom = skb_headroom(skb); - int tailroom = skb_tailroom(skb); - - if (padlen <= tailroom && - sizeof(struct nc_header) <= headroom) - /* There's enough head and tail room */ - goto encapsulate; - - if ((sizeof (struct nc_header) + padlen) < - (headroom + tailroom)) { - /* There's enough total room, so just readjust */ - skb->data = memmove(skb->head - + sizeof (struct nc_header), - skb->data, skb->len); - skb_set_tail_pointer(skb, len); - goto encapsulate; - } - } - - /* Create a new skb to use with the correct size */ - skb2 = skb_copy_expand(skb, - sizeof (struct nc_header), - padlen, - flags); - dev_kfree_skb_any(skb); - if (!skb2) - return skb2; - skb = skb2; - -encapsulate: - /* header first */ - header = (struct nc_header *) skb_push(skb, sizeof *header); - header->hdr_len = cpu_to_le16(sizeof (*header)); - header->packet_len = cpu_to_le16(len); - header->packet_id = cpu_to_le16((u16)dev->xid++); - - /* maybe pad; then trailer */ - if (!((skb->len + sizeof *trailer) & 0x01)) - *skb_put(skb, 1) = PAD_BYTE; - trailer = (struct nc_trailer *) skb_put(skb, sizeof *trailer); - put_unaligned(header->packet_id, &trailer->packet_id); -#if 0 - devdbg(dev, "frame >tx h %d p %d id %d", - header->hdr_len, header->packet_len, - header->packet_id); -#endif - return skb; -} - -static int net1080_bind(struct usbnet *dev, struct usb_interface *intf) -{ - unsigned extra = sizeof (struct nc_header) - + 1 - + sizeof (struct nc_trailer); - - dev->net->hard_header_len += extra; - dev->rx_urb_size = dev->net->hard_header_len + dev->net->mtu; - dev->hard_mtu = NC_MAX_PACKET; - return usbnet_get_endpoints (dev, intf); -} - -static const struct driver_info net1080_info = { - .description = "NetChip TurboCONNECT", - .flags = FLAG_FRAMING_NC, - .bind = net1080_bind, - .reset = net1080_reset, - .check_connect = net1080_check_connect, - .rx_fixup = net1080_rx_fixup, - .tx_fixup = net1080_tx_fixup, -}; - -static const struct usb_device_id products [] = { -{ - USB_DEVICE(0x0525, 0x1080), // NetChip ref design - .driver_info = (unsigned long) &net1080_info, -}, { - USB_DEVICE(0x06D0, 0x0622), // Laplink Gold - .driver_info = (unsigned long) &net1080_info, -}, - { }, // END -}; -MODULE_DEVICE_TABLE(usb, products); - -static struct usb_driver net1080_driver = { - .name = "net1080", - .id_table = products, - .probe = usbnet_probe, - .disconnect = usbnet_disconnect, - .suspend = usbnet_suspend, - .resume = usbnet_resume, -}; - -static int __init net1080_init(void) -{ - return usb_register(&net1080_driver); -} -module_init(net1080_init); - -static void __exit net1080_exit(void) -{ - usb_deregister(&net1080_driver); -} -module_exit(net1080_exit); - -MODULE_AUTHOR("David Brownell"); -MODULE_DESCRIPTION("NetChip 1080 based USB Host-to-Host Links"); -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c deleted file mode 100644 index a05fd97e5bc2..000000000000 --- a/drivers/usb/net/pegasus.c +++ /dev/null @@ -1,1504 +0,0 @@ -/* - * Copyright (c) 1999-2005 Petko Manolov (petkan@users.sourceforge.net) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * ChangeLog: - * .... Most of the time spent on reading sources & docs. - * v0.2.x First official release for the Linux kernel. - * v0.3.0 Beutified and structured, some bugs fixed. - * v0.3.x URBifying bulk requests and bugfixing. First relatively - * stable release. Still can touch device's registers only - * from top-halves. - * v0.4.0 Control messages remained unurbified are now URBs. - * Now we can touch the HW at any time. - * v0.4.9 Control urbs again use process context to wait. Argh... - * Some long standing bugs (enable_net_traffic) fixed. - * Also nasty trick about resubmiting control urb from - * interrupt context used. Please let me know how it - * behaves. Pegasus II support added since this version. - * TODO: suppressing HCD warnings spewage on disconnect. - * v0.4.13 Ethernet address is now set at probe(), not at open() - * time as this seems to break dhcpd. - * v0.5.0 branch to 2.5.x kernels - * v0.5.1 ethtool support added - * v0.5.5 rx socket buffers are in a pool and the their allocation - * is out of the interrupt routine. - */ - -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/ethtool.h> -#include <linux/mii.h> -#include <linux/usb.h> -#include <linux/module.h> -#include <asm/byteorder.h> -#include <asm/uaccess.h> -#include "pegasus.h" - -/* - * Version Information - */ -#define DRIVER_VERSION "v0.6.14 (2006/09/27)" -#define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>" -#define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver" - -static const char driver_name[] = "pegasus"; - -#undef PEGASUS_WRITE_EEPROM -#define BMSR_MEDIA (BMSR_10HALF | BMSR_10FULL | BMSR_100HALF | \ - BMSR_100FULL | BMSR_ANEGCAPABLE) - -static int loopback = 0; -static int mii_mode = 0; -static char *devid=NULL; - -static struct usb_eth_dev usb_dev_id[] = { -#define PEGASUS_DEV(pn, vid, pid, flags) \ - {.name = pn, .vendor = vid, .device = pid, .private = flags}, -#include "pegasus.h" -#undef PEGASUS_DEV - {NULL, 0, 0, 0}, - {NULL, 0, 0, 0} -}; - -static struct usb_device_id pegasus_ids[] = { -#define PEGASUS_DEV(pn, vid, pid, flags) \ - {.match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = vid, .idProduct = pid}, -#include "pegasus.h" -#undef PEGASUS_DEV - {}, - {} -}; - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -module_param(loopback, bool, 0); -module_param(mii_mode, bool, 0); -module_param(devid, charp, 0); -MODULE_PARM_DESC(loopback, "Enable MAC loopback mode (bit 0)"); -MODULE_PARM_DESC(mii_mode, "Enable HomePNA mode (bit 0),default=MII mode = 0"); -MODULE_PARM_DESC(devid, "The format is: 'DEV_name:VendorID:DeviceID:Flags'"); - -/* 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"); - -MODULE_DEVICE_TABLE(usb, pegasus_ids); - -static int update_eth_regs_async(pegasus_t *); -/* Aargh!!! I _really_ hate such tweaks */ -static void ctrl_callback(struct urb *urb) -{ - pegasus_t *pegasus = urb->context; - - if (!pegasus) - return; - - switch (urb->status) { - case 0: - if (pegasus->flags & ETH_REGS_CHANGE) { - pegasus->flags &= ~ETH_REGS_CHANGE; - pegasus->flags |= ETH_REGS_CHANGED; - update_eth_regs_async(pegasus); - return; - } - break; - case -EINPROGRESS: - return; - case -ENOENT: - break; - default: - if (netif_msg_drv(pegasus)) - dev_dbg(&pegasus->intf->dev, "%s, status %d\n", - __FUNCTION__, urb->status); - } - pegasus->flags &= ~ETH_REGS_CHANGED; - wake_up(&pegasus->ctrl_wait); -} - -static int get_registers(pegasus_t * pegasus, __u16 indx, __u16 size, - void *data) -{ - int ret; - char *buffer; - DECLARE_WAITQUEUE(wait, current); - - buffer = kmalloc(size, GFP_KERNEL); - if (!buffer) { - if (netif_msg_drv(pegasus)) - dev_warn(&pegasus->intf->dev, "out of memory in %s\n", - __FUNCTION__); - return -ENOMEM; - } - add_wait_queue(&pegasus->ctrl_wait, &wait); - set_current_state(TASK_UNINTERRUPTIBLE); - while (pegasus->flags & ETH_REGS_CHANGED) - schedule(); - remove_wait_queue(&pegasus->ctrl_wait, &wait); - set_current_state(TASK_RUNNING); - - pegasus->dr.bRequestType = PEGASUS_REQT_READ; - pegasus->dr.bRequest = PEGASUS_REQ_GET_REGS; - pegasus->dr.wValue = cpu_to_le16(0); - pegasus->dr.wIndex = cpu_to_le16p(&indx); - pegasus->dr.wLength = cpu_to_le16p(&size); - pegasus->ctrl_urb->transfer_buffer_length = size; - - usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb, - usb_rcvctrlpipe(pegasus->usb, 0), - (char *) &pegasus->dr, - buffer, size, ctrl_callback, pegasus); - - add_wait_queue(&pegasus->ctrl_wait, &wait); - set_current_state(TASK_UNINTERRUPTIBLE); - - /* using ATOMIC, we'd never wake up if we slept */ - if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { - set_current_state(TASK_RUNNING); - if (ret == -ENODEV) - netif_device_detach(pegasus->net); - if (netif_msg_drv(pegasus)) - dev_err(&pegasus->intf->dev, "%s, status %d\n", - __FUNCTION__, ret); - goto out; - } - - schedule(); -out: - remove_wait_queue(&pegasus->ctrl_wait, &wait); - memcpy(data, buffer, size); - kfree(buffer); - - return ret; -} - -static int set_registers(pegasus_t * pegasus, __u16 indx, __u16 size, - void *data) -{ - int ret; - char *buffer; - DECLARE_WAITQUEUE(wait, current); - - buffer = kmalloc(size, GFP_KERNEL); - if (!buffer) { - if (netif_msg_drv(pegasus)) - dev_warn(&pegasus->intf->dev, "out of memory in %s\n", - __FUNCTION__); - return -ENOMEM; - } - memcpy(buffer, data, size); - - add_wait_queue(&pegasus->ctrl_wait, &wait); - set_current_state(TASK_UNINTERRUPTIBLE); - while (pegasus->flags & ETH_REGS_CHANGED) - schedule(); - remove_wait_queue(&pegasus->ctrl_wait, &wait); - set_current_state(TASK_RUNNING); - - pegasus->dr.bRequestType = PEGASUS_REQT_WRITE; - pegasus->dr.bRequest = PEGASUS_REQ_SET_REGS; - pegasus->dr.wValue = cpu_to_le16(0); - pegasus->dr.wIndex = cpu_to_le16p(&indx); - pegasus->dr.wLength = cpu_to_le16p(&size); - pegasus->ctrl_urb->transfer_buffer_length = size; - - usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb, - usb_sndctrlpipe(pegasus->usb, 0), - (char *) &pegasus->dr, - buffer, size, ctrl_callback, pegasus); - - add_wait_queue(&pegasus->ctrl_wait, &wait); - set_current_state(TASK_UNINTERRUPTIBLE); - - if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { - if (ret == -ENODEV) - netif_device_detach(pegasus->net); - if (netif_msg_drv(pegasus)) - dev_err(&pegasus->intf->dev, "%s, status %d\n", - __FUNCTION__, ret); - goto out; - } - - schedule(); -out: - remove_wait_queue(&pegasus->ctrl_wait, &wait); - kfree(buffer); - - return ret; -} - -static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data) -{ - int ret; - char *tmp; - DECLARE_WAITQUEUE(wait, current); - - tmp = kmalloc(1, GFP_KERNEL); - if (!tmp) { - if (netif_msg_drv(pegasus)) - dev_warn(&pegasus->intf->dev, "out of memory in %s\n", - __FUNCTION__); - return -ENOMEM; - } - memcpy(tmp, &data, 1); - add_wait_queue(&pegasus->ctrl_wait, &wait); - set_current_state(TASK_UNINTERRUPTIBLE); - while (pegasus->flags & ETH_REGS_CHANGED) - schedule(); - remove_wait_queue(&pegasus->ctrl_wait, &wait); - set_current_state(TASK_RUNNING); - - pegasus->dr.bRequestType = PEGASUS_REQT_WRITE; - pegasus->dr.bRequest = PEGASUS_REQ_SET_REG; - pegasus->dr.wValue = cpu_to_le16(data); - pegasus->dr.wIndex = cpu_to_le16p(&indx); - pegasus->dr.wLength = cpu_to_le16(1); - pegasus->ctrl_urb->transfer_buffer_length = 1; - - usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb, - usb_sndctrlpipe(pegasus->usb, 0), - (char *) &pegasus->dr, - tmp, 1, ctrl_callback, pegasus); - - add_wait_queue(&pegasus->ctrl_wait, &wait); - set_current_state(TASK_UNINTERRUPTIBLE); - - if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { - if (ret == -ENODEV) - netif_device_detach(pegasus->net); - if (netif_msg_drv(pegasus)) - dev_err(&pegasus->intf->dev, "%s, status %d\n", - __FUNCTION__, ret); - goto out; - } - - schedule(); -out: - remove_wait_queue(&pegasus->ctrl_wait, &wait); - kfree(tmp); - - return ret; -} - -static int update_eth_regs_async(pegasus_t * pegasus) -{ - int ret; - - pegasus->dr.bRequestType = PEGASUS_REQT_WRITE; - pegasus->dr.bRequest = PEGASUS_REQ_SET_REGS; - pegasus->dr.wValue = 0; - pegasus->dr.wIndex = cpu_to_le16(EthCtrl0); - pegasus->dr.wLength = cpu_to_le16(3); - pegasus->ctrl_urb->transfer_buffer_length = 3; - - usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb, - usb_sndctrlpipe(pegasus->usb, 0), - (char *) &pegasus->dr, - pegasus->eth_regs, 3, ctrl_callback, pegasus); - - if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { - if (ret == -ENODEV) - netif_device_detach(pegasus->net); - if (netif_msg_drv(pegasus)) - dev_err(&pegasus->intf->dev, "%s, status %d\n", - __FUNCTION__, ret); - } - - return ret; -} - -/* Returns 0 on success, error on failure */ -static int read_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 * regd) -{ - int i; - __u8 data[4] = { phy, 0, 0, indx }; - __le16 regdi; - int ret; - - set_register(pegasus, PhyCtrl, 0); - set_registers(pegasus, PhyAddr, sizeof (data), data); - set_register(pegasus, PhyCtrl, (indx | PHY_READ)); - for (i = 0; i < REG_TIMEOUT; i++) { - ret = get_registers(pegasus, PhyCtrl, 1, data); - if (ret == -ESHUTDOWN) - goto fail; - if (data[0] & PHY_DONE) - break; - } - if (i < REG_TIMEOUT) { - ret = get_registers(pegasus, PhyData, 2, ®di); - *regd = le16_to_cpu(regdi); - return ret; - } -fail: - if (netif_msg_drv(pegasus)) - dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__); - - return ret; -} - -static int mdio_read(struct net_device *dev, int phy_id, int loc) -{ - pegasus_t *pegasus = (pegasus_t *) netdev_priv(dev); - u16 res; - - read_mii_word(pegasus, phy_id, loc, &res); - return (int)res; -} - -static int write_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 regd) -{ - int i; - __u8 data[4] = { phy, 0, 0, indx }; - int ret; - - data[1] = (u8) regd; - data[2] = (u8) (regd >> 8); - set_register(pegasus, PhyCtrl, 0); - set_registers(pegasus, PhyAddr, sizeof(data), data); - set_register(pegasus, PhyCtrl, (indx | PHY_WRITE)); - for (i = 0; i < REG_TIMEOUT; i++) { - ret = get_registers(pegasus, PhyCtrl, 1, data); - if (ret == -ESHUTDOWN) - goto fail; - if (data[0] & PHY_DONE) - break; - } - if (i < REG_TIMEOUT) - return ret; - -fail: - if (netif_msg_drv(pegasus)) - dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__); - return -ETIMEDOUT; -} - -static void mdio_write(struct net_device *dev, int phy_id, int loc, int val) -{ - pegasus_t *pegasus = (pegasus_t *) netdev_priv(dev); - - write_mii_word(pegasus, phy_id, loc, val); -} - -static int read_eprom_word(pegasus_t * pegasus, __u8 index, __u16 * retdata) -{ - int i; - __u8 tmp; - __le16 retdatai; - int ret; - - set_register(pegasus, EpromCtrl, 0); - set_register(pegasus, EpromOffset, index); - set_register(pegasus, EpromCtrl, EPROM_READ); - - for (i = 0; i < REG_TIMEOUT; i++) { - ret = get_registers(pegasus, EpromCtrl, 1, &tmp); - if (tmp & EPROM_DONE) - break; - if (ret == -ESHUTDOWN) - goto fail; - } - if (i < REG_TIMEOUT) { - ret = get_registers(pegasus, EpromData, 2, &retdatai); - *retdata = le16_to_cpu(retdatai); - return ret; - } - -fail: - if (netif_msg_drv(pegasus)) - dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__); - return -ETIMEDOUT; -} - -#ifdef PEGASUS_WRITE_EEPROM -static inline void enable_eprom_write(pegasus_t * pegasus) -{ - __u8 tmp; - int ret; - - get_registers(pegasus, EthCtrl2, 1, &tmp); - set_register(pegasus, EthCtrl2, tmp | EPROM_WR_ENABLE); -} - -static inline void disable_eprom_write(pegasus_t * pegasus) -{ - __u8 tmp; - int ret; - - get_registers(pegasus, EthCtrl2, 1, &tmp); - set_register(pegasus, EpromCtrl, 0); - set_register(pegasus, EthCtrl2, tmp & ~EPROM_WR_ENABLE); -} - -static int write_eprom_word(pegasus_t * pegasus, __u8 index, __u16 data) -{ - int i; - __u8 tmp, d[4] = { 0x3f, 0, 0, EPROM_WRITE }; - int ret; - - set_registers(pegasus, EpromOffset, 4, d); - enable_eprom_write(pegasus); - set_register(pegasus, EpromOffset, index); - set_registers(pegasus, EpromData, 2, &data); - set_register(pegasus, EpromCtrl, EPROM_WRITE); - - for (i = 0; i < REG_TIMEOUT; i++) { - ret = get_registers(pegasus, EpromCtrl, 1, &tmp); - if (ret == -ESHUTDOWN) - goto fail; - if (tmp & EPROM_DONE) - break; - } - disable_eprom_write(pegasus); - if (i < REG_TIMEOUT) - return ret; -fail: - if (netif_msg_drv(pegasus)) - dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__); - return -ETIMEDOUT; -} -#endif /* PEGASUS_WRITE_EEPROM */ - -static inline void get_node_id(pegasus_t * pegasus, __u8 * id) -{ - int i; - __u16 w16; - - for (i = 0; i < 3; i++) { - read_eprom_word(pegasus, i, &w16); - ((__le16 *) id)[i] = cpu_to_le16p(&w16); - } -} - -static void set_ethernet_addr(pegasus_t * pegasus) -{ - __u8 node_id[6]; - - if (pegasus->features & PEGASUS_II) { - get_registers(pegasus, 0x10, sizeof(node_id), node_id); - } else { - get_node_id(pegasus, node_id); - set_registers(pegasus, EthID, sizeof (node_id), node_id); - } - memcpy(pegasus->net->dev_addr, node_id, sizeof (node_id)); -} - -static inline int reset_mac(pegasus_t * pegasus) -{ - __u8 data = 0x8; - int i; - - set_register(pegasus, EthCtrl1, data); - for (i = 0; i < REG_TIMEOUT; i++) { - get_registers(pegasus, EthCtrl1, 1, &data); - if (~data & 0x08) { - if (loopback & 1) - break; - if (mii_mode && (pegasus->features & HAS_HOME_PNA)) - set_register(pegasus, Gpio1, 0x34); - else - set_register(pegasus, Gpio1, 0x26); - set_register(pegasus, Gpio0, pegasus->features); - set_register(pegasus, Gpio0, DEFAULT_GPIO_SET); - break; - } - } - if (i == REG_TIMEOUT) - return -ETIMEDOUT; - - if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS || - usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) { - set_register(pegasus, Gpio0, 0x24); - set_register(pegasus, Gpio0, 0x26); - } - if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_ELCON) { - __u16 auxmode; - read_mii_word(pegasus, 3, 0x1b, &auxmode); - write_mii_word(pegasus, 3, 0x1b, auxmode | 4); - } - - return 0; -} - -static int enable_net_traffic(struct net_device *dev, struct usb_device *usb) -{ - __u16 linkpart; - __u8 data[4]; - pegasus_t *pegasus = netdev_priv(dev); - int ret; - - read_mii_word(pegasus, pegasus->phy, MII_LPA, &linkpart); - data[0] = 0xc9; - data[1] = 0; - if (linkpart & (ADVERTISE_100FULL | ADVERTISE_10FULL)) - data[1] |= 0x20; /* set full duplex */ - if (linkpart & (ADVERTISE_100FULL | ADVERTISE_100HALF)) - data[1] |= 0x10; /* set 100 Mbps */ - if (mii_mode) - data[1] = 0; - data[2] = (loopback & 1) ? 0x09 : 0x01; - - memcpy(pegasus->eth_regs, data, sizeof (data)); - ret = set_registers(pegasus, EthCtrl0, 3, data); - - if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS || - usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS2 || - usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) { - u16 auxmode; - read_mii_word(pegasus, 0, 0x1b, &auxmode); - write_mii_word(pegasus, 0, 0x1b, auxmode | 4); - } - - return ret; -} - -static void fill_skb_pool(pegasus_t * pegasus) -{ - int i; - - for (i = 0; i < RX_SKBS; i++) { - if (pegasus->rx_pool[i]) - continue; - pegasus->rx_pool[i] = dev_alloc_skb(PEGASUS_MTU + 2); - /* - ** we give up if the allocation fail. the tasklet will be - ** rescheduled again anyway... - */ - if (pegasus->rx_pool[i] == NULL) - return; - skb_reserve(pegasus->rx_pool[i], 2); - } -} - -static void free_skb_pool(pegasus_t * pegasus) -{ - int i; - - for (i = 0; i < RX_SKBS; i++) { - if (pegasus->rx_pool[i]) { - dev_kfree_skb(pegasus->rx_pool[i]); - pegasus->rx_pool[i] = NULL; - } - } -} - -static inline struct sk_buff *pull_skb(pegasus_t * pegasus) -{ - int i; - struct sk_buff *skb; - - for (i = 0; i < RX_SKBS; i++) { - if (likely(pegasus->rx_pool[i] != NULL)) { - skb = pegasus->rx_pool[i]; - pegasus->rx_pool[i] = NULL; - return skb; - } - } - return NULL; -} - -static void read_bulk_callback(struct urb *urb) -{ - pegasus_t *pegasus = urb->context; - struct net_device *net; - int rx_status, count = urb->actual_length; - u8 *buf = urb->transfer_buffer; - __u16 pkt_len; - - if (!pegasus) - return; - - net = pegasus->net; - if (!netif_device_present(net) || !netif_running(net)) - return; - - switch (urb->status) { - case 0: - break; - case -ETIME: - if (netif_msg_rx_err(pegasus)) - pr_debug("%s: reset MAC\n", net->name); - pegasus->flags &= ~PEGASUS_RX_BUSY; - break; - case -EPIPE: /* stall, or disconnect from TT */ - /* FIXME schedule work to clear the halt */ - if (netif_msg_rx_err(pegasus)) - printk(KERN_WARNING "%s: no rx stall recovery\n", - net->name); - return; - case -ENOENT: - case -ECONNRESET: - case -ESHUTDOWN: - if (netif_msg_ifdown(pegasus)) - pr_debug("%s: rx unlink, %d\n", net->name, urb->status); - return; - default: - if (netif_msg_rx_err(pegasus)) - pr_debug("%s: RX status %d\n", net->name, urb->status); - goto goon; - } - - if (!count || count < 4) - goto goon; - - rx_status = buf[count - 2]; - if (rx_status & 0x1e) { - if (netif_msg_rx_err(pegasus)) - pr_debug("%s: RX packet error %x\n", - net->name, rx_status); - pegasus->stats.rx_errors++; - if (rx_status & 0x06) // long or runt - pegasus->stats.rx_length_errors++; - if (rx_status & 0x08) - pegasus->stats.rx_crc_errors++; - if (rx_status & 0x10) // extra bits - pegasus->stats.rx_frame_errors++; - goto goon; - } - if (pegasus->chip == 0x8513) { - pkt_len = le32_to_cpu(*(__le32 *)urb->transfer_buffer); - pkt_len &= 0x0fff; - pegasus->rx_skb->data += 2; - } else { - pkt_len = buf[count - 3] << 8; - pkt_len += buf[count - 4]; - pkt_len &= 0xfff; - pkt_len -= 8; - } - - /* - * If the packet is unreasonably long, quietly drop it rather than - * kernel panicing by calling skb_put. - */ - if (pkt_len > PEGASUS_MTU) - goto goon; - - /* - * at this point we are sure pegasus->rx_skb != NULL - * so we go ahead and pass up the packet. - */ - skb_put(pegasus->rx_skb, pkt_len); - pegasus->rx_skb->protocol = eth_type_trans(pegasus->rx_skb, net); - netif_rx(pegasus->rx_skb); - pegasus->stats.rx_packets++; - pegasus->stats.rx_bytes += pkt_len; - - if (pegasus->flags & PEGASUS_UNPLUG) - return; - - spin_lock(&pegasus->rx_pool_lock); - pegasus->rx_skb = pull_skb(pegasus); - spin_unlock(&pegasus->rx_pool_lock); - - if (pegasus->rx_skb == NULL) - goto tl_sched; -goon: - usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb, - usb_rcvbulkpipe(pegasus->usb, 1), - pegasus->rx_skb->data, PEGASUS_MTU + 8, - read_bulk_callback, pegasus); - rx_status = usb_submit_urb(pegasus->rx_urb, GFP_ATOMIC); - if (rx_status == -ENODEV) - netif_device_detach(pegasus->net); - else if (rx_status) { - pegasus->flags |= PEGASUS_RX_URB_FAIL; - goto tl_sched; - } else { - pegasus->flags &= ~PEGASUS_RX_URB_FAIL; - } - - return; - -tl_sched: - tasklet_schedule(&pegasus->rx_tl); -} - -static void rx_fixup(unsigned long data) -{ - pegasus_t *pegasus; - unsigned long flags; - int status; - - pegasus = (pegasus_t *) data; - if (pegasus->flags & PEGASUS_UNPLUG) - return; - - spin_lock_irqsave(&pegasus->rx_pool_lock, flags); - fill_skb_pool(pegasus); - if (pegasus->flags & PEGASUS_RX_URB_FAIL) - if (pegasus->rx_skb) - goto try_again; - if (pegasus->rx_skb == NULL) { - pegasus->rx_skb = pull_skb(pegasus); - } - if (pegasus->rx_skb == NULL) { - if (netif_msg_rx_err(pegasus)) - printk(KERN_WARNING "%s: low on memory\n", - pegasus->net->name); - tasklet_schedule(&pegasus->rx_tl); - goto done; - } - usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb, - usb_rcvbulkpipe(pegasus->usb, 1), - pegasus->rx_skb->data, PEGASUS_MTU + 8, - read_bulk_callback, pegasus); -try_again: - status = usb_submit_urb(pegasus->rx_urb, GFP_ATOMIC); - if (status == -ENODEV) - netif_device_detach(pegasus->net); - else if (status) { - pegasus->flags |= PEGASUS_RX_URB_FAIL; - tasklet_schedule(&pegasus->rx_tl); - } else { - pegasus->flags &= ~PEGASUS_RX_URB_FAIL; - } -done: - spin_unlock_irqrestore(&pegasus->rx_pool_lock, flags); -} - -static void write_bulk_callback(struct urb *urb) -{ - pegasus_t *pegasus = urb->context; - struct net_device *net = pegasus->net; - - if (!pegasus) - return; - - if (!netif_device_present(net) || !netif_running(net)) - return; - - switch (urb->status) { - case -EPIPE: - /* FIXME schedule_work() to clear the tx halt */ - netif_stop_queue(net); - if (netif_msg_tx_err(pegasus)) - printk(KERN_WARNING "%s: no tx stall recovery\n", - net->name); - return; - case -ENOENT: - case -ECONNRESET: - case -ESHUTDOWN: - if (netif_msg_ifdown(pegasus)) - pr_debug("%s: tx unlink, %d\n", net->name, urb->status); - return; - default: - if (netif_msg_tx_err(pegasus)) - pr_info("%s: TX status %d\n", net->name, urb->status); - /* FALL THROUGH */ - case 0: - break; - } - - net->trans_start = jiffies; - netif_wake_queue(net); -} - -static void intr_callback(struct urb *urb) -{ - pegasus_t *pegasus = urb->context; - struct net_device *net; - int status; - - if (!pegasus) - return; - net = pegasus->net; - - switch (urb->status) { - case 0: - break; - case -ECONNRESET: /* unlink */ - case -ENOENT: - case -ESHUTDOWN: - return; - default: - /* some Pegasus-I products report LOTS of data - * toggle errors... avoid log spamming - */ - if (netif_msg_timer(pegasus)) - pr_debug("%s: intr status %d\n", net->name, - urb->status); - } - - if (urb->actual_length >= 6) { - u8 * d = urb->transfer_buffer; - - /* byte 0 == tx_status1, reg 2B */ - if (d[0] & (TX_UNDERRUN|EXCESSIVE_COL - |LATE_COL|JABBER_TIMEOUT)) { - pegasus->stats.tx_errors++; - if (d[0] & TX_UNDERRUN) - pegasus->stats.tx_fifo_errors++; - if (d[0] & (EXCESSIVE_COL | JABBER_TIMEOUT)) - pegasus->stats.tx_aborted_errors++; - if (d[0] & LATE_COL) - pegasus->stats.tx_window_errors++; - } - - /* d[5].LINK_STATUS lies on some adapters. - * d[0].NO_CARRIER kicks in only with failed TX. - * ... so monitoring with MII may be safest. - */ - - /* bytes 3-4 == rx_lostpkt, reg 2E/2F */ - pegasus->stats.rx_missed_errors += ((d[3] & 0x7f) << 8) | d[4]; - } - - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status == -ENODEV) - netif_device_detach(pegasus->net); - if (status && netif_msg_timer(pegasus)) - printk(KERN_ERR "%s: can't resubmit interrupt urb, %d\n", - net->name, status); -} - -static void pegasus_tx_timeout(struct net_device *net) -{ - pegasus_t *pegasus = netdev_priv(net); - if (netif_msg_timer(pegasus)) - printk(KERN_WARNING "%s: tx timeout\n", net->name); - usb_unlink_urb(pegasus->tx_urb); - pegasus->stats.tx_errors++; -} - -static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net) -{ - pegasus_t *pegasus = netdev_priv(net); - int count = ((skb->len + 2) & 0x3f) ? skb->len + 2 : skb->len + 3; - int res; - __u16 l16 = skb->len; - - netif_stop_queue(net); - - ((__le16 *) pegasus->tx_buff)[0] = cpu_to_le16(l16); - skb_copy_from_linear_data(skb, pegasus->tx_buff + 2, skb->len); - usb_fill_bulk_urb(pegasus->tx_urb, pegasus->usb, - usb_sndbulkpipe(pegasus->usb, 2), - pegasus->tx_buff, count, - write_bulk_callback, pegasus); - if ((res = usb_submit_urb(pegasus->tx_urb, GFP_ATOMIC))) { - if (netif_msg_tx_err(pegasus)) - printk(KERN_WARNING "%s: fail tx, %d\n", - net->name, res); - switch (res) { - case -EPIPE: /* stall, or disconnect from TT */ - /* cleanup should already have been scheduled */ - break; - case -ENODEV: /* disconnect() upcoming */ - netif_device_detach(pegasus->net); - break; - default: - pegasus->stats.tx_errors++; - netif_start_queue(net); - } - } else { - pegasus->stats.tx_packets++; - pegasus->stats.tx_bytes += skb->len; - net->trans_start = jiffies; - } - dev_kfree_skb(skb); - - return 0; -} - -static struct net_device_stats *pegasus_netdev_stats(struct net_device *dev) -{ - return &((pegasus_t *) netdev_priv(dev))->stats; -} - -static inline void disable_net_traffic(pegasus_t * pegasus) -{ - int tmp = 0; - - set_registers(pegasus, EthCtrl0, 2, &tmp); -} - -static inline void get_interrupt_interval(pegasus_t * pegasus) -{ - __u8 data[2]; - - read_eprom_word(pegasus, 4, (__u16 *) data); - if (pegasus->usb->speed != USB_SPEED_HIGH) { - if (data[1] < 0x80) { - if (netif_msg_timer(pegasus)) - dev_info(&pegasus->intf->dev, "intr interval " - "changed from %ums to %ums\n", - data[1], 0x80); - data[1] = 0x80; -#ifdef PEGASUS_WRITE_EEPROM - write_eprom_word(pegasus, 4, *(__u16 *) data); -#endif - } - } - pegasus->intr_interval = data[1]; -} - -static void set_carrier(struct net_device *net) -{ - pegasus_t *pegasus = netdev_priv(net); - u16 tmp; - - if (read_mii_word(pegasus, pegasus->phy, MII_BMSR, &tmp)) - return; - - if (tmp & BMSR_LSTATUS) - netif_carrier_on(net); - else - netif_carrier_off(net); -} - -static void free_all_urbs(pegasus_t * pegasus) -{ - usb_free_urb(pegasus->intr_urb); - usb_free_urb(pegasus->tx_urb); - usb_free_urb(pegasus->rx_urb); - usb_free_urb(pegasus->ctrl_urb); -} - -static void unlink_all_urbs(pegasus_t * pegasus) -{ - usb_kill_urb(pegasus->intr_urb); - usb_kill_urb(pegasus->tx_urb); - usb_kill_urb(pegasus->rx_urb); - usb_kill_urb(pegasus->ctrl_urb); -} - -static int alloc_urbs(pegasus_t * pegasus) -{ - pegasus->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!pegasus->ctrl_urb) { - return 0; - } - pegasus->rx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!pegasus->rx_urb) { - usb_free_urb(pegasus->ctrl_urb); - return 0; - } - pegasus->tx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!pegasus->tx_urb) { - usb_free_urb(pegasus->rx_urb); - usb_free_urb(pegasus->ctrl_urb); - return 0; - } - pegasus->intr_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!pegasus->intr_urb) { - usb_free_urb(pegasus->tx_urb); - usb_free_urb(pegasus->rx_urb); - usb_free_urb(pegasus->ctrl_urb); - return 0; - } - - return 1; -} - -static int pegasus_open(struct net_device *net) -{ - pegasus_t *pegasus = netdev_priv(net); - int res; - - if (pegasus->rx_skb == NULL) - pegasus->rx_skb = pull_skb(pegasus); - /* - ** Note: no point to free the pool. it is empty :-) - */ - if (!pegasus->rx_skb) - return -ENOMEM; - - res = set_registers(pegasus, EthID, 6, net->dev_addr); - - usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb, - usb_rcvbulkpipe(pegasus->usb, 1), - pegasus->rx_skb->data, PEGASUS_MTU + 8, - read_bulk_callback, pegasus); - if ((res = usb_submit_urb(pegasus->rx_urb, GFP_KERNEL))) { - if (res == -ENODEV) - netif_device_detach(pegasus->net); - if (netif_msg_ifup(pegasus)) - pr_debug("%s: failed rx_urb, %d", net->name, res); - goto exit; - } - - usb_fill_int_urb(pegasus->intr_urb, pegasus->usb, - usb_rcvintpipe(pegasus->usb, 3), - pegasus->intr_buff, sizeof (pegasus->intr_buff), - intr_callback, pegasus, pegasus->intr_interval); - if ((res = usb_submit_urb(pegasus->intr_urb, GFP_KERNEL))) { - if (res == -ENODEV) - netif_device_detach(pegasus->net); - if (netif_msg_ifup(pegasus)) - pr_debug("%s: failed intr_urb, %d\n", net->name, res); - usb_kill_urb(pegasus->rx_urb); - goto exit; - } - if ((res = enable_net_traffic(net, pegasus->usb))) { - if (netif_msg_ifup(pegasus)) - pr_debug("%s: can't enable_net_traffic() - %d\n", - net->name, res); - res = -EIO; - usb_kill_urb(pegasus->rx_urb); - usb_kill_urb(pegasus->intr_urb); - free_skb_pool(pegasus); - goto exit; - } - set_carrier(net); - netif_start_queue(net); - if (netif_msg_ifup(pegasus)) - pr_debug("%s: open\n", net->name); - res = 0; -exit: - return res; -} - -static int pegasus_close(struct net_device *net) -{ - pegasus_t *pegasus = netdev_priv(net); - - netif_stop_queue(net); - if (!(pegasus->flags & PEGASUS_UNPLUG)) - disable_net_traffic(pegasus); - tasklet_kill(&pegasus->rx_tl); - unlink_all_urbs(pegasus); - - return 0; -} - -static void pegasus_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - pegasus_t *pegasus = netdev_priv(dev); - strncpy(info->driver, driver_name, sizeof (info->driver) - 1); - strncpy(info->version, DRIVER_VERSION, sizeof (info->version) - 1); - usb_make_path(pegasus->usb, info->bus_info, sizeof (info->bus_info)); -} - -/* also handles three patterns of some kind in hardware */ -#define WOL_SUPPORTED (WAKE_MAGIC|WAKE_PHY) - -static void -pegasus_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) -{ - pegasus_t *pegasus = netdev_priv(dev); - - wol->supported = WAKE_MAGIC | WAKE_PHY; - wol->wolopts = pegasus->wolopts; -} - -static int -pegasus_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) -{ - pegasus_t *pegasus = netdev_priv(dev); - u8 reg78 = 0x04; - - if (wol->wolopts & ~WOL_SUPPORTED) - return -EINVAL; - - if (wol->wolopts & WAKE_MAGIC) - reg78 |= 0x80; - if (wol->wolopts & WAKE_PHY) - reg78 |= 0x40; - /* FIXME this 0x10 bit still needs to get set in the chip... */ - if (wol->wolopts) - pegasus->eth_regs[0] |= 0x10; - else - pegasus->eth_regs[0] &= ~0x10; - pegasus->wolopts = wol->wolopts; - return set_register(pegasus, WakeupControl, reg78); -} - -static inline void pegasus_reset_wol(struct net_device *dev) -{ - struct ethtool_wolinfo wol; - - memset(&wol, 0, sizeof wol); - (void) pegasus_set_wol(dev, &wol); -} - -static int -pegasus_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) -{ - pegasus_t *pegasus; - - if (in_atomic()) - return 0; - - pegasus = netdev_priv(dev); - mii_ethtool_gset(&pegasus->mii, ecmd); - - return 0; -} - -static int -pegasus_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) -{ - pegasus_t *pegasus = netdev_priv(dev); - return mii_ethtool_sset(&pegasus->mii, ecmd); -} - -static int pegasus_nway_reset(struct net_device *dev) -{ - pegasus_t *pegasus = netdev_priv(dev); - return mii_nway_restart(&pegasus->mii); -} - -static u32 pegasus_get_link(struct net_device *dev) -{ - pegasus_t *pegasus = netdev_priv(dev); - return mii_link_ok(&pegasus->mii); -} - -static u32 pegasus_get_msglevel(struct net_device *dev) -{ - pegasus_t *pegasus = netdev_priv(dev); - return pegasus->msg_enable; -} - -static void pegasus_set_msglevel(struct net_device *dev, u32 v) -{ - pegasus_t *pegasus = netdev_priv(dev); - pegasus->msg_enable = v; -} - -static struct ethtool_ops ops = { - .get_drvinfo = pegasus_get_drvinfo, - .get_settings = pegasus_get_settings, - .set_settings = pegasus_set_settings, - .nway_reset = pegasus_nway_reset, - .get_link = pegasus_get_link, - .get_msglevel = pegasus_get_msglevel, - .set_msglevel = pegasus_set_msglevel, - .get_wol = pegasus_get_wol, - .set_wol = pegasus_set_wol, -}; - -static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd) -{ - __u16 *data = (__u16 *) & rq->ifr_ifru; - pegasus_t *pegasus = netdev_priv(net); - int res; - - switch (cmd) { - case SIOCDEVPRIVATE: - data[0] = pegasus->phy; - case SIOCDEVPRIVATE + 1: - read_mii_word(pegasus, data[0], data[1] & 0x1f, &data[3]); - res = 0; - break; - case SIOCDEVPRIVATE + 2: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, data[2]); - res = 0; - break; - default: - res = -EOPNOTSUPP; - } - return res; -} - -static void pegasus_set_multicast(struct net_device *net) -{ - pegasus_t *pegasus = netdev_priv(net); - - if (net->flags & IFF_PROMISC) { - pegasus->eth_regs[EthCtrl2] |= RX_PROMISCUOUS; - if (netif_msg_link(pegasus)) - pr_info("%s: Promiscuous mode enabled.\n", net->name); - } else if (net->mc_count || - (net->flags & IFF_ALLMULTI)) { - pegasus->eth_regs[EthCtrl0] |= RX_MULTICAST; - pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS; - if (netif_msg_link(pegasus)) - pr_info("%s: set allmulti\n", net->name); - } else { - pegasus->eth_regs[EthCtrl0] &= ~RX_MULTICAST; - pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS; - } - - pegasus->flags |= ETH_REGS_CHANGE; - ctrl_callback(pegasus->ctrl_urb); -} - -static __u8 mii_phy_probe(pegasus_t * pegasus) -{ - int i; - __u16 tmp; - - for (i = 0; i < 32; i++) { - read_mii_word(pegasus, i, MII_BMSR, &tmp); - if (tmp == 0 || tmp == 0xffff || (tmp & BMSR_MEDIA) == 0) - continue; - else - return i; - } - - return 0xff; -} - -static inline void setup_pegasus_II(pegasus_t * pegasus) -{ - __u8 data = 0xa5; - - set_register(pegasus, Reg1d, 0); - set_register(pegasus, Reg7b, 1); - mdelay(100); - if ((pegasus->features & HAS_HOME_PNA) && mii_mode) - set_register(pegasus, Reg7b, 0); - else - set_register(pegasus, Reg7b, 2); - - set_register(pegasus, 0x83, data); - get_registers(pegasus, 0x83, 1, &data); - - if (data == 0xa5) { - pegasus->chip = 0x8513; - } else { - pegasus->chip = 0; - } - - set_register(pegasus, 0x80, 0xc0); - set_register(pegasus, 0x83, 0xff); - set_register(pegasus, 0x84, 0x01); - - if (pegasus->features & HAS_HOME_PNA && mii_mode) - set_register(pegasus, Reg81, 6); - else - set_register(pegasus, Reg81, 2); -} - - -static struct workqueue_struct *pegasus_workqueue = NULL; -#define CARRIER_CHECK_DELAY (2 * HZ) - -static void check_carrier(struct work_struct *work) -{ - pegasus_t *pegasus = container_of(work, pegasus_t, carrier_check.work); - set_carrier(pegasus->net); - if (!(pegasus->flags & PEGASUS_UNPLUG)) { - queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, - CARRIER_CHECK_DELAY); - } -} - -static int pegasus_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *dev = interface_to_usbdev(intf); - struct net_device *net; - pegasus_t *pegasus; - int dev_index = id - pegasus_ids; - int res = -ENOMEM; - - usb_get_dev(dev); - net = alloc_etherdev(sizeof(struct pegasus)); - if (!net) { - dev_err(&intf->dev, "can't allocate %s\n", "device"); - goto out; - } - - pegasus = netdev_priv(net); - memset(pegasus, 0, sizeof (struct pegasus)); - pegasus->dev_index = dev_index; - init_waitqueue_head(&pegasus->ctrl_wait); - - if (!alloc_urbs(pegasus)) { - dev_err(&intf->dev, "can't allocate %s\n", "urbs"); - goto out1; - } - - tasklet_init(&pegasus->rx_tl, rx_fixup, (unsigned long) pegasus); - - INIT_DELAYED_WORK(&pegasus->carrier_check, check_carrier); - - pegasus->intf = intf; - pegasus->usb = dev; - pegasus->net = net; - SET_MODULE_OWNER(net); - net->open = pegasus_open; - net->stop = pegasus_close; - net->watchdog_timeo = PEGASUS_TX_TIMEOUT; - net->tx_timeout = pegasus_tx_timeout; - net->do_ioctl = pegasus_ioctl; - net->hard_start_xmit = pegasus_start_xmit; - net->set_multicast_list = pegasus_set_multicast; - net->get_stats = pegasus_netdev_stats; - SET_ETHTOOL_OPS(net, &ops); - pegasus->mii.dev = net; - pegasus->mii.mdio_read = mdio_read; - pegasus->mii.mdio_write = mdio_write; - pegasus->mii.phy_id_mask = 0x1f; - pegasus->mii.reg_num_mask = 0x1f; - spin_lock_init(&pegasus->rx_pool_lock); - pegasus->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV - | NETIF_MSG_PROBE | NETIF_MSG_LINK); - - pegasus->features = usb_dev_id[dev_index].private; - get_interrupt_interval(pegasus); - if (reset_mac(pegasus)) { - dev_err(&intf->dev, "can't reset MAC\n"); - res = -EIO; - goto out2; - } - set_ethernet_addr(pegasus); - fill_skb_pool(pegasus); - if (pegasus->features & PEGASUS_II) { - dev_info(&intf->dev, "setup Pegasus II specific registers\n"); - setup_pegasus_II(pegasus); - } - pegasus->phy = mii_phy_probe(pegasus); - if (pegasus->phy == 0xff) { - dev_warn(&intf->dev, "can't locate MII phy, using default\n"); - pegasus->phy = 1; - } - pegasus->mii.phy_id = pegasus->phy; - usb_set_intfdata(intf, pegasus); - SET_NETDEV_DEV(net, &intf->dev); - pegasus_reset_wol(net); - res = register_netdev(net); - if (res) - goto out3; - queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, - CARRIER_CHECK_DELAY); - - dev_info(&intf->dev, "%s, %s, %02x:%02x:%02x:%02x:%02x:%02x\n", - net->name, - usb_dev_id[dev_index].name, - net->dev_addr [0], net->dev_addr [1], - net->dev_addr [2], net->dev_addr [3], - net->dev_addr [4], net->dev_addr [5]); - return 0; - -out3: - usb_set_intfdata(intf, NULL); - free_skb_pool(pegasus); -out2: - free_all_urbs(pegasus); -out1: - free_netdev(net); -out: - usb_put_dev(dev); - return res; -} - -static void pegasus_disconnect(struct usb_interface *intf) -{ - struct pegasus *pegasus = usb_get_intfdata(intf); - - usb_set_intfdata(intf, NULL); - if (!pegasus) { - dev_dbg(&intf->dev, "unregistering non-bound device?\n"); - return; - } - - pegasus->flags |= PEGASUS_UNPLUG; - cancel_delayed_work(&pegasus->carrier_check); - unregister_netdev(pegasus->net); - usb_put_dev(interface_to_usbdev(intf)); - unlink_all_urbs(pegasus); - free_all_urbs(pegasus); - free_skb_pool(pegasus); - if (pegasus->rx_skb != NULL) { - dev_kfree_skb(pegasus->rx_skb); - pegasus->rx_skb = NULL; - } - free_netdev(pegasus->net); -} - -static int pegasus_suspend (struct usb_interface *intf, pm_message_t message) -{ - struct pegasus *pegasus = usb_get_intfdata(intf); - - netif_device_detach (pegasus->net); - cancel_delayed_work(&pegasus->carrier_check); - if (netif_running(pegasus->net)) { - usb_kill_urb(pegasus->rx_urb); - usb_kill_urb(pegasus->intr_urb); - } - return 0; -} - -static int pegasus_resume (struct usb_interface *intf) -{ - struct pegasus *pegasus = usb_get_intfdata(intf); - - netif_device_attach (pegasus->net); - if (netif_running(pegasus->net)) { - pegasus->rx_urb->status = 0; - pegasus->rx_urb->actual_length = 0; - read_bulk_callback(pegasus->rx_urb); - - pegasus->intr_urb->status = 0; - pegasus->intr_urb->actual_length = 0; - intr_callback(pegasus->intr_urb); - } - queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, - CARRIER_CHECK_DELAY); - return 0; -} - -static struct usb_driver pegasus_driver = { - .name = driver_name, - .probe = pegasus_probe, - .disconnect = pegasus_disconnect, - .id_table = pegasus_ids, - .suspend = pegasus_suspend, - .resume = pegasus_resume, -}; - -static void parse_id(char *id) -{ - unsigned int vendor_id=0, device_id=0, flags=0, i=0; - char *token, *name=NULL; - - if ((token = strsep(&id, ":")) != NULL) - name = token; - /* name now points to a null terminated string*/ - if ((token = strsep(&id, ":")) != NULL) - vendor_id = simple_strtoul(token, NULL, 16); - if ((token = strsep(&id, ":")) != NULL) - device_id = simple_strtoul(token, NULL, 16); - flags = simple_strtoul(id, NULL, 16); - pr_info("%s: new device %s, vendor ID 0x%04x, device ID 0x%04x, flags: 0x%x\n", - driver_name, name, vendor_id, device_id, flags); - - if (vendor_id > 0x10000 || vendor_id == 0) - return; - if (device_id > 0x10000 || device_id == 0) - return; - - for (i=0; usb_dev_id[i].name; i++); - usb_dev_id[i].name = name; - usb_dev_id[i].vendor = vendor_id; - usb_dev_id[i].device = device_id; - usb_dev_id[i].private = flags; - pegasus_ids[i].match_flags = USB_DEVICE_ID_MATCH_DEVICE; - pegasus_ids[i].idVendor = vendor_id; - pegasus_ids[i].idProduct = device_id; -} - -static int __init pegasus_init(void) -{ - pr_info("%s: %s, " DRIVER_DESC "\n", driver_name, DRIVER_VERSION); - if (devid) - parse_id(devid); - pegasus_workqueue = create_singlethread_workqueue("pegasus"); - if (!pegasus_workqueue) - return -ENOMEM; - return usb_register(&pegasus_driver); -} - -static void __exit pegasus_exit(void) -{ - destroy_workqueue(pegasus_workqueue); - usb_deregister(&pegasus_driver); -} - -module_init(pegasus_init); -module_exit(pegasus_exit); diff --git a/drivers/usb/net/pegasus.h b/drivers/usb/net/pegasus.h deleted file mode 100644 index c7467823cd1c..000000000000 --- a/drivers/usb/net/pegasus.h +++ /dev/null @@ -1,307 +0,0 @@ -/* - * Copyright (c) 1999-2003 Petko Manolov - Petkan (petkan@users.sourceforge.net) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - */ - - -#ifndef PEGASUS_DEV - -#define PEGASUS_II 0x80000000 -#define HAS_HOME_PNA 0x40000000 - -#define PEGASUS_MTU 1536 -#define RX_SKBS 4 - -#define EPROM_WRITE 0x01 -#define EPROM_READ 0x02 -#define EPROM_DONE 0x04 -#define EPROM_WR_ENABLE 0x10 -#define EPROM_LOAD 0x20 - -#define PHY_DONE 0x80 -#define PHY_READ 0x40 -#define PHY_WRITE 0x20 -#define DEFAULT_GPIO_RESET 0x24 -#define DEFAULT_GPIO_SET 0x26 - -#define PEGASUS_PRESENT 0x00000001 -#define PEGASUS_TX_BUSY 0x00000004 -#define PEGASUS_RX_BUSY 0x00000008 -#define CTRL_URB_RUNNING 0x00000010 -#define CTRL_URB_SLEEP 0x00000020 -#define PEGASUS_UNPLUG 0x00000040 -#define PEGASUS_RX_URB_FAIL 0x00000080 -#define ETH_REGS_CHANGE 0x40000000 -#define ETH_REGS_CHANGED 0x80000000 - -#define RX_MULTICAST 2 -#define RX_PROMISCUOUS 4 - -#define REG_TIMEOUT (HZ) -#define PEGASUS_TX_TIMEOUT (HZ*10) - -#define TX_UNDERRUN 0x80 -#define EXCESSIVE_COL 0x40 -#define LATE_COL 0x20 -#define NO_CARRIER 0x10 -#define LOSS_CARRIER 0x08 -#define JABBER_TIMEOUT 0x04 - -#define LINK_STATUS 0x01 - -#define PEGASUS_REQT_READ 0xc0 -#define PEGASUS_REQT_WRITE 0x40 -#define PEGASUS_REQ_GET_REGS 0xf0 -#define PEGASUS_REQ_SET_REGS 0xf1 -#define PEGASUS_REQ_SET_REG PEGASUS_REQ_SET_REGS - -enum pegasus_registers { - EthCtrl0 = 0, - EthCtrl1 = 1, - EthCtrl2 = 2, - EthID = 0x10, - Reg1d = 0x1d, - EpromOffset = 0x20, - EpromData = 0x21, /* 0x21 low, 0x22 high byte */ - EpromCtrl = 0x23, - PhyAddr = 0x25, - PhyData = 0x26, /* 0x26 low, 0x27 high byte */ - PhyCtrl = 0x28, - UsbStst = 0x2a, - EthTxStat0 = 0x2b, - EthTxStat1 = 0x2c, - EthRxStat = 0x2d, - WakeupControl = 0x78, - Reg7b = 0x7b, - Gpio0 = 0x7e, - Gpio1 = 0x7f, - Reg81 = 0x81, -}; - - -typedef struct pegasus { - struct usb_device *usb; - struct usb_interface *intf; - struct net_device *net; - struct net_device_stats stats; - struct mii_if_info mii; - unsigned flags; - unsigned features; - u32 msg_enable; - u32 wolopts; - int dev_index; - int intr_interval; - struct tasklet_struct rx_tl; - struct delayed_work carrier_check; - struct urb *ctrl_urb, *rx_urb, *tx_urb, *intr_urb; - struct sk_buff *rx_pool[RX_SKBS]; - struct sk_buff *rx_skb; - struct usb_ctrlrequest dr; - wait_queue_head_t ctrl_wait; - spinlock_t rx_pool_lock; - int chip; - unsigned char intr_buff[8]; - __u8 tx_buff[PEGASUS_MTU]; - __u8 eth_regs[4]; - __u8 phy; - __u8 gpio_res; -} pegasus_t; - - -struct usb_eth_dev { - char *name; - __u16 vendor; - __u16 device; - __u32 private; /* LSB is gpio reset value */ -}; - -#define VENDOR_3COM 0x0506 -#define VENDOR_ABOCOM 0x07b8 -#define VENDOR_ACCTON 0x083a -#define VENDOR_ADMTEK 0x07a6 -#define VENDOR_AEILAB 0x3334 -#define VENDOR_ALLIEDTEL 0x07c9 -#define VENDOR_ATEN 0x0557 -#define VENDOR_BELKIN 0x050d -#define VENDOR_BILLIONTON 0x08dd -#define VENDOR_COMPAQ 0x049f -#define VENDOR_COREGA 0x07aa -#define VENDOR_DLINK 0x2001 -#define VENDOR_ELCON 0x0db7 -#define VENDOR_ELECOM 0x056e -#define VENDOR_ELSA 0x05cc -#define VENDOR_GIGABYTE 0x1044 -#define VENDOR_HAWKING 0x0e66 -#define VENDOR_HP 0x03f0 -#define VENDOR_IODATA 0x04bb -#define VENDOR_KINGSTON 0x0951 -#define VENDOR_LANEED 0x056e -#define VENDOR_LINKSYS 0x066b -#define VENDOR_LINKSYS2 0x077b -#define VENDOR_MELCO 0x0411 -#define VENDOR_MICROSOFT 0x045e -#define VENDOR_MOBILITY 0x1342 -#define VENDOR_NETGEAR 0x0846 -#define VENDOR_OCT 0x0b39 -#define VENDOR_SMARTBRIDGES 0x08d1 -#define VENDOR_SMC 0x0707 -#define VENDOR_SOHOWARE 0x15e8 -#define VENDOR_SIEMENS 0x067c - - -#else /* PEGASUS_DEV */ - -PEGASUS_DEV( "3Com USB Ethernet 3C460B", VENDOR_3COM, 0x4601, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "ATEN USB Ethernet UC-110T", VENDOR_ATEN, 0x2007, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x110c, - DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA ) -PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4104, - DEFAULT_GPIO_RESET | HAS_HOME_PNA ) -PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4004, - DEFAULT_GPIO_RESET | HAS_HOME_PNA ) -PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4007, - DEFAULT_GPIO_RESET | HAS_HOME_PNA ) -PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x4102, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x4002, - DEFAULT_GPIO_RESET ) -PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x400b, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x400c, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0xabc1, - DEFAULT_GPIO_RESET ) -PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x200c, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "Accton USB 10/100 Ethernet Adapter", VENDOR_ACCTON, 0x1046, - DEFAULT_GPIO_RESET ) -PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_ACCTON, 0x5046, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "Philips USB 10/100 Ethernet", VENDOR_ACCTON, 0xb004, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet", - VENDOR_ADMTEK, 0x8511, - DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA ) -PEGASUS_DEV( "ADMtek ADM8513 \"Pegasus II\" USB Ethernet", - VENDOR_ADMTEK, 0x8513, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "ADMtek ADM8515 \"Pegasus II\" USB-2.0 Ethernet", - VENDOR_ADMTEK, 0x8515, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "ADMtek AN986 \"Pegasus\" USB Ethernet (evaluation board)", - VENDOR_ADMTEK, 0x0986, - DEFAULT_GPIO_RESET | HAS_HOME_PNA ) -PEGASUS_DEV( "AN986A USB MAC", VENDOR_ADMTEK, 1986, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "AEI USB Fast Ethernet Adapter", VENDOR_AEILAB, 0x1701, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "Allied Telesyn Int. AT-USB100", VENDOR_ALLIEDTEL, 0xb100, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "Belkin F5D5050 USB Ethernet", VENDOR_BELKIN, 0x0121, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "Billionton USB-100", VENDOR_BILLIONTON, 0x0986, - DEFAULT_GPIO_RESET ) -PEGASUS_DEV( "Billionton USBLP-100", VENDOR_BILLIONTON, 0x0987, - DEFAULT_GPIO_RESET | HAS_HOME_PNA ) -PEGASUS_DEV( "iPAQ Networking 10/100 USB", VENDOR_COMPAQ, 0x8511, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "Billionton USBEL-100", VENDOR_BILLIONTON, 0x0988, - DEFAULT_GPIO_RESET ) -PEGASUS_DEV( "Billionton USBE-100", VENDOR_BILLIONTON, 0x8511, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "Corega FEther USB-TX", VENDOR_COREGA, 0x0004, - DEFAULT_GPIO_RESET ) -PEGASUS_DEV( "Corega FEther USB-TXS", VENDOR_COREGA, 0x000d, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4001, - DEFAULT_GPIO_RESET ) -PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4002, - DEFAULT_GPIO_RESET ) -PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4102, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x400b, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x200c, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "D-Link DSB-650TX(PNA)", VENDOR_DLINK, 0x4003, - DEFAULT_GPIO_RESET | HAS_HOME_PNA ) -PEGASUS_DEV( "D-Link DSB-650", VENDOR_DLINK, 0xabc1, - DEFAULT_GPIO_RESET ) -PEGASUS_DEV( "GOLDPFEIL USB Adapter", VENDOR_ELCON, 0x0002, - DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA ) -PEGASUS_DEV( "ELECOM USB Ethernet LD-USB20", VENDOR_ELECOM, 0x4010, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "EasiDock Ethernet", VENDOR_MOBILITY, 0x0304, - DEFAULT_GPIO_RESET ) -PEGASUS_DEV( "Elsa Micolink USB2Ethernet", VENDOR_ELSA, 0x3000, - DEFAULT_GPIO_RESET ) -PEGASUS_DEV( "GIGABYTE GN-BR402W Wireless Router", VENDOR_GIGABYTE, 0x8002, - DEFAULT_GPIO_RESET ) -PEGASUS_DEV( "Hawking UF100 10/100 Ethernet", VENDOR_HAWKING, 0x400c, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "HP hn210c Ethernet USB", VENDOR_HP, 0x811c, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "IO DATA USB ET/TX", VENDOR_IODATA, 0x0904, - DEFAULT_GPIO_RESET ) -PEGASUS_DEV( "IO DATA USB ET/TX-S", VENDOR_IODATA, 0x0913, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "Kingston KNU101TX Ethernet", VENDOR_KINGSTON, 0x000a, - DEFAULT_GPIO_RESET) -PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x4002, - DEFAULT_GPIO_RESET ) -PEGASUS_DEV( "LANEED USB Ethernet LD-USBL/TX", VENDOR_LANEED, 0x4005, - DEFAULT_GPIO_RESET | PEGASUS_II) -PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x400b, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "LANEED USB Ethernet LD-USB/T", VENDOR_LANEED, 0xabc1, - DEFAULT_GPIO_RESET ) -PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x200c, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "Linksys USB10TX", VENDOR_LINKSYS, 0x2202, - DEFAULT_GPIO_RESET ) -PEGASUS_DEV( "Linksys USB100TX", VENDOR_LINKSYS, 0x2203, - DEFAULT_GPIO_RESET ) -PEGASUS_DEV( "Linksys USB100TX", VENDOR_LINKSYS, 0x2204, - DEFAULT_GPIO_RESET | HAS_HOME_PNA ) -PEGASUS_DEV( "Linksys USB10T Ethernet Adapter", VENDOR_LINKSYS, 0x2206, - DEFAULT_GPIO_RESET | PEGASUS_II) -PEGASUS_DEV( "Linksys USBVPN1", VENDOR_LINKSYS2, 0x08b4, - DEFAULT_GPIO_RESET ) -PEGASUS_DEV( "Linksys USB USB100TX", VENDOR_LINKSYS, 0x400b, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "Linksys USB10TX", VENDOR_LINKSYS, 0x200c, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0001, - DEFAULT_GPIO_RESET ) -PEGASUS_DEV( "MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0005, - DEFAULT_GPIO_RESET ) -PEGASUS_DEV( "MELCO/BUFFALO LUA2-TX", VENDOR_MELCO, 0x0009, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "Microsoft MN-110", VENDOR_MICROSOFT, 0x007a, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "NETGEAR FA101", VENDOR_NETGEAR, 0x1020, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "OCT Inc.", VENDOR_OCT, 0x0109, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "OCT USB TO Ethernet", VENDOR_OCT, 0x0901, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "smartNIC 2 PnP Adapter", VENDOR_SMARTBRIDGES, 0x0003, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "SMC 202 USB Ethernet", VENDOR_SMC, 0x0200, - DEFAULT_GPIO_RESET ) -PEGASUS_DEV( "SMC 2206 USB Ethernet", VENDOR_SMC, 0x0201, - DEFAULT_GPIO_RESET | PEGASUS_II) -PEGASUS_DEV( "SOHOware NUB100 Ethernet", VENDOR_SOHOWARE, 0x9100, - DEFAULT_GPIO_RESET ) -PEGASUS_DEV( "SOHOware NUB110 Ethernet", VENDOR_SOHOWARE, 0x9110, - DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_SIEMENS, 0x1001, - DEFAULT_GPIO_RESET | PEGASUS_II ) - - -#endif /* PEGASUS_DEV */ diff --git a/drivers/usb/net/plusb.c b/drivers/usb/net/plusb.c deleted file mode 100644 index 45300939d185..000000000000 --- a/drivers/usb/net/plusb.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - * PL-2301/2302 USB host-to-host link cables - * Copyright (C) 2000-2005 by David Brownell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -// #define DEBUG // error path messages, extra info -// #define VERBOSE // more; success messages - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/ethtool.h> -#include <linux/workqueue.h> -#include <linux/mii.h> -#include <linux/usb.h> - -#include "usbnet.h" - - -/* - * Prolific PL-2301/PL-2302 driver ... http://www.prolifictech.com - * - * The protocol and handshaking used here should be bug-compatible - * with the Linux 2.2 "plusb" driver, by Deti Fliegl. - * - * HEADS UP: this handshaking isn't all that robust. This driver - * gets confused easily if you unplug one end of the cable then - * try to connect it again; you'll need to restart both ends. The - * "naplink" software (used by some PlayStation/2 deveopers) does - * the handshaking much better! Also, sometimes this hardware - * seems to get wedged under load. Prolific docs are weak, and - * don't identify differences between PL2301 and PL2302, much less - * anything to explain the different PL2302 versions observed. - */ - -/* - * Bits 0-4 can be used for software handshaking; they're set from - * one end, cleared from the other, "read" with the interrupt byte. - */ -#define PL_S_EN (1<<7) /* (feature only) suspend enable */ -/* reserved bit -- rx ready (6) ? */ -#define PL_TX_READY (1<<5) /* (interrupt only) transmit ready */ -#define PL_RESET_OUT (1<<4) /* reset output pipe */ -#define PL_RESET_IN (1<<3) /* reset input pipe */ -#define PL_TX_C (1<<2) /* transmission complete */ -#define PL_TX_REQ (1<<1) /* transmission received */ -#define PL_PEER_E (1<<0) /* peer exists */ - -static inline int -pl_vendor_req(struct usbnet *dev, u8 req, u8 val, u8 index) -{ - return usb_control_msg(dev->udev, - usb_rcvctrlpipe(dev->udev, 0), - req, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - val, index, - NULL, 0, - USB_CTRL_GET_TIMEOUT); -} - -static inline int -pl_clear_QuickLink_features(struct usbnet *dev, int val) -{ - return pl_vendor_req(dev, 1, (u8) val, 0); -} - -static inline int -pl_set_QuickLink_features(struct usbnet *dev, int val) -{ - return pl_vendor_req(dev, 3, (u8) val, 0); -} - -static int pl_reset(struct usbnet *dev) -{ - /* some units seem to need this reset, others reject it utterly. - * FIXME be more like "naplink" or windows drivers. - */ - (void) pl_set_QuickLink_features(dev, - PL_S_EN|PL_RESET_OUT|PL_RESET_IN|PL_PEER_E); - return 0; -} - -static const struct driver_info prolific_info = { - .description = "Prolific PL-2301/PL-2302", - .flags = FLAG_NO_SETINT, - /* some PL-2302 versions seem to fail usb_set_interface() */ - .reset = pl_reset, -}; - - -/*-------------------------------------------------------------------------*/ - -/* - * Proilific's name won't normally be on the cables, and - * may not be on the device. - */ - -static const struct usb_device_id products [] = { - -{ - USB_DEVICE(0x067b, 0x0000), // PL-2301 - .driver_info = (unsigned long) &prolific_info, -}, { - USB_DEVICE(0x067b, 0x0001), // PL-2302 - .driver_info = (unsigned long) &prolific_info, -}, - - { }, // END -}; -MODULE_DEVICE_TABLE(usb, products); - -static struct usb_driver plusb_driver = { - .name = "plusb", - .id_table = products, - .probe = usbnet_probe, - .disconnect = usbnet_disconnect, - .suspend = usbnet_suspend, - .resume = usbnet_resume, -}; - -static int __init plusb_init(void) -{ - return usb_register(&plusb_driver); -} -module_init(plusb_init); - -static void __exit plusb_exit(void) -{ - usb_deregister(&plusb_driver); -} -module_exit(plusb_exit); - -MODULE_AUTHOR("David Brownell"); -MODULE_DESCRIPTION("Prolific PL-2301/2302 USB Host to Host Link Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/net/rndis_host.c b/drivers/usb/net/rndis_host.c deleted file mode 100644 index 980e4aaa97aa..000000000000 --- a/drivers/usb/net/rndis_host.c +++ /dev/null @@ -1,727 +0,0 @@ -/* - * Host Side support for RNDIS Networking Links - * Copyright (C) 2005 by David Brownell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -// #define DEBUG // error path messages, extra info -// #define VERBOSE // more; success messages - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/ethtool.h> -#include <linux/workqueue.h> -#include <linux/mii.h> -#include <linux/usb.h> -#include <linux/usb/cdc.h> - -#include "usbnet.h" - - -/* - * RNDIS is NDIS remoted over USB. It's a MSFT variant of CDC ACM ... of - * course ACM was intended for modems, not Ethernet links! USB's standard - * for Ethernet links is "CDC Ethernet", which is significantly simpler. - * - * NOTE that Microsoft's "RNDIS 1.0" specification is incomplete. Issues - * include: - * - Power management in particular relies on information that's scattered - * through other documentation, and which is incomplete or incorrect even - * there. - * - There are various undocumented protocol requirements, such as the - * need to send unused garbage in control-OUT messages. - * - In some cases, MS-Windows will emit undocumented requests; this - * matters more to peripheral implementations than host ones. - * - * Moreover there's a no-open-specs variant of RNDIS called "ActiveSync". - * - * For these reasons and others, ** USE OF RNDIS IS STRONGLY DISCOURAGED ** in - * favor of such non-proprietary alternatives as CDC Ethernet or the newer (and - * currently rare) "Ethernet Emulation Model" (EEM). - */ - -/* - * CONTROL uses CDC "encapsulated commands" with funky notifications. - * - control-out: SEND_ENCAPSULATED - * - interrupt-in: RESPONSE_AVAILABLE - * - control-in: GET_ENCAPSULATED - * - * We'll try to ignore the RESPONSE_AVAILABLE notifications. - * - * REVISIT some RNDIS implementations seem to have curious issues still - * to be resolved. - */ -struct rndis_msg_hdr { - __le32 msg_type; /* RNDIS_MSG_* */ - __le32 msg_len; - // followed by data that varies between messages - __le32 request_id; - __le32 status; - // ... and more -} __attribute__ ((packed)); - -/* MS-Windows uses this strange size, but RNDIS spec says 1024 minimum */ -#define CONTROL_BUFFER_SIZE 1025 - -/* RNDIS defines an (absurdly huge) 10 second control timeout, - * but ActiveSync seems to use a more usual 5 second timeout - * (which matches the USB 2.0 spec). - */ -#define RNDIS_CONTROL_TIMEOUT_MS (5 * 1000) - - -#define ccpu2 __constant_cpu_to_le32 - -#define RNDIS_MSG_COMPLETION ccpu2(0x80000000) - -/* codes for "msg_type" field of rndis messages; - * only the data channel uses packet messages (maybe batched); - * everything else goes on the control channel. - */ -#define RNDIS_MSG_PACKET ccpu2(0x00000001) /* 1-N packets */ -#define RNDIS_MSG_INIT ccpu2(0x00000002) -#define RNDIS_MSG_INIT_C (RNDIS_MSG_INIT|RNDIS_MSG_COMPLETION) -#define RNDIS_MSG_HALT ccpu2(0x00000003) -#define RNDIS_MSG_QUERY ccpu2(0x00000004) -#define RNDIS_MSG_QUERY_C (RNDIS_MSG_QUERY|RNDIS_MSG_COMPLETION) -#define RNDIS_MSG_SET ccpu2(0x00000005) -#define RNDIS_MSG_SET_C (RNDIS_MSG_SET|RNDIS_MSG_COMPLETION) -#define RNDIS_MSG_RESET ccpu2(0x00000006) -#define RNDIS_MSG_RESET_C (RNDIS_MSG_RESET|RNDIS_MSG_COMPLETION) -#define RNDIS_MSG_INDICATE ccpu2(0x00000007) -#define RNDIS_MSG_KEEPALIVE ccpu2(0x00000008) -#define RNDIS_MSG_KEEPALIVE_C (RNDIS_MSG_KEEPALIVE|RNDIS_MSG_COMPLETION) - -/* codes for "status" field of completion messages */ -#define RNDIS_STATUS_SUCCESS ccpu2(0x00000000) -#define RNDIS_STATUS_FAILURE ccpu2(0xc0000001) -#define RNDIS_STATUS_INVALID_DATA ccpu2(0xc0010015) -#define RNDIS_STATUS_NOT_SUPPORTED ccpu2(0xc00000bb) -#define RNDIS_STATUS_MEDIA_CONNECT ccpu2(0x4001000b) -#define RNDIS_STATUS_MEDIA_DISCONNECT ccpu2(0x4001000c) - - -struct rndis_data_hdr { - __le32 msg_type; /* RNDIS_MSG_PACKET */ - __le32 msg_len; // rndis_data_hdr + data_len + pad - __le32 data_offset; // 36 -- right after header - __le32 data_len; // ... real packet size - - __le32 oob_data_offset; // zero - __le32 oob_data_len; // zero - __le32 num_oob; // zero - __le32 packet_data_offset; // zero - - __le32 packet_data_len; // zero - __le32 vc_handle; // zero - __le32 reserved; // zero -} __attribute__ ((packed)); - -struct rndis_init { /* OUT */ - // header and: - __le32 msg_type; /* RNDIS_MSG_INIT */ - __le32 msg_len; // 24 - __le32 request_id; - __le32 major_version; // of rndis (1.0) - __le32 minor_version; - __le32 max_transfer_size; -} __attribute__ ((packed)); - -struct rndis_init_c { /* IN */ - // header and: - __le32 msg_type; /* RNDIS_MSG_INIT_C */ - __le32 msg_len; - __le32 request_id; - __le32 status; - __le32 major_version; // of rndis (1.0) - __le32 minor_version; - __le32 device_flags; - __le32 medium; // zero == 802.3 - __le32 max_packets_per_message; - __le32 max_transfer_size; - __le32 packet_alignment; // max 7; (1<<n) bytes - __le32 af_list_offset; // zero - __le32 af_list_size; // zero -} __attribute__ ((packed)); - -struct rndis_halt { /* OUT (no reply) */ - // header and: - __le32 msg_type; /* RNDIS_MSG_HALT */ - __le32 msg_len; - __le32 request_id; -} __attribute__ ((packed)); - -struct rndis_query { /* OUT */ - // header and: - __le32 msg_type; /* RNDIS_MSG_QUERY */ - __le32 msg_len; - __le32 request_id; - __le32 oid; - __le32 len; - __le32 offset; -/*?*/ __le32 handle; // zero -} __attribute__ ((packed)); - -struct rndis_query_c { /* IN */ - // header and: - __le32 msg_type; /* RNDIS_MSG_QUERY_C */ - __le32 msg_len; - __le32 request_id; - __le32 status; - __le32 len; - __le32 offset; -} __attribute__ ((packed)); - -struct rndis_set { /* OUT */ - // header and: - __le32 msg_type; /* RNDIS_MSG_SET */ - __le32 msg_len; - __le32 request_id; - __le32 oid; - __le32 len; - __le32 offset; -/*?*/ __le32 handle; // zero -} __attribute__ ((packed)); - -struct rndis_set_c { /* IN */ - // header and: - __le32 msg_type; /* RNDIS_MSG_SET_C */ - __le32 msg_len; - __le32 request_id; - __le32 status; -} __attribute__ ((packed)); - -struct rndis_reset { /* IN */ - // header and: - __le32 msg_type; /* RNDIS_MSG_RESET */ - __le32 msg_len; - __le32 reserved; -} __attribute__ ((packed)); - -struct rndis_reset_c { /* OUT */ - // header and: - __le32 msg_type; /* RNDIS_MSG_RESET_C */ - __le32 msg_len; - __le32 status; - __le32 addressing_lost; -} __attribute__ ((packed)); - -struct rndis_indicate { /* IN (unrequested) */ - // header and: - __le32 msg_type; /* RNDIS_MSG_INDICATE */ - __le32 msg_len; - __le32 status; - __le32 length; - __le32 offset; -/**/ __le32 diag_status; - __le32 error_offset; -/**/ __le32 message; -} __attribute__ ((packed)); - -struct rndis_keepalive { /* OUT (optionally IN) */ - // header and: - __le32 msg_type; /* RNDIS_MSG_KEEPALIVE */ - __le32 msg_len; - __le32 request_id; -} __attribute__ ((packed)); - -struct rndis_keepalive_c { /* IN (optionally OUT) */ - // header and: - __le32 msg_type; /* RNDIS_MSG_KEEPALIVE_C */ - __le32 msg_len; - __le32 request_id; - __le32 status; -} __attribute__ ((packed)); - -/* NOTE: about 30 OIDs are "mandatory" for peripherals to support ... and - * there are gobs more that may optionally be supported. We'll avoid as much - * of that mess as possible. - */ -#define OID_802_3_PERMANENT_ADDRESS ccpu2(0x01010101) -#define OID_GEN_MAXIMUM_FRAME_SIZE ccpu2(0x00010106) -#define OID_GEN_CURRENT_PACKET_FILTER ccpu2(0x0001010e) - -/* - * RNDIS notifications from device: command completion; "reverse" - * keepalives; etc - */ -static void rndis_status(struct usbnet *dev, struct urb *urb) -{ - devdbg(dev, "rndis status urb, len %d stat %d", - urb->actual_length, urb->status); - // FIXME for keepalives, respond immediately (asynchronously) - // if not an RNDIS status, do like cdc_status(dev,urb) does -} - -/* - * RPC done RNDIS-style. Caller guarantees: - * - message is properly byteswapped - * - there's no other request pending - * - buf can hold up to 1KB response (required by RNDIS spec) - * On return, the first few entries are already byteswapped. - * - * Call context is likely probe(), before interface name is known, - * which is why we won't try to use it in the diagnostics. - */ -static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf) -{ - struct cdc_state *info = (void *) &dev->data; - int master_ifnum; - int retval; - unsigned count; - __le32 rsp; - u32 xid = 0, msg_len, request_id; - - /* REVISIT when this gets called from contexts other than probe() or - * disconnect(): either serialize, or dispatch responses on xid - */ - - /* Issue the request; xid is unique, don't bother byteswapping it */ - if (likely(buf->msg_type != RNDIS_MSG_HALT - && buf->msg_type != RNDIS_MSG_RESET)) { - xid = dev->xid++; - if (!xid) - xid = dev->xid++; - buf->request_id = (__force __le32) xid; - } - master_ifnum = info->control->cur_altsetting->desc.bInterfaceNumber; - retval = usb_control_msg(dev->udev, - usb_sndctrlpipe(dev->udev, 0), - USB_CDC_SEND_ENCAPSULATED_COMMAND, - USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, master_ifnum, - buf, le32_to_cpu(buf->msg_len), - RNDIS_CONTROL_TIMEOUT_MS); - if (unlikely(retval < 0 || xid == 0)) - return retval; - - // FIXME Seems like some devices discard responses when - // we time out and cancel our "get response" requests... - // so, this is fragile. Probably need to poll for status. - - /* ignore status endpoint, just poll the control channel; - * the request probably completed immediately - */ - rsp = buf->msg_type | RNDIS_MSG_COMPLETION; - for (count = 0; count < 10; count++) { - memset(buf, 0, CONTROL_BUFFER_SIZE); - retval = usb_control_msg(dev->udev, - usb_rcvctrlpipe(dev->udev, 0), - USB_CDC_GET_ENCAPSULATED_RESPONSE, - USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, master_ifnum, - buf, CONTROL_BUFFER_SIZE, - RNDIS_CONTROL_TIMEOUT_MS); - if (likely(retval >= 8)) { - msg_len = le32_to_cpu(buf->msg_len); - request_id = (__force u32) buf->request_id; - if (likely(buf->msg_type == rsp)) { - if (likely(request_id == xid)) { - if (unlikely(rsp == RNDIS_MSG_RESET_C)) - return 0; - if (likely(RNDIS_STATUS_SUCCESS - == buf->status)) - return 0; - dev_dbg(&info->control->dev, - "rndis reply status %08x\n", - le32_to_cpu(buf->status)); - return -EL3RST; - } - dev_dbg(&info->control->dev, - "rndis reply id %d expected %d\n", - request_id, xid); - /* then likely retry */ - } else switch (buf->msg_type) { - case RNDIS_MSG_INDICATE: { /* fault */ - // struct rndis_indicate *msg = (void *)buf; - dev_info(&info->control->dev, - "rndis fault indication\n"); - } - break; - case RNDIS_MSG_KEEPALIVE: { /* ping */ - struct rndis_keepalive_c *msg = (void *)buf; - - msg->msg_type = RNDIS_MSG_KEEPALIVE_C; - msg->msg_len = ccpu2(sizeof *msg); - msg->status = RNDIS_STATUS_SUCCESS; - retval = usb_control_msg(dev->udev, - usb_sndctrlpipe(dev->udev, 0), - USB_CDC_SEND_ENCAPSULATED_COMMAND, - USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, master_ifnum, - msg, sizeof *msg, - RNDIS_CONTROL_TIMEOUT_MS); - if (unlikely(retval < 0)) - dev_dbg(&info->control->dev, - "rndis keepalive err %d\n", - retval); - } - break; - default: - dev_dbg(&info->control->dev, - "unexpected rndis msg %08x len %d\n", - le32_to_cpu(buf->msg_type), msg_len); - } - } else { - /* device probably issued a protocol stall; ignore */ - dev_dbg(&info->control->dev, - "rndis response error, code %d\n", retval); - } - msleep(2); - } - dev_dbg(&info->control->dev, "rndis response timeout\n"); - return -ETIMEDOUT; -} - -/* - * rndis_query: - * - * Performs a query for @oid along with 0 or more bytes of payload as - * specified by @in_len. If @reply_len is not set to -1 then the reply - * length is checked against this value, resulting in an error if it - * doesn't match. - * - * NOTE: Adding a payload exactly or greater than the size of the expected - * response payload is an evident requirement MSFT added for ActiveSync. - * - * The only exception is for OIDs that return a variably sized response, - * in which case no payload should be added. This undocumented (and - * nonsensical!) issue was found by sniffing protocol requests from the - * ActiveSync 4.1 Windows driver. - */ -static int rndis_query(struct usbnet *dev, struct usb_interface *intf, - void *buf, u32 oid, u32 in_len, - void **reply, int *reply_len) -{ - int retval; - union { - void *buf; - struct rndis_msg_hdr *header; - struct rndis_query *get; - struct rndis_query_c *get_c; - } u; - u32 off, len; - - u.buf = buf; - - memset(u.get, 0, sizeof *u.get + in_len); - u.get->msg_type = RNDIS_MSG_QUERY; - u.get->msg_len = cpu_to_le32(sizeof *u.get + in_len); - u.get->oid = oid; - u.get->len = cpu_to_le32(in_len); - u.get->offset = ccpu2(20); - - retval = rndis_command(dev, u.header); - if (unlikely(retval < 0)) { - dev_err(&intf->dev, "RNDIS_MSG_QUERY(0x%08x) failed, %d\n", - oid, retval); - return retval; - } - - off = le32_to_cpu(u.get_c->offset); - len = le32_to_cpu(u.get_c->len); - if (unlikely((8 + off + len) > CONTROL_BUFFER_SIZE)) - goto response_error; - - if (*reply_len != -1 && len != *reply_len) - goto response_error; - - *reply = (unsigned char *) &u.get_c->request_id + off; - *reply_len = len; - - return retval; - -response_error: - dev_err(&intf->dev, "RNDIS_MSG_QUERY(0x%08x) " - "invalid response - off %d len %d\n", - oid, off, len); - return -EDOM; -} - -static int rndis_bind(struct usbnet *dev, struct usb_interface *intf) -{ - int retval; - struct net_device *net = dev->net; - struct cdc_state *info = (void *) &dev->data; - union { - void *buf; - struct rndis_msg_hdr *header; - struct rndis_init *init; - struct rndis_init_c *init_c; - struct rndis_query *get; - struct rndis_query_c *get_c; - struct rndis_set *set; - struct rndis_set_c *set_c; - } u; - u32 tmp; - int reply_len; - unsigned char *bp; - - /* we can't rely on i/o from stack working, or stack allocation */ - u.buf = kmalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL); - if (!u.buf) - return -ENOMEM; - retval = usbnet_generic_cdc_bind(dev, intf); - if (retval < 0) - goto fail; - - u.init->msg_type = RNDIS_MSG_INIT; - u.init->msg_len = ccpu2(sizeof *u.init); - u.init->major_version = ccpu2(1); - u.init->minor_version = ccpu2(0); - - /* max transfer (in spec) is 0x4000 at full speed, but for - * TX we'll stick to one Ethernet packet plus RNDIS framing. - * For RX we handle drivers that zero-pad to end-of-packet. - * Don't let userspace change these settings. - * - * NOTE: there still seems to be wierdness here, as if we need - * to do some more things to make sure WinCE targets accept this. - * They default to jumbograms of 8KB or 16KB, which is absurd - * for such low data rates and which is also more than Linux - * can usually expect to allocate for SKB data... - */ - net->hard_header_len += sizeof (struct rndis_data_hdr); - dev->hard_mtu = net->mtu + net->hard_header_len; - - dev->rx_urb_size = dev->hard_mtu + (dev->maxpacket + 1); - dev->rx_urb_size &= ~(dev->maxpacket - 1); - u.init->max_transfer_size = cpu_to_le32(dev->rx_urb_size); - - net->change_mtu = NULL; - retval = rndis_command(dev, u.header); - if (unlikely(retval < 0)) { - /* it might not even be an RNDIS device!! */ - dev_err(&intf->dev, "RNDIS init failed, %d\n", retval); - goto fail_and_release; - } - tmp = le32_to_cpu(u.init_c->max_transfer_size); - if (tmp < dev->hard_mtu) { - dev_err(&intf->dev, - "dev can't take %u byte packets (max %u)\n", - dev->hard_mtu, tmp); - goto fail_and_release; - } - - /* REVISIT: peripheral "alignment" request is ignored ... */ - dev_dbg(&intf->dev, - "hard mtu %u (%u from dev), rx buflen %Zu, align %d\n", - dev->hard_mtu, tmp, dev->rx_urb_size, - 1 << le32_to_cpu(u.init_c->packet_alignment)); - - /* Get designated host ethernet address */ - reply_len = ETH_ALEN; - retval = rndis_query(dev, intf, u.buf, OID_802_3_PERMANENT_ADDRESS, - 48, (void **) &bp, &reply_len); - if (unlikely(retval< 0)) { - dev_err(&intf->dev, "rndis get ethaddr, %d\n", retval); - goto fail_and_release; - } - memcpy(net->dev_addr, bp, ETH_ALEN); - - /* set a nonzero filter to enable data transfers */ - memset(u.set, 0, sizeof *u.set); - u.set->msg_type = RNDIS_MSG_SET; - u.set->msg_len = ccpu2(4 + sizeof *u.set); - u.set->oid = OID_GEN_CURRENT_PACKET_FILTER; - u.set->len = ccpu2(4); - u.set->offset = ccpu2((sizeof *u.set) - 8); - *(__le32 *)(u.buf + sizeof *u.set) = ccpu2(DEFAULT_FILTER); - - retval = rndis_command(dev, u.header); - if (unlikely(retval < 0)) { - dev_err(&intf->dev, "rndis set packet filter, %d\n", retval); - goto fail_and_release; - } - - retval = 0; - - kfree(u.buf); - return retval; - -fail_and_release: - usb_set_intfdata(info->data, NULL); - usb_driver_release_interface(driver_of(intf), info->data); - info->data = NULL; -fail: - kfree(u.buf); - return retval; -} - -static void rndis_unbind(struct usbnet *dev, struct usb_interface *intf) -{ - struct rndis_halt *halt; - - /* try to clear any rndis state/activity (no i/o from stack!) */ - halt = kzalloc(sizeof *halt, GFP_KERNEL); - if (halt) { - halt->msg_type = RNDIS_MSG_HALT; - halt->msg_len = ccpu2(sizeof *halt); - (void) rndis_command(dev, (void *)halt); - kfree(halt); - } - - return usbnet_cdc_unbind(dev, intf); -} - -/* - * DATA -- host must not write zlps - */ -static int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb) -{ - /* peripheral may have batched packets to us... */ - while (likely(skb->len)) { - struct rndis_data_hdr *hdr = (void *)skb->data; - struct sk_buff *skb2; - u32 msg_len, data_offset, data_len; - - msg_len = le32_to_cpu(hdr->msg_len); - data_offset = le32_to_cpu(hdr->data_offset); - data_len = le32_to_cpu(hdr->data_len); - - /* don't choke if we see oob, per-packet data, etc */ - if (unlikely(hdr->msg_type != RNDIS_MSG_PACKET - || skb->len < msg_len - || (data_offset + data_len + 8) > msg_len)) { - dev->stats.rx_frame_errors++; - devdbg(dev, "bad rndis message %d/%d/%d/%d, len %d", - le32_to_cpu(hdr->msg_type), - msg_len, data_offset, data_len, skb->len); - return 0; - } - skb_pull(skb, 8 + data_offset); - - /* at most one packet left? */ - if (likely((data_len - skb->len) <= sizeof *hdr)) { - skb_trim(skb, data_len); - break; - } - - /* try to return all the packets in the batch */ - skb2 = skb_clone(skb, GFP_ATOMIC); - if (unlikely(!skb2)) - break; - skb_pull(skb, msg_len - sizeof *hdr); - skb_trim(skb2, data_len); - usbnet_skb_return(dev, skb2); - } - - /* caller will usbnet_skb_return the remaining packet */ - return 1; -} - -static struct sk_buff * -rndis_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) -{ - struct rndis_data_hdr *hdr; - struct sk_buff *skb2; - unsigned len = skb->len; - - if (likely(!skb_cloned(skb))) { - int room = skb_headroom(skb); - - /* enough head room as-is? */ - if (unlikely((sizeof *hdr) <= room)) - goto fill; - - /* enough room, but needs to be readjusted? */ - room += skb_tailroom(skb); - if (likely((sizeof *hdr) <= room)) { - skb->data = memmove(skb->head + sizeof *hdr, - skb->data, len); - skb_set_tail_pointer(skb, len); - goto fill; - } - } - - /* create a new skb, with the correct size (and tailpad) */ - skb2 = skb_copy_expand(skb, sizeof *hdr, 1, flags); - dev_kfree_skb_any(skb); - if (unlikely(!skb2)) - return skb2; - skb = skb2; - - /* fill out the RNDIS header. we won't bother trying to batch - * packets; Linux minimizes wasted bandwidth through tx queues. - */ -fill: - hdr = (void *) __skb_push(skb, sizeof *hdr); - memset(hdr, 0, sizeof *hdr); - hdr->msg_type = RNDIS_MSG_PACKET; - hdr->msg_len = cpu_to_le32(skb->len); - hdr->data_offset = ccpu2(sizeof(*hdr) - 8); - hdr->data_len = cpu_to_le32(len); - - /* FIXME make the last packet always be short ... */ - return skb; -} - - -static const struct driver_info rndis_info = { - .description = "RNDIS device", - .flags = FLAG_ETHER | FLAG_FRAMING_RN | FLAG_NO_SETINT, - .bind = rndis_bind, - .unbind = rndis_unbind, - .status = rndis_status, - .rx_fixup = rndis_rx_fixup, - .tx_fixup = rndis_tx_fixup, -}; - -#undef ccpu2 - - -/*-------------------------------------------------------------------------*/ - -static const struct usb_device_id products [] = { -{ - /* RNDIS is MSFT's un-official variant of CDC ACM */ - USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff), - .driver_info = (unsigned long) &rndis_info, -}, { - /* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */ - USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1), - .driver_info = (unsigned long) &rndis_info, -}, - { }, // END -}; -MODULE_DEVICE_TABLE(usb, products); - -static struct usb_driver rndis_driver = { - .name = "rndis_host", - .id_table = products, - .probe = usbnet_probe, - .disconnect = usbnet_disconnect, - .suspend = usbnet_suspend, - .resume = usbnet_resume, -}; - -static int __init rndis_init(void) -{ - return usb_register(&rndis_driver); -} -module_init(rndis_init); - -static void __exit rndis_exit(void) -{ - usb_deregister(&rndis_driver); -} -module_exit(rndis_exit); - -MODULE_AUTHOR("David Brownell"); -MODULE_DESCRIPTION("USB Host side RNDIS driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c deleted file mode 100644 index fa598f0340cf..000000000000 --- a/drivers/usb/net/rtl8150.c +++ /dev/null @@ -1,1004 +0,0 @@ -/* - * Copyright (c) 2002 Petko Manolov (petkan@users.sourceforge.net) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - */ - -#include <linux/init.h> -#include <linux/signal.h> -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/mii.h> -#include <linux/ethtool.h> -#include <linux/usb.h> -#include <asm/uaccess.h> - -/* Version Information */ -#define DRIVER_VERSION "v0.6.2 (2004/08/27)" -#define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>" -#define DRIVER_DESC "rtl8150 based usb-ethernet driver" - -#define IDR 0x0120 -#define MAR 0x0126 -#define CR 0x012e -#define TCR 0x012f -#define RCR 0x0130 -#define TSR 0x0132 -#define RSR 0x0133 -#define CON0 0x0135 -#define CON1 0x0136 -#define MSR 0x0137 -#define PHYADD 0x0138 -#define PHYDAT 0x0139 -#define PHYCNT 0x013b -#define GPPC 0x013d -#define BMCR 0x0140 -#define BMSR 0x0142 -#define ANAR 0x0144 -#define ANLP 0x0146 -#define AER 0x0148 -#define CSCR 0x014C /* This one has the link status */ -#define CSCR_LINK_STATUS (1 << 3) - -#define IDR_EEPROM 0x1202 - -#define PHY_READ 0 -#define PHY_WRITE 0x20 -#define PHY_GO 0x40 - -#define MII_TIMEOUT 10 -#define INTBUFSIZE 8 - -#define RTL8150_REQT_READ 0xc0 -#define RTL8150_REQT_WRITE 0x40 -#define RTL8150_REQ_GET_REGS 0x05 -#define RTL8150_REQ_SET_REGS 0x05 - - -/* Transmit status register errors */ -#define TSR_ECOL (1<<5) -#define TSR_LCOL (1<<4) -#define TSR_LOSS_CRS (1<<3) -#define TSR_JBR (1<<2) -#define TSR_ERRORS (TSR_ECOL | TSR_LCOL | TSR_LOSS_CRS | TSR_JBR) -/* Receive status register errors */ -#define RSR_CRC (1<<2) -#define RSR_FAE (1<<1) -#define RSR_ERRORS (RSR_CRC | RSR_FAE) - -/* Media status register definitions */ -#define MSR_DUPLEX (1<<4) -#define MSR_SPEED (1<<3) -#define MSR_LINK (1<<2) - -/* Interrupt pipe data */ -#define INT_TSR 0x00 -#define INT_RSR 0x01 -#define INT_MSR 0x02 -#define INT_WAKSR 0x03 -#define INT_TXOK_CNT 0x04 -#define INT_RXLOST_CNT 0x05 -#define INT_CRERR_CNT 0x06 -#define INT_COL_CNT 0x07 - -/* Transmit status register errors */ -#define TSR_ECOL (1<<5) -#define TSR_LCOL (1<<4) -#define TSR_LOSS_CRS (1<<3) -#define TSR_JBR (1<<2) -#define TSR_ERRORS (TSR_ECOL | TSR_LCOL | TSR_LOSS_CRS | TSR_JBR) -/* Receive status register errors */ -#define RSR_CRC (1<<2) -#define RSR_FAE (1<<1) -#define RSR_ERRORS (RSR_CRC | RSR_FAE) - -/* Media status register definitions */ -#define MSR_DUPLEX (1<<4) -#define MSR_SPEED (1<<3) -#define MSR_LINK (1<<2) - -/* Interrupt pipe data */ -#define INT_TSR 0x00 -#define INT_RSR 0x01 -#define INT_MSR 0x02 -#define INT_WAKSR 0x03 -#define INT_TXOK_CNT 0x04 -#define INT_RXLOST_CNT 0x05 -#define INT_CRERR_CNT 0x06 -#define INT_COL_CNT 0x07 - - -#define RTL8150_MTU 1540 -#define RTL8150_TX_TIMEOUT (HZ) -#define RX_SKB_POOL_SIZE 4 - -/* rtl8150 flags */ -#define RTL8150_HW_CRC 0 -#define RX_REG_SET 1 -#define RTL8150_UNPLUG 2 -#define RX_URB_FAIL 3 - -/* Define these values to match your device */ -#define VENDOR_ID_REALTEK 0x0bda -#define VENDOR_ID_MELCO 0x0411 -#define VENDOR_ID_MICRONET 0x3980 -#define VENDOR_ID_LONGSHINE 0x07b8 -#define VENDOR_ID_OQO 0x1557 -#define VENDOR_ID_ZYXEL 0x0586 - -#define PRODUCT_ID_RTL8150 0x8150 -#define PRODUCT_ID_LUAKTX 0x0012 -#define PRODUCT_ID_LCS8138TX 0x401a -#define PRODUCT_ID_SP128AR 0x0003 -#define PRODUCT_ID_PRESTIGE 0x401a - -#undef EEPROM_WRITE - -/* table of devices that work with this driver */ -static struct usb_device_id rtl8150_table[] = { - {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8150)}, - {USB_DEVICE(VENDOR_ID_MELCO, PRODUCT_ID_LUAKTX)}, - {USB_DEVICE(VENDOR_ID_MICRONET, PRODUCT_ID_SP128AR)}, - {USB_DEVICE(VENDOR_ID_LONGSHINE, PRODUCT_ID_LCS8138TX)}, - {USB_DEVICE(VENDOR_ID_OQO, PRODUCT_ID_RTL8150)}, - {USB_DEVICE(VENDOR_ID_ZYXEL, PRODUCT_ID_PRESTIGE)}, - {} -}; - -MODULE_DEVICE_TABLE(usb, rtl8150_table); - -struct rtl8150 { - unsigned long flags; - struct usb_device *udev; - struct tasklet_struct tl; - struct net_device_stats stats; - struct net_device *netdev; - struct urb *rx_urb, *tx_urb, *intr_urb, *ctrl_urb; - struct sk_buff *tx_skb, *rx_skb; - struct sk_buff *rx_skb_pool[RX_SKB_POOL_SIZE]; - spinlock_t rx_pool_lock; - struct usb_ctrlrequest dr; - int intr_interval; - __le16 rx_creg; - u8 *intr_buff; - u8 phy; -}; - -typedef struct rtl8150 rtl8150_t; - -static void fill_skb_pool(rtl8150_t *); -static void free_skb_pool(rtl8150_t *); -static inline struct sk_buff *pull_skb(rtl8150_t *); -static void rtl8150_disconnect(struct usb_interface *intf); -static int rtl8150_probe(struct usb_interface *intf, - const struct usb_device_id *id); -static int rtl8150_suspend(struct usb_interface *intf, pm_message_t message); -static int rtl8150_resume(struct usb_interface *intf); - -static const char driver_name [] = "rtl8150"; - -static struct usb_driver rtl8150_driver = { - .name = driver_name, - .probe = rtl8150_probe, - .disconnect = rtl8150_disconnect, - .id_table = rtl8150_table, - .suspend = rtl8150_suspend, - .resume = rtl8150_resume -}; - -/* -** -** device related part of the code -** -*/ -static int get_registers(rtl8150_t * dev, u16 indx, u16 size, void *data) -{ - return usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), - RTL8150_REQ_GET_REGS, RTL8150_REQT_READ, - indx, 0, data, size, 500); -} - -static int set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data) -{ - return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), - RTL8150_REQ_SET_REGS, RTL8150_REQT_WRITE, - indx, 0, data, size, 500); -} - -static void ctrl_callback(struct urb *urb) -{ - rtl8150_t *dev; - - switch (urb->status) { - case 0: - break; - case -EINPROGRESS: - break; - case -ENOENT: - break; - default: - warn("ctrl urb status %d", urb->status); - } - dev = urb->context; - clear_bit(RX_REG_SET, &dev->flags); -} - -static int async_set_registers(rtl8150_t * dev, u16 indx, u16 size) -{ - int ret; - - if (test_bit(RX_REG_SET, &dev->flags)) - return -EAGAIN; - - dev->dr.bRequestType = RTL8150_REQT_WRITE; - dev->dr.bRequest = RTL8150_REQ_SET_REGS; - dev->dr.wValue = cpu_to_le16(indx); - dev->dr.wIndex = 0; - dev->dr.wLength = cpu_to_le16(size); - dev->ctrl_urb->transfer_buffer_length = size; - usb_fill_control_urb(dev->ctrl_urb, dev->udev, - usb_sndctrlpipe(dev->udev, 0), (char *) &dev->dr, - &dev->rx_creg, size, ctrl_callback, dev); - if ((ret = usb_submit_urb(dev->ctrl_urb, GFP_ATOMIC))) { - if (ret == -ENODEV) - netif_device_detach(dev->netdev); - err("control request submission failed: %d", ret); - } else - set_bit(RX_REG_SET, &dev->flags); - - return ret; -} - -static int read_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 * reg) -{ - int i; - u8 data[3], tmp; - - data[0] = phy; - data[1] = data[2] = 0; - tmp = indx | PHY_READ | PHY_GO; - i = 0; - - set_registers(dev, PHYADD, sizeof(data), data); - set_registers(dev, PHYCNT, 1, &tmp); - do { - get_registers(dev, PHYCNT, 1, data); - } while ((data[0] & PHY_GO) && (i++ < MII_TIMEOUT)); - - if (i < MII_TIMEOUT) { - get_registers(dev, PHYDAT, 2, data); - *reg = data[0] | (data[1] << 8); - return 0; - } else - return 1; -} - -static int write_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 reg) -{ - int i; - u8 data[3], tmp; - - data[0] = phy; - data[1] = reg & 0xff; - data[2] = (reg >> 8) & 0xff; - tmp = indx | PHY_WRITE | PHY_GO; - i = 0; - - set_registers(dev, PHYADD, sizeof(data), data); - set_registers(dev, PHYCNT, 1, &tmp); - do { - get_registers(dev, PHYCNT, 1, data); - } while ((data[0] & PHY_GO) && (i++ < MII_TIMEOUT)); - - if (i < MII_TIMEOUT) - return 0; - else - return 1; -} - -static inline void set_ethernet_addr(rtl8150_t * dev) -{ - u8 node_id[6]; - - get_registers(dev, IDR, sizeof(node_id), node_id); - memcpy(dev->netdev->dev_addr, node_id, sizeof(node_id)); -} - -static int rtl8150_set_mac_address(struct net_device *netdev, void *p) -{ - struct sockaddr *addr = p; - rtl8150_t *dev = netdev_priv(netdev); - int i; - - if (netif_running(netdev)) - return -EBUSY; - - memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); - dbg("%s: Setting MAC address to ", netdev->name); - for (i = 0; i < 5; i++) - dbg("%02X:", netdev->dev_addr[i]); - dbg("%02X\n", netdev->dev_addr[i]); - /* Set the IDR registers. */ - set_registers(dev, IDR, sizeof(netdev->dev_addr), netdev->dev_addr); -#ifdef EEPROM_WRITE - { - u8 cr; - /* Get the CR contents. */ - get_registers(dev, CR, 1, &cr); - /* Set the WEPROM bit (eeprom write enable). */ - cr |= 0x20; - set_registers(dev, CR, 1, &cr); - /* Write the MAC address into eeprom. Eeprom writes must be word-sized, - so we need to split them up. */ - for (i = 0; i * 2 < netdev->addr_len; i++) { - set_registers(dev, IDR_EEPROM + (i * 2), 2, - netdev->dev_addr + (i * 2)); - } - /* Clear the WEPROM bit (preventing accidental eeprom writes). */ - cr &= 0xdf; - set_registers(dev, CR, 1, &cr); - } -#endif - return 0; -} - -static int rtl8150_reset(rtl8150_t * dev) -{ - u8 data = 0x10; - int i = HZ; - - set_registers(dev, CR, 1, &data); - do { - get_registers(dev, CR, 1, &data); - } while ((data & 0x10) && --i); - - return (i > 0) ? 1 : 0; -} - -static int alloc_all_urbs(rtl8150_t * dev) -{ - dev->rx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->rx_urb) - return 0; - dev->tx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->tx_urb) { - usb_free_urb(dev->rx_urb); - return 0; - } - dev->intr_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->intr_urb) { - usb_free_urb(dev->rx_urb); - usb_free_urb(dev->tx_urb); - return 0; - } - dev->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->intr_urb) { - usb_free_urb(dev->rx_urb); - usb_free_urb(dev->tx_urb); - usb_free_urb(dev->intr_urb); - return 0; - } - - return 1; -} - -static void free_all_urbs(rtl8150_t * dev) -{ - usb_free_urb(dev->rx_urb); - usb_free_urb(dev->tx_urb); - usb_free_urb(dev->intr_urb); - usb_free_urb(dev->ctrl_urb); -} - -static void unlink_all_urbs(rtl8150_t * dev) -{ - usb_kill_urb(dev->rx_urb); - usb_kill_urb(dev->tx_urb); - usb_kill_urb(dev->intr_urb); - usb_kill_urb(dev->ctrl_urb); -} - -static inline struct sk_buff *pull_skb(rtl8150_t *dev) -{ - struct sk_buff *skb; - int i; - - for (i = 0; i < RX_SKB_POOL_SIZE; i++) { - if (dev->rx_skb_pool[i]) { - skb = dev->rx_skb_pool[i]; - dev->rx_skb_pool[i] = NULL; - return skb; - } - } - return NULL; -} - -static void read_bulk_callback(struct urb *urb) -{ - rtl8150_t *dev; - unsigned pkt_len, res; - struct sk_buff *skb; - struct net_device *netdev; - u16 rx_stat; - int status; - - dev = urb->context; - if (!dev) - return; - if (test_bit(RTL8150_UNPLUG, &dev->flags)) - return; - netdev = dev->netdev; - if (!netif_device_present(netdev)) - return; - - switch (urb->status) { - case 0: - break; - case -ENOENT: - return; /* the urb is in unlink state */ - case -ETIME: - warn("may be reset is needed?.."); - goto goon; - default: - warn("Rx status %d", urb->status); - goto goon; - } - - if (!dev->rx_skb) - goto resched; - /* protect against short packets (tell me why we got some?!?) */ - if (urb->actual_length < 4) - goto goon; - - res = urb->actual_length; - rx_stat = le16_to_cpu(*(__le16 *)(urb->transfer_buffer + res - 4)); - pkt_len = res - 4; - - skb_put(dev->rx_skb, pkt_len); - dev->rx_skb->protocol = eth_type_trans(dev->rx_skb, netdev); - netif_rx(dev->rx_skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes += pkt_len; - - spin_lock(&dev->rx_pool_lock); - skb = pull_skb(dev); - spin_unlock(&dev->rx_pool_lock); - if (!skb) - goto resched; - - dev->rx_skb = skb; -goon: - usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1), - dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev); - status = usb_submit_urb(dev->rx_urb, GFP_ATOMIC); - if (status == -ENODEV) - netif_device_detach(dev->netdev); - else if (status) { - set_bit(RX_URB_FAIL, &dev->flags); - goto resched; - } else { - clear_bit(RX_URB_FAIL, &dev->flags); - } - - return; -resched: - tasklet_schedule(&dev->tl); -} - -static void rx_fixup(unsigned long data) -{ - rtl8150_t *dev; - struct sk_buff *skb; - int status; - - dev = (rtl8150_t *)data; - - spin_lock_irq(&dev->rx_pool_lock); - fill_skb_pool(dev); - spin_unlock_irq(&dev->rx_pool_lock); - if (test_bit(RX_URB_FAIL, &dev->flags)) - if (dev->rx_skb) - goto try_again; - spin_lock_irq(&dev->rx_pool_lock); - skb = pull_skb(dev); - spin_unlock_irq(&dev->rx_pool_lock); - if (skb == NULL) - goto tlsched; - dev->rx_skb = skb; - usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1), - dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev); -try_again: - status = usb_submit_urb(dev->rx_urb, GFP_ATOMIC); - if (status == -ENODEV) { - netif_device_detach(dev->netdev); - } else if (status) { - set_bit(RX_URB_FAIL, &dev->flags); - goto tlsched; - } else { - clear_bit(RX_URB_FAIL, &dev->flags); - } - - return; -tlsched: - tasklet_schedule(&dev->tl); -} - -static void write_bulk_callback(struct urb *urb) -{ - rtl8150_t *dev; - - dev = urb->context; - if (!dev) - return; - dev_kfree_skb_irq(dev->tx_skb); - if (!netif_device_present(dev->netdev)) - return; - if (urb->status) - info("%s: Tx status %d", dev->netdev->name, urb->status); - dev->netdev->trans_start = jiffies; - netif_wake_queue(dev->netdev); -} - -static void intr_callback(struct urb *urb) -{ - rtl8150_t *dev; - __u8 *d; - int status; - - dev = urb->context; - if (!dev) - return; - switch (urb->status) { - case 0: /* success */ - break; - case -ECONNRESET: /* unlink */ - case -ENOENT: - case -ESHUTDOWN: - return; - /* -EPIPE: should clear the halt */ - default: - info("%s: intr status %d", dev->netdev->name, urb->status); - goto resubmit; - } - - d = urb->transfer_buffer; - if (d[0] & TSR_ERRORS) { - dev->stats.tx_errors++; - if (d[INT_TSR] & (TSR_ECOL | TSR_JBR)) - dev->stats.tx_aborted_errors++; - if (d[INT_TSR] & TSR_LCOL) - dev->stats.tx_window_errors++; - if (d[INT_TSR] & TSR_LOSS_CRS) - dev->stats.tx_carrier_errors++; - } - /* Report link status changes to the network stack */ - if ((d[INT_MSR] & MSR_LINK) == 0) { - if (netif_carrier_ok(dev->netdev)) { - netif_carrier_off(dev->netdev); - dbg("%s: LINK LOST\n", __func__); - } - } else { - if (!netif_carrier_ok(dev->netdev)) { - netif_carrier_on(dev->netdev); - dbg("%s: LINK CAME BACK\n", __func__); - } - } - -resubmit: - status = usb_submit_urb (urb, GFP_ATOMIC); - if (status == -ENODEV) - netif_device_detach(dev->netdev); - else if (status) - err ("can't resubmit intr, %s-%s/input0, status %d", - dev->udev->bus->bus_name, - dev->udev->devpath, status); -} - -static int rtl8150_suspend(struct usb_interface *intf, pm_message_t message) -{ - rtl8150_t *dev = usb_get_intfdata(intf); - - netif_device_detach(dev->netdev); - - if (netif_running(dev->netdev)) { - usb_kill_urb(dev->rx_urb); - usb_kill_urb(dev->intr_urb); - } - return 0; -} - -static int rtl8150_resume(struct usb_interface *intf) -{ - rtl8150_t *dev = usb_get_intfdata(intf); - - netif_device_attach(dev->netdev); - if (netif_running(dev->netdev)) { - dev->rx_urb->status = 0; - dev->rx_urb->actual_length = 0; - read_bulk_callback(dev->rx_urb); - - dev->intr_urb->status = 0; - dev->intr_urb->actual_length = 0; - intr_callback(dev->intr_urb); - } - return 0; -} - -/* -** -** network related part of the code -** -*/ - -static void fill_skb_pool(rtl8150_t *dev) -{ - struct sk_buff *skb; - int i; - - for (i = 0; i < RX_SKB_POOL_SIZE; i++) { - if (dev->rx_skb_pool[i]) - continue; - skb = dev_alloc_skb(RTL8150_MTU + 2); - if (!skb) { - return; - } - skb_reserve(skb, 2); - dev->rx_skb_pool[i] = skb; - } -} - -static void free_skb_pool(rtl8150_t *dev) -{ - int i; - - for (i = 0; i < RX_SKB_POOL_SIZE; i++) - if (dev->rx_skb_pool[i]) - dev_kfree_skb(dev->rx_skb_pool[i]); -} - -static int enable_net_traffic(rtl8150_t * dev) -{ - u8 cr, tcr, rcr, msr; - - if (!rtl8150_reset(dev)) { - warn("%s - device reset failed", __FUNCTION__); - } - /* RCR bit7=1 attach Rx info at the end; =0 HW CRC (which is broken) */ - rcr = 0x9e; - dev->rx_creg = cpu_to_le16(rcr); - tcr = 0xd8; - cr = 0x0c; - if (!(rcr & 0x80)) - set_bit(RTL8150_HW_CRC, &dev->flags); - set_registers(dev, RCR, 1, &rcr); - set_registers(dev, TCR, 1, &tcr); - set_registers(dev, CR, 1, &cr); - get_registers(dev, MSR, 1, &msr); - - return 0; -} - -static void disable_net_traffic(rtl8150_t * dev) -{ - u8 cr; - - get_registers(dev, CR, 1, &cr); - cr &= 0xf3; - set_registers(dev, CR, 1, &cr); -} - -static struct net_device_stats *rtl8150_netdev_stats(struct net_device *dev) -{ - return &((rtl8150_t *)netdev_priv(dev))->stats; -} - -static void rtl8150_tx_timeout(struct net_device *netdev) -{ - rtl8150_t *dev = netdev_priv(netdev); - warn("%s: Tx timeout.", netdev->name); - usb_unlink_urb(dev->tx_urb); - dev->stats.tx_errors++; -} - -static void rtl8150_set_multicast(struct net_device *netdev) -{ - rtl8150_t *dev = netdev_priv(netdev); - netif_stop_queue(netdev); - if (netdev->flags & IFF_PROMISC) { - dev->rx_creg |= cpu_to_le16(0x0001); - info("%s: promiscuous mode", netdev->name); - } else if (netdev->mc_count || - (netdev->flags & IFF_ALLMULTI)) { - dev->rx_creg &= cpu_to_le16(0xfffe); - dev->rx_creg |= cpu_to_le16(0x0002); - info("%s: allmulti set", netdev->name); - } else { - /* ~RX_MULTICAST, ~RX_PROMISCUOUS */ - dev->rx_creg &= cpu_to_le16(0x00fc); - } - async_set_registers(dev, RCR, 2); - netif_wake_queue(netdev); -} - -static int rtl8150_start_xmit(struct sk_buff *skb, struct net_device *netdev) -{ - rtl8150_t *dev = netdev_priv(netdev); - int count, res; - - netif_stop_queue(netdev); - count = (skb->len < 60) ? 60 : skb->len; - count = (count & 0x3f) ? count : count + 1; - dev->tx_skb = skb; - usb_fill_bulk_urb(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 2), - skb->data, count, write_bulk_callback, dev); - if ((res = usb_submit_urb(dev->tx_urb, GFP_ATOMIC))) { - /* Can we get/handle EPIPE here? */ - if (res == -ENODEV) - netif_device_detach(dev->netdev); - else { - warn("failed tx_urb %d\n", res); - dev->stats.tx_errors++; - netif_start_queue(netdev); - } - } else { - dev->stats.tx_packets++; - dev->stats.tx_bytes += skb->len; - netdev->trans_start = jiffies; - } - - return 0; -} - - -static void set_carrier(struct net_device *netdev) -{ - rtl8150_t *dev = netdev_priv(netdev); - short tmp; - - get_registers(dev, CSCR, 2, &tmp); - if (tmp & CSCR_LINK_STATUS) - netif_carrier_on(netdev); - else - netif_carrier_off(netdev); -} - -static int rtl8150_open(struct net_device *netdev) -{ - rtl8150_t *dev = netdev_priv(netdev); - int res; - - if (dev->rx_skb == NULL) - dev->rx_skb = pull_skb(dev); - if (!dev->rx_skb) - return -ENOMEM; - - set_registers(dev, IDR, 6, netdev->dev_addr); - - usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1), - dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev); - if ((res = usb_submit_urb(dev->rx_urb, GFP_KERNEL))) { - if (res == -ENODEV) - netif_device_detach(dev->netdev); - warn("%s: rx_urb submit failed: %d", __FUNCTION__, res); - return res; - } - usb_fill_int_urb(dev->intr_urb, dev->udev, usb_rcvintpipe(dev->udev, 3), - dev->intr_buff, INTBUFSIZE, intr_callback, - dev, dev->intr_interval); - if ((res = usb_submit_urb(dev->intr_urb, GFP_KERNEL))) { - if (res == -ENODEV) - netif_device_detach(dev->netdev); - warn("%s: intr_urb submit failed: %d", __FUNCTION__, res); - usb_kill_urb(dev->rx_urb); - return res; - } - enable_net_traffic(dev); - set_carrier(netdev); - netif_start_queue(netdev); - - return res; -} - -static int rtl8150_close(struct net_device *netdev) -{ - rtl8150_t *dev = netdev_priv(netdev); - int res = 0; - - netif_stop_queue(netdev); - if (!test_bit(RTL8150_UNPLUG, &dev->flags)) - disable_net_traffic(dev); - unlink_all_urbs(dev); - - return res; -} - -static void rtl8150_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info) -{ - rtl8150_t *dev = netdev_priv(netdev); - - strncpy(info->driver, driver_name, ETHTOOL_BUSINFO_LEN); - strncpy(info->version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN); - usb_make_path(dev->udev, info->bus_info, sizeof info->bus_info); -} - -static int rtl8150_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) -{ - rtl8150_t *dev = netdev_priv(netdev); - short lpa, bmcr; - - ecmd->supported = (SUPPORTED_10baseT_Half | - SUPPORTED_10baseT_Full | - SUPPORTED_100baseT_Half | - SUPPORTED_100baseT_Full | - SUPPORTED_Autoneg | - SUPPORTED_TP | SUPPORTED_MII); - ecmd->port = PORT_TP; - ecmd->transceiver = XCVR_INTERNAL; - ecmd->phy_address = dev->phy; - get_registers(dev, BMCR, 2, &bmcr); - get_registers(dev, ANLP, 2, &lpa); - if (bmcr & BMCR_ANENABLE) { - ecmd->autoneg = AUTONEG_ENABLE; - ecmd->speed = (lpa & (LPA_100HALF | LPA_100FULL)) ? - SPEED_100 : SPEED_10; - if (ecmd->speed == SPEED_100) - ecmd->duplex = (lpa & LPA_100FULL) ? - DUPLEX_FULL : DUPLEX_HALF; - else - ecmd->duplex = (lpa & LPA_10FULL) ? - DUPLEX_FULL : DUPLEX_HALF; - } else { - ecmd->autoneg = AUTONEG_DISABLE; - ecmd->speed = (bmcr & BMCR_SPEED100) ? - SPEED_100 : SPEED_10; - ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? - DUPLEX_FULL : DUPLEX_HALF; - } - return 0; -} - -static struct ethtool_ops ops = { - .get_drvinfo = rtl8150_get_drvinfo, - .get_settings = rtl8150_get_settings, - .get_link = ethtool_op_get_link -}; - -static int rtl8150_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) -{ - rtl8150_t *dev = netdev_priv(netdev); - u16 *data = (u16 *) & rq->ifr_ifru; - int res = 0; - - switch (cmd) { - case SIOCDEVPRIVATE: - data[0] = dev->phy; - case SIOCDEVPRIVATE + 1: - read_mii_word(dev, dev->phy, (data[1] & 0x1f), &data[3]); - break; - case SIOCDEVPRIVATE + 2: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - write_mii_word(dev, dev->phy, (data[1] & 0x1f), data[2]); - break; - default: - res = -EOPNOTSUPP; - } - - return res; -} - -static int rtl8150_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - rtl8150_t *dev; - struct net_device *netdev; - - netdev = alloc_etherdev(sizeof(rtl8150_t)); - if (!netdev) { - err("Out of memory"); - return -ENOMEM; - } - - dev = netdev_priv(netdev); - memset(dev, 0, sizeof(rtl8150_t)); - - dev->intr_buff = kmalloc(INTBUFSIZE, GFP_KERNEL); - if (!dev->intr_buff) { - free_netdev(netdev); - return -ENOMEM; - } - - tasklet_init(&dev->tl, rx_fixup, (unsigned long)dev); - spin_lock_init(&dev->rx_pool_lock); - - dev->udev = udev; - dev->netdev = netdev; - SET_MODULE_OWNER(netdev); - netdev->open = rtl8150_open; - netdev->stop = rtl8150_close; - netdev->do_ioctl = rtl8150_ioctl; - netdev->watchdog_timeo = RTL8150_TX_TIMEOUT; - netdev->tx_timeout = rtl8150_tx_timeout; - netdev->hard_start_xmit = rtl8150_start_xmit; - netdev->set_multicast_list = rtl8150_set_multicast; - netdev->set_mac_address = rtl8150_set_mac_address; - netdev->get_stats = rtl8150_netdev_stats; - netdev->mtu = RTL8150_MTU; - SET_ETHTOOL_OPS(netdev, &ops); - dev->intr_interval = 100; /* 100ms */ - - if (!alloc_all_urbs(dev)) { - err("out of memory"); - goto out; - } - if (!rtl8150_reset(dev)) { - err("couldn't reset the device"); - goto out1; - } - fill_skb_pool(dev); - set_ethernet_addr(dev); - - usb_set_intfdata(intf, dev); - SET_NETDEV_DEV(netdev, &intf->dev); - if (register_netdev(netdev) != 0) { - err("couldn't register the device"); - goto out2; - } - - info("%s: rtl8150 is detected", netdev->name); - - return 0; - -out2: - usb_set_intfdata(intf, NULL); - free_skb_pool(dev); -out1: - free_all_urbs(dev); -out: - kfree(dev->intr_buff); - free_netdev(netdev); - return -EIO; -} - -static void rtl8150_disconnect(struct usb_interface *intf) -{ - rtl8150_t *dev = usb_get_intfdata(intf); - - usb_set_intfdata(intf, NULL); - if (dev) { - set_bit(RTL8150_UNPLUG, &dev->flags); - tasklet_disable(&dev->tl); - tasklet_kill(&dev->tl); - unregister_netdev(dev->netdev); - unlink_all_urbs(dev); - free_all_urbs(dev); - free_skb_pool(dev); - if (dev->rx_skb) - dev_kfree_skb(dev->rx_skb); - kfree(dev->intr_buff); - free_netdev(dev->netdev); - } -} - -static int __init usb_rtl8150_init(void) -{ - info(DRIVER_DESC " " DRIVER_VERSION); - return usb_register(&rtl8150_driver); -} - -static void __exit usb_rtl8150_exit(void) -{ - usb_deregister(&rtl8150_driver); -} - -module_init(usb_rtl8150_init); -module_exit(usb_rtl8150_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c deleted file mode 100644 index f9cd42d058b0..000000000000 --- a/drivers/usb/net/usbnet.c +++ /dev/null @@ -1,1304 +0,0 @@ -/* - * USB Network driver infrastructure - * Copyright (C) 2000-2005 by David Brownell - * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com> - * - * 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 <linux/module.h> -#include <linux/init.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/ethtool.h> -#include <linux/workqueue.h> -#include <linux/mii.h> -#include <linux/usb.h> - -#include "usbnet.h" - -#define DRIVER_VERSION "22-Aug-2005" - - -/*-------------------------------------------------------------------------*/ - -/* - * 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) - -// 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 - -/*-------------------------------------------------------------------------*/ - -// randomly generated ethernet address -static u8 node_id [ETH_ALEN]; - -static const char driver_name [] = "usbnet"; - -/* 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 */ -int usbnet_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 (!usb_endpoint_dir_in(&e->desc)) - continue; - intr = 1; - /* FALLTHROUGH */ - case USB_ENDPOINT_XFER_BULK: - break; - default: - continue; - } - if (usb_endpoint_dir_in(&e->desc)) { - 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; -} -EXPORT_SYMBOL_GPL(usbnet_get_endpoints); - -static void intr_complete (struct urb *urb); - -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 { - usb_fill_int_urb(dev->interrupt, dev->udev, pipe, - buf, maxp, intr_complete, dev, period); - dev_dbg(&intf->dev, - "status ep%din, %d bytes period %d\n", - 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. - */ -void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb) -{ - int status; - - 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); -} -EXPORT_SYMBOL_GPL(usbnet_skb_return); - - -/*------------------------------------------------------------------------- - * - * Network Device Driver (peer link to "Host Device", from USB host) - * - *-------------------------------------------------------------------------*/ - -static int usbnet_change_mtu (struct net_device *net, int new_mtu) -{ - struct usbnet *dev = netdev_priv(net); - int ll_mtu = new_mtu + net->hard_header_len; - int old_hard_mtu = dev->hard_mtu; - int old_rx_urb_size = dev->rx_urb_size; - - if (new_mtu <= 0) - return -EINVAL; - // no second zero-length packet read wanted after mtu-sized packets - if ((ll_mtu % dev->maxpacket) == 0) - return -EDOM; - net->mtu = new_mtu; - - dev->hard_mtu = net->mtu + net->hard_header_len; - if (dev->rx_urb_size == old_hard_mtu) { - dev->rx_urb_size = dev->hard_mtu; - if (dev->rx_urb_size > old_rx_urb_size) - usbnet_unlink_rx_urbs(dev); - } - - return 0; -} - -/*-------------------------------------------------------------------------*/ - -static struct net_device_stats *usbnet_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. - */ -void usbnet_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); -} -EXPORT_SYMBOL_GPL(usbnet_defer_kevent); - -/*-------------------------------------------------------------------------*/ - -static void rx_complete (struct urb *urb); - -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; - - if ((skb = alloc_skb (size + NET_IP_ALIGN, flags)) == NULL) { - if (netif_msg_rx_err (dev)) - devdbg (dev, "no rx skb"); - usbnet_defer_kevent (dev, EVENT_RX_MEMORY); - usb_free_urb (urb); - return; - } - 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: - usbnet_defer_kevent (dev, EVENT_RX_HALT); - break; - case -ENOMEM: - usbnet_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)) - devdbg (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) - usbnet_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); - } -} - -/*-------------------------------------------------------------------------*/ - -static void rx_complete (struct urb *urb) -{ - struct sk_buff *skb = (struct sk_buff *) urb->context; - struct skb_data *entry = (struct skb_data *) skb->cb; - 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)) - devdbg (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 ETIMEOUT/EILSEQ - // storm, recovering as needed. - case -EPIPE: - dev->stats.rx_errors++; - usbnet_defer_kevent (dev, EVENT_RX_HALT); - // FALLTHROUGH - - // software-driven interface shutdown - case -ECONNRESET: // async unlink - case -ESHUTDOWN: // hardware gone - if (netif_msg_ifdown (dev)) - devdbg (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)) - devdbg (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)) - devdbg (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)) - devdbg (dev, "no read resubmitted"); -} - -static void intr_complete (struct urb *urb) -{ - 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); - return; - - /* NOTE: not throttling like RX/TX, since this endpoint - * already polls infrequently - */ - default: - devdbg (dev, "intr status %d", status); - 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); - for (skb = q->next; skb != (struct sk_buff *) q; skb = skbnext) { - struct skb_data *entry; - struct urb *urb; - int retval; - - entry = (struct skb_data *) skb->cb; - urb = entry->urb; - skbnext = skb->next; - - // 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 - -void usbnet_unlink_rx_urbs(struct usbnet *dev) -{ - if (netif_running(dev->net)) { - (void) unlink_urbs (dev, &dev->rxq); - tasklet_schedule(&dev->bh); - } -} -EXPORT_SYMBOL_GPL(usbnet_unlink_rx_urbs); - -/*-------------------------------------------------------------------------*/ - -// precondition: never called in_interrupt - -static int usbnet_stop (struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - int temp; - DECLARE_WAIT_QUEUE_HEAD_ONSTACK (unlink_wakeup); - DECLARE_WAITQUEUE (wait, current); - - netif_stop_queue (net); - - if (netif_msg_ifdown (dev)) - devinfo (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld", - dev->stats.rx_packets, dev->stats.tx_packets, - dev->stats.rx_errors, dev->stats.tx_errors - ); - - // 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 usbnet_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); -done: - return retval; -} - -/*-------------------------------------------------------------------------*/ - -/* ethtool methods; minidrivers may need to add some more, but - * they'll probably want to use this base set. - */ - -#if defined(CONFIG_MII) || defined(CONFIG_MII_MODULE) -#define HAVE_MII - -int usbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd) -{ - struct usbnet *dev = netdev_priv(net); - - if (!dev->mii.mdio_read) - return -EOPNOTSUPP; - - return mii_ethtool_gset(&dev->mii, cmd); -} -EXPORT_SYMBOL_GPL(usbnet_get_settings); - -int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd) -{ - struct usbnet *dev = netdev_priv(net); - int retval; - - if (!dev->mii.mdio_write) - return -EOPNOTSUPP; - - retval = mii_ethtool_sset(&dev->mii, cmd); - - /* link speed/duplex might have changed */ - if (dev->driver_info->link_reset) - dev->driver_info->link_reset(dev); - - return retval; - -} -EXPORT_SYMBOL_GPL(usbnet_set_settings); - -u32 usbnet_get_link (struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - - /* 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, say we're up (to avoid breaking scripts) */ - return 1; -} -EXPORT_SYMBOL_GPL(usbnet_get_link); - -int usbnet_nway_reset(struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - - if (!dev->mii.mdio_write) - return -EOPNOTSUPP; - - return mii_nway_restart(&dev->mii); -} -EXPORT_SYMBOL_GPL(usbnet_nway_reset); - -#endif /* HAVE_MII */ - -void usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info) -{ - struct usbnet *dev = netdev_priv(net); - - 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); -} -EXPORT_SYMBOL_GPL(usbnet_get_drvinfo); - -u32 usbnet_get_msglevel (struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - - return dev->msg_enable; -} -EXPORT_SYMBOL_GPL(usbnet_get_msglevel); - -void usbnet_set_msglevel (struct net_device *net, u32 level) -{ - struct usbnet *dev = netdev_priv(net); - - dev->msg_enable = level; -} -EXPORT_SYMBOL_GPL(usbnet_set_msglevel); - -/* drivers may override default ethtool_ops in their bind() routine */ -static struct ethtool_ops usbnet_ethtool_ops = { -#ifdef HAVE_MII - .get_settings = usbnet_get_settings, - .set_settings = usbnet_set_settings, - .get_link = usbnet_get_link, - .nway_reset = usbnet_nway_reset, -#endif - .get_drvinfo = usbnet_get_drvinfo, - .get_msglevel = usbnet_get_msglevel, - .set_msglevel = usbnet_set_msglevel, -}; - -/*-------------------------------------------------------------------------*/ - -/* 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. - */ -static void -kevent (struct work_struct *work) -{ - struct usbnet *dev = - container_of(work, struct usbnet, kevent); - int status; - - /* usb_clear_halt() needs a thread context */ - if (test_bit (EVENT_TX_HALT, &dev->flags)) { - 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)) { - 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; - - 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); - 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); -} - -/*-------------------------------------------------------------------------*/ - -static void tx_complete (struct urb *urb) -{ - struct sk_buff *skb = (struct sk_buff *) urb->context; - struct skb_data *entry = (struct skb_data *) skb->cb; - 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: - usbnet_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 usbnet_tx_timeout (struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - - unlink_urbs (dev, &dev->txq); - tasklet_schedule (&dev->bh); - - // FIXME: device recovery -- reset? -} - -/*-------------------------------------------------------------------------*/ - -static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - int length; - int retval = NET_XMIT_SUCCESS; - struct urb *urb = NULL; - struct skb_data *entry; - struct driver_info *info = dev->driver_info; - unsigned long flags; - - // 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. - * - * FIXME zero that byte, if it doesn't require a new skb. - */ - if ((length % dev->maxpacket) == 0) - urb->transfer_buffer_length++; - - spin_lock_irqsave (&dev->txq.lock, flags); - - switch ((retval = usb_submit_urb (urb, GFP_ATOMIC))) { - case -EPIPE: - netif_stop_queue (net); - usbnet_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: - retval = NET_XMIT_SUCCESS; - 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 retval; -} - - -/*-------------------------------------------------------------------------*/ - -// tasklet (work deferred from completions, in_irq) or timer - -static void usbnet_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) - 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 - -void usbnet_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); -} -EXPORT_SYMBOL_GPL(usbnet_disconnect); - - -/*-------------------------------------------------------------------------*/ - -// precondition: never called in_interrupt - -int -usbnet_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) { - dev_dbg (&udev->dev, "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->driver_info = info; - dev->driver_name = name; - dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV - | NETIF_MSG_PROBE | NETIF_MSG_LINK); - skb_queue_head_init (&dev->rxq); - skb_queue_head_init (&dev->txq); - skb_queue_head_init (&dev->done); - dev->bh.func = usbnet_bh; - dev->bh.data = (unsigned long) dev; - INIT_WORK (&dev->kevent, kevent); - dev->delay.function = usbnet_bh; - dev->delay.data = (unsigned long) dev; - init_timer (&dev->delay); - mutex_init (&dev->phy_mutex); - - SET_MODULE_OWNER (net); - dev->net = net; - strcpy (net->name, "usb%d"); - memcpy (net->dev_addr, node_id, sizeof node_id); - - /* 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_64BIT_MASK)) - net->features |= NETIF_F_HIGHDMA; -#endif - - net->change_mtu = usbnet_change_mtu; - net->get_stats = usbnet_get_stats; - net->hard_start_xmit = usbnet_start_xmit; - net->open = usbnet_open; - net->stop = usbnet_stop; - net->watchdog_timeo = TX_TIMEOUT_JIFFIES; - net->tx_timeout = usbnet_tx_timeout; - net->ethtool_ops = &usbnet_ethtool_ops; - - // allow device-specific bind/init procedures - // NOTE net->name still not usable ... - if (info->bind) { - status = info->bind (dev, udev); - if (status < 0) - goto out1; - - // heuristic: "usb%d" for links we know are two-host, - // else "eth%d" when there's reasonable doubt. userspace - // can rename the link if it knows better. - if ((dev->driver_info->flags & FLAG_ETHER) != 0 - && (net->dev_addr [0] & 0x02) == 0) - strcpy (net->name, "eth%d"); - - /* 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; - } else if (!info->in || !info->out) - status = usbnet_get_endpoints (dev, udev); - else { - dev->in = usb_rcvbulkpipe (xdev, info->in); - dev->out = usb_sndbulkpipe (xdev, info->out); - if (!(info->flags & FLAG_NO_SETINT)) - status = usb_set_interface (xdev, - interface->desc.bInterfaceNumber, - interface->desc.bAlternateSetting); - else - status = 0; - - } - if (status == 0 && dev->status) - 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) - goto out3; - if (netif_msg_probe (dev)) - devinfo (dev, "register '%s' at usb-%s-%s, %s, " - "%02x:%02x:%02x:%02x:%02x:%02x", - udev->dev.driver->name, - xdev->bus->bus_name, xdev->devpath, - dev->driver_info->description, - net->dev_addr [0], net->dev_addr [1], - net->dev_addr [2], net->dev_addr [3], - net->dev_addr [4], net->dev_addr [5]); - - // 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; -} -EXPORT_SYMBOL_GPL(usbnet_probe); - -/*-------------------------------------------------------------------------*/ - -/* FIXME these suspend/resume methods assume non-CDC style - * devices, with only one interface. - */ - -int usbnet_suspend (struct usb_interface *intf, pm_message_t message) -{ - struct usbnet *dev = usb_get_intfdata(intf); - - /* accelerate emptying of the rx and queues, to avoid - * having everything error out. - */ - netif_device_detach (dev->net); - (void) unlink_urbs (dev, &dev->rxq); - (void) unlink_urbs (dev, &dev->txq); - return 0; -} -EXPORT_SYMBOL_GPL(usbnet_suspend); - -int usbnet_resume (struct usb_interface *intf) -{ - struct usbnet *dev = usb_get_intfdata(intf); - - netif_device_attach (dev->net); - tasklet_schedule (&dev->bh); - return 0; -} -EXPORT_SYMBOL_GPL(usbnet_resume); - - -/*-------------------------------------------------------------------------*/ - -static int __init usbnet_init(void) -{ - /* compiler should optimize this out */ - BUILD_BUG_ON (sizeof (((struct sk_buff *)0)->cb) - < sizeof (struct skb_data)); - - random_ether_addr(node_id); - return 0; -} -module_init(usbnet_init); - -static void __exit usbnet_exit(void) -{ -} -module_exit(usbnet_exit); - -MODULE_AUTHOR("David Brownell"); -MODULE_DESCRIPTION("USB network driver framework"); -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/net/usbnet.h b/drivers/usb/net/usbnet.h deleted file mode 100644 index 82db5a8e528e..000000000000 --- a/drivers/usb/net/usbnet.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - * USB Networking Link Interface - * - * Copyright (C) 2000-2005 by David Brownell <dbrownell@users.sourceforge.net> - * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com> - * - * 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 __USBNET_H -#define __USBNET_H - - -/* interface from usbnet core to each USB networking link we handle */ -struct usbnet { - /* housekeeping */ - struct usb_device *udev; - struct driver_info *driver_info; - const char *driver_name; - wait_queue_head_t *wait; - struct mutex phy_mutex; - - /* 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 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 -}; - -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 */ - - /* 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, gfp_t flags); - - /* for new devices, use the descriptor-reading code instead */ - int in; /* rx endpoint */ - int out; /* tx endpoint */ - - unsigned long data; /* Misc driver specific data */ -}; - -/* Minidrivers are just drivers using the "usbnet" core as a powerful - * network-specific subroutine library ... that happens to do pretty - * much everything except custom framing and chip-specific stuff. - */ -extern int usbnet_probe(struct usb_interface *, const struct usb_device_id *); -extern int usbnet_suspend (struct usb_interface *, pm_message_t ); -extern int usbnet_resume (struct usb_interface *); -extern void usbnet_disconnect(struct usb_interface *); - - -/* 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; -}; - -extern int usbnet_generic_cdc_bind (struct usbnet *, struct usb_interface *); -extern void usbnet_cdc_unbind (struct usbnet *, struct usb_interface *); - -/* 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; -}; - - -extern int usbnet_get_endpoints(struct usbnet *, struct usb_interface *); -extern void usbnet_defer_kevent (struct usbnet *, int); -extern void usbnet_skb_return (struct usbnet *, struct sk_buff *); -extern void usbnet_unlink_rx_urbs(struct usbnet *); - -extern int usbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd); -extern int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd); -extern u32 usbnet_get_link (struct net_device *net); -extern u32 usbnet_get_msglevel (struct net_device *); -extern void usbnet_set_msglevel (struct net_device *, u32); -extern void usbnet_get_drvinfo (struct net_device *, struct ethtool_drvinfo *); -extern int usbnet_nway_reset(struct net_device *net); - -/* 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(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); \ - - -#endif /* __USBNET_H */ diff --git a/drivers/usb/net/zaurus.c b/drivers/usb/net/zaurus.c deleted file mode 100644 index 9f98e8ce487a..000000000000 --- a/drivers/usb/net/zaurus.c +++ /dev/null @@ -1,385 +0,0 @@ -/* - * Copyright (C) 2002 Pavel Machek <pavel@ucw.cz> - * Copyright (C) 2002-2005 by David Brownell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -// #define DEBUG // error path messages, extra info -// #define VERBOSE // more; success messages - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/netdevice.h> -#include <linux/ethtool.h> -#include <linux/workqueue.h> -#include <linux/mii.h> -#include <linux/crc32.h> -#include <linux/usb.h> -#include <linux/usb/cdc.h> - -#include "usbnet.h" - - -/* - * All known Zaurii lie about their standards conformance. At least - * the earliest SA-1100 models lie by saying they support CDC Ethernet. - * Some later models (especially PXA-25x and PXA-27x based ones) lie - * and say they support CDC MDLM (for access to cell phone modems). - * - * There are non-Zaurus products that use these same protocols too. - * - * The annoying thing is that at the same time Sharp was developing - * that annoying standards-breaking software, the Linux community had - * a simple "CDC Subset" working reliably on the same SA-1100 hardware. - * That is, the same functionality but not violating standards. - * - * The CDC Ethernet nonconformance points are troublesome to hosts - * with a true CDC Ethernet implementation: - * - Framing appends a CRC, which the spec says drivers "must not" do; - * - Transfers data in altsetting zero, instead of altsetting 1; - * - All these peripherals use the same ethernet address. - * - * The CDC MDLM nonconformance is less immediately troublesome, since all - * MDLM implementations are quasi-proprietary anyway. - */ - -static struct sk_buff * -zaurus_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) -{ - int padlen; - struct sk_buff *skb2; - - padlen = 2; - if (!skb_cloned(skb)) { - int tailroom = skb_tailroom(skb); - if ((padlen + 4) <= tailroom) - goto done; - } - skb2 = skb_copy_expand(skb, 0, 4 + padlen, flags); - dev_kfree_skb_any(skb); - skb = skb2; - if (skb) { - u32 fcs; -done: - fcs = crc32_le(~0, skb->data, skb->len); - fcs = ~fcs; - - *skb_put (skb, 1) = fcs & 0xff; - *skb_put (skb, 1) = (fcs>> 8) & 0xff; - *skb_put (skb, 1) = (fcs>>16) & 0xff; - *skb_put (skb, 1) = (fcs>>24) & 0xff; - } - return skb; -} - -static int zaurus_bind(struct usbnet *dev, struct usb_interface *intf) -{ - /* Belcarra's funky framing has other options; mostly - * TRAILERS (!) with 4 bytes CRC, and maybe 2 pad bytes. - */ - dev->net->hard_header_len += 6; - dev->rx_urb_size = dev->net->hard_header_len + dev->net->mtu; - return usbnet_generic_cdc_bind(dev, intf); -} - -/* PDA style devices are always connected if present */ -static int always_connected (struct usbnet *dev) -{ - return 0; -} - -static const struct driver_info zaurus_sl5x00_info = { - .description = "Sharp Zaurus SL-5x00", - .flags = FLAG_FRAMING_Z, - .check_connect = always_connected, - .bind = zaurus_bind, - .unbind = usbnet_cdc_unbind, - .tx_fixup = zaurus_tx_fixup, -}; -#define ZAURUS_STRONGARM_INFO ((unsigned long)&zaurus_sl5x00_info) - -static const struct driver_info zaurus_pxa_info = { - .description = "Sharp Zaurus, PXA-2xx based", - .flags = FLAG_FRAMING_Z, - .check_connect = always_connected, - .bind = zaurus_bind, - .unbind = usbnet_cdc_unbind, - .tx_fixup = zaurus_tx_fixup, -}; -#define ZAURUS_PXA_INFO ((unsigned long)&zaurus_pxa_info) - -static const struct driver_info olympus_mxl_info = { - .description = "Olympus R1000", - .flags = FLAG_FRAMING_Z, - .check_connect = always_connected, - .bind = zaurus_bind, - .unbind = usbnet_cdc_unbind, - .tx_fixup = zaurus_tx_fixup, -}; -#define OLYMPUS_MXL_INFO ((unsigned long)&olympus_mxl_info) - - -/* Some more recent products using Lineo/Belcarra code will wrongly claim - * CDC MDLM conformance. They aren't conformant: data endpoints live - * in the control interface, there's no data interface, and it's not used - * to talk to a cell phone radio. But at least we can detect these two - * pseudo-classes, rather than growing this product list with entries for - * each new nonconformant product (sigh). - */ -static const u8 safe_guid[16] = { - 0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6, - 0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f, -}; -static const u8 blan_guid[16] = { - 0x74, 0xf0, 0x3d, 0xbd, 0x1e, 0xc1, 0x44, 0x70, - 0xa3, 0x67, 0x71, 0x34, 0xc9, 0xf5, 0x54, 0x37, -}; - -static int blan_mdlm_bind(struct usbnet *dev, struct usb_interface *intf) -{ - u8 *buf = intf->cur_altsetting->extra; - int len = intf->cur_altsetting->extralen; - struct usb_cdc_mdlm_desc *desc = NULL; - struct usb_cdc_mdlm_detail_desc *detail = NULL; - - while (len > 3) { - if (buf [1] != USB_DT_CS_INTERFACE) - goto next_desc; - - /* use bDescriptorSubType, and just verify that we get a - * "BLAN" (or "SAFE") descriptor. - */ - switch (buf [2]) { - case USB_CDC_MDLM_TYPE: - if (desc) { - dev_dbg(&intf->dev, "extra MDLM\n"); - goto bad_desc; - } - desc = (void *) buf; - if (desc->bLength != sizeof *desc) { - dev_dbg(&intf->dev, "MDLM len %u\n", - desc->bLength); - goto bad_desc; - } - /* expect bcdVersion 1.0, ignore */ - if (memcmp(&desc->bGUID, blan_guid, 16) - && memcmp(&desc->bGUID, safe_guid, 16) ) { - /* hey, this one might _really_ be MDLM! */ - dev_dbg(&intf->dev, "MDLM guid\n"); - goto bad_desc; - } - break; - case USB_CDC_MDLM_DETAIL_TYPE: - if (detail) { - dev_dbg(&intf->dev, "extra MDLM detail\n"); - goto bad_desc; - } - detail = (void *) buf; - switch (detail->bGuidDescriptorType) { - case 0: /* "SAFE" */ - if (detail->bLength != (sizeof *detail + 2)) - goto bad_detail; - break; - case 1: /* "BLAN" */ - if (detail->bLength != (sizeof *detail + 3)) - goto bad_detail; - break; - default: - goto bad_detail; - } - - /* assuming we either noticed BLAN already, or will - * find it soon, there are some data bytes here: - * - bmNetworkCapabilities (unused) - * - bmDataCapabilities (bits, see below) - * - bPad (ignored, for PADAFTER -- BLAN-only) - * bits are: - * - 0x01 -- Zaurus framing (add CRC) - * - 0x02 -- PADBEFORE (CRC includes some padding) - * - 0x04 -- PADAFTER (some padding after CRC) - * - 0x08 -- "fermat" packet mangling (for hw bugs) - * the PADBEFORE appears not to matter; we interop - * with devices that use it and those that don't. - */ - if ((detail->bDetailData[1] & ~0x02) != 0x01) { - /* bmDataCapabilities == 0 would be fine too, - * but framing is minidriver-coupled for now. - */ -bad_detail: - dev_dbg(&intf->dev, - "bad MDLM detail, %d %d %d\n", - detail->bLength, - detail->bDetailData[0], - detail->bDetailData[2]); - goto bad_desc; - } - - /* same extra framing as for non-BLAN mode */ - dev->net->hard_header_len += 6; - dev->rx_urb_size = dev->net->hard_header_len - + dev->net->mtu; - break; - } -next_desc: - len -= buf [0]; /* bLength */ - buf += buf [0]; - } - - if (!desc || !detail) { - dev_dbg(&intf->dev, "missing cdc mdlm %s%sdescriptor\n", - desc ? "" : "func ", - detail ? "" : "detail "); - goto bad_desc; - } - - /* There's probably a CDC Ethernet descriptor there, but we can't - * rely on the Ethernet address it provides since not all vendors - * bother to make it unique. Likewise there's no point in tracking - * of the CDC event notifications. - */ - return usbnet_get_endpoints(dev, intf); - -bad_desc: - dev_info(&dev->udev->dev, "unsupported MDLM descriptors\n"); - return -ENODEV; -} - -static const struct driver_info bogus_mdlm_info = { - .description = "pseudo-MDLM (BLAN) device", - .flags = FLAG_FRAMING_Z, - .check_connect = always_connected, - .tx_fixup = zaurus_tx_fixup, - .bind = blan_mdlm_bind, -}; - -static const struct usb_device_id products [] = { -#define ZAURUS_MASTER_INTERFACE \ - .bInterfaceClass = USB_CLASS_COMM, \ - .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, \ - .bInterfaceProtocol = USB_CDC_PROTO_NONE - -/* SA-1100 based Sharp Zaurus ("collie"), or compatible. */ -{ - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x04DD, - .idProduct = 0x8004, - ZAURUS_MASTER_INTERFACE, - .driver_info = ZAURUS_STRONGARM_INFO, -}, - -/* PXA-2xx based models are also lying-about-cdc. If you add any - * more devices that claim to be CDC Ethernet, make sure they get - * added to the blacklist in cdc_ether too. - * - * NOTE: OpenZaurus versions with 2.6 kernels won't use these entries, - * unlike the older ones with 2.4 "embedix" kernels. - */ -{ - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x04DD, - .idProduct = 0x8005, /* A-300 */ - ZAURUS_MASTER_INTERFACE, - .driver_info = ZAURUS_PXA_INFO, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x04DD, - .idProduct = 0x8006, /* B-500/SL-5600 */ - ZAURUS_MASTER_INTERFACE, - .driver_info = ZAURUS_PXA_INFO, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x04DD, - .idProduct = 0x8007, /* C-700 */ - ZAURUS_MASTER_INTERFACE, - .driver_info = ZAURUS_PXA_INFO, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x04DD, - .idProduct = 0x9031, /* C-750 C-760 */ - ZAURUS_MASTER_INTERFACE, - .driver_info = ZAURUS_PXA_INFO, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x04DD, - .idProduct = 0x9032, /* SL-6000 */ - ZAURUS_MASTER_INTERFACE, - .driver_info = ZAURUS_PXA_INFO, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x04DD, - /* reported with some C860 units */ - .idProduct = 0x9050, /* C-860 */ - ZAURUS_MASTER_INTERFACE, - .driver_info = ZAURUS_PXA_INFO, -}, - - -/* At least some of the newest PXA units have very different lies about - * their standards support: they claim to be cell phones offering - * direct access to their radios! (No, they don't conform to CDC MDLM.) - */ -{ - USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MDLM, - USB_CDC_PROTO_NONE), - .driver_info = (unsigned long) &bogus_mdlm_info, -}, - -/* Olympus has some models with a Zaurus-compatible option. - * R-1000 uses a FreeScale i.MXL cpu (ARMv4T) - */ -{ - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x07B4, - .idProduct = 0x0F02, /* R-1000 */ - ZAURUS_MASTER_INTERFACE, - .driver_info = OLYMPUS_MXL_INFO, -}, - { }, // END -}; -MODULE_DEVICE_TABLE(usb, products); - -static struct usb_driver zaurus_driver = { - .name = "zaurus", - .id_table = products, - .probe = usbnet_probe, - .disconnect = usbnet_disconnect, - .suspend = usbnet_suspend, - .resume = usbnet_resume, -}; - -static int __init zaurus_init(void) -{ - return usb_register(&zaurus_driver); -} -module_init(zaurus_init); - -static void __exit zaurus_exit(void) -{ - usb_deregister(&zaurus_driver); -} -module_exit(zaurus_exit); - -MODULE_AUTHOR("Pavel Machek, David Brownell"); -MODULE_DESCRIPTION("Sharp Zaurus PDA, and compatible products"); -MODULE_LICENSE("GPL"); |