diff options
Diffstat (limited to 'ANDROID_3.4.5/drivers/net/usb')
36 files changed, 0 insertions, 32197 deletions
diff --git a/ANDROID_3.4.5/drivers/net/usb/Kconfig b/ANDROID_3.4.5/drivers/net/usb/Kconfig deleted file mode 100644 index 833e32f8..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/Kconfig +++ /dev/null @@ -1,487 +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 NET_CORE - 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/net/usb/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 NET_CORE - 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 - tristate "Multi-purpose USB Networking Framework" - select NET_CORE - select MII - ---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 - select CRC32 - 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: - - * Dell Wireless 5530 HSPA - * Ericsson PipeRider (all variants) - * Ericsson Mobile Broadband Module (all variants) - * Motorola (DM100 and SB4100) - * Broadcom Cable Modem (reference design) - * Toshiba (PCX1100U and F3507g/F3607gw) - * ... - - 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_CDC_EEM - tristate "CDC EEM support" - depends on USB_USBNET && EXPERIMENTAL - help - This option supports devices conforming to the Communication Device - Class (CDC) Ethernet Emulation Model, a specification that's easy to - implement in device firmware. The CDC EEM specifications are available - from <http://www.usb.org/>. - - 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_CDC_NCM - tristate "CDC NCM support" - depends on USB_USBNET - default y - help - This driver provides support for CDC NCM (Network Control Model - Device USB Class Specification). The CDC NCM specification is - available from <http://www.usb.org/>. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module. - - This driver should work with at least the following devices: - * ST-Ericsson M700 LTE FDD/TDD Mobile Broadband Modem (ref. design) - * ST-Ericsson M5730 HSPA+ Mobile Broadband Modem (reference design) - * ST-Ericsson M570 HSPA+ Mobile Broadband Modem (reference design) - * ST-Ericsson M343 HSPA Mobile Broadband Modem (reference design) - * Ericsson F5521gw Mobile Broadband Module - -config USB_NET_DM9601 - tristate "Davicom DM9601 based USB 1.1 10/100 ethernet devices" - depends on USB_USBNET - select CRC32 - help - This option adds support for Davicom DM9601 based USB 1.1 - 10/100 Ethernet adapters. - -config USB_NET_SMSC75XX - tristate "SMSC LAN75XX based USB 2.0 gigabit ethernet devices" - depends on USB_USBNET - select CRC32 - help - This option adds support for SMSC LAN95XX based USB 2.0 - Gigabit Ethernet adapters. - -config USB_NET_SMSC95XX - tristate "SMSC LAN95XX based USB 2.0 10/100 ethernet devices" - depends on USB_USBNET - select CRC32 - help - This option adds support for SMSC LAN95XX based USB 2.0 - 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/25A1 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 - 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". - -config USB_NET_CX82310_ETH - tristate "Conexant CX82310 USB ethernet port" - depends on USB_USBNET - help - Choose this option if you're using a Conexant CX82310-based ADSL - router with USB ethernet port. This driver is for routers only, - it will not work with ADSL modems (use cxacru driver instead). - -config USB_NET_KALMIA - tristate "Samsung Kalmia based LTE USB modem" - depends on USB_USBNET - help - Choose this option if you have a Samsung Kalmia based USB modem - as Samsung GT-B3730. - - To compile this driver as a module, choose M here: the - module will be called kalmia. - -config USB_NET_QMI_WWAN - tristate "QMI WWAN driver for Qualcomm MSM based 3G and LTE modems" - depends on USB_USBNET - select USB_WDM - help - Support WWAN LTE/3G devices based on Qualcomm Mobile Data Modem - (MDM) chipsets. Examples of such devices are - * Huawei E392/E398 - - This driver will only drive the ethernet part of the chips. - The devices require additional configuration to be usable. - Multiple management interfaces with linux drivers are - available: - - * option: AT commands on /dev/ttyUSBx - * cdc-wdm: Qualcomm MSM Interface (QMI) protocol on /dev/cdc-wdmx - - A modem manager with support for QMI is recommended. - - To compile this driver as a module, choose M here: the - module will be called qmi_wwan. - -config USB_HSO - tristate "Option USB High Speed Mobile Devices" - depends on USB && RFKILL - default n - help - Choose this option if you have an Option HSDPA/HSUPA card. - These cards support downlink speeds of 7.2Mbps or greater. - - To compile this driver as a module, choose M here: the - module will be called hso. - -config USB_NET_INT51X1 - tristate "Intellon PLC based usb adapter" - depends on USB_USBNET - help - Choose this option if you're using a 14Mb USB-based PLC - (Powerline Communications) solution with an Intellon - INT51x1/INT5200 chip, like the "devolo dLan duo". - -config USB_CDC_PHONET - tristate "CDC Phonet support" - depends on PHONET - help - Choose this option to support the Phonet interface to a Nokia - cellular modem, as found on most Nokia handsets with the - "PC suite" USB profile. - -config USB_IPHETH - tristate "Apple iPhone USB Ethernet driver" - default n - ---help--- - Module used to share Internet connection (tethering) from your - iPhone (Original, 3G and 3GS) to your system. - Note that you need userspace libraries and programs that are needed - to pair your device with your system and that understand the iPhone - protocol. - - For more information: http://giagio.com/wiki/moin.cgi/iPhoneEthernetDriver - -config USB_SIERRA_NET - tristate "USB-to-WWAN Driver for Sierra Wireless modems" - depends on USB_USBNET - help - Choose this option if you have a Sierra Wireless USB-to-WWAN device. - - To compile this driver as a module, choose M here: the - module will be called sierra_net. - -config USB_VL600 - tristate "LG VL600 modem dongle" - depends on USB_NET_CDCETHER - select USB_ACM - help - Select this if you want to use an LG Electronics 4G/LTE usb modem - called VL600. This driver only handles the ethernet - interface exposed by the modem firmware. To establish a connection - you will first need a userspace program that sends the right - command to the modem through its CDC ACM port, and most - likely also a DHCP client. See this thread about using the - 4G modem from Verizon: - - http://ubuntuforums.org/showpost.php?p=10589647&postcount=17 - - -endmenu diff --git a/ANDROID_3.4.5/drivers/net/usb/Makefile b/ANDROID_3.4.5/drivers/net/usb/Makefile deleted file mode 100644 index 60eb76c4..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/Makefile +++ /dev/null @@ -1,36 +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_HSO) += hso.o -obj-$(CONFIG_USB_NET_AX8817X) += asix.o -obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o -obj-$(CONFIG_USB_NET_CDC_EEM) += cdc_eem.o -obj-$(CONFIG_USB_NET_DM9601) += dm9601.o -obj-$(CONFIG_USB_NET_SMSC75XX) += smsc75xx.o -obj-$(CONFIG_USB_NET_SMSC95XX) += smsc95xx.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 -obj-$(CONFIG_USB_NET_INT51X1) += int51x1.o -obj-$(CONFIG_USB_CDC_PHONET) += cdc-phonet.o -obj-$(CONFIG_USB_NET_KALMIA) += kalmia.o -obj-$(CONFIG_USB_IPHETH) += ipheth.o -obj-$(CONFIG_USB_SIERRA_NET) += sierra_net.o -obj-$(CONFIG_USB_NET_CX82310_ETH) += cx82310_eth.o -obj-$(CONFIG_USB_NET_CDC_NCM) += cdc_ncm.o -obj-$(CONFIG_USB_VL600) += lg-vl600.o -obj-$(CONFIG_USB_NET_QMI_WWAN) += qmi_wwan.o -obj-m += r8152.o -obj-y+=ch9x00.o - - diff --git a/ANDROID_3.4.5/drivers/net/usb/asix.c b/ANDROID_3.4.5/drivers/net/usb/asix.c deleted file mode 100644 index 0dd2aa84..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/asix.c +++ /dev/null @@ -1,1665 +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 <linux/usb/usbnet.h> -#include <linux/slab.h> -#include <linux/if_vlan.h> - -#define DRIVER_VERSION "22-Dec-2011" -#define 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_NODE_ID 0x14 -#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 - -#define PHY_MODE_RTL8211CL 0x000C - -/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ -struct asix_data { - u8 multi_filter[AX_MCAST_FILTER_SIZE]; - u8 mac_addr[ETH_ALEN]; - u8 phymode; - u8 ledmode; - u8 eeprom_len; -}; - -struct ax88172_int_data { - __le16 res1; - u8 link; - __le16 res2; - u8 status; - __le16 res3; -} __packed; - -static int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, - u16 size, void *data) -{ - void *buf; - int err = -ENOMEM; - - netdev_dbg(dev->net, "asix_read_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n", - cmd, value, index, size); - - buf = kmalloc(size, GFP_KERNEL); - if (!buf) - goto out; - - err = usb_control_msg( - dev->udev, - usb_rcvctrlpipe(dev->udev, 0), - cmd, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, - index, - buf, - size, - USB_CTRL_GET_TIMEOUT); - if (err == size) - memcpy(data, buf, size); - else if (err >= 0) - err = -EINVAL; - kfree(buf); - -out: - return err; -} - -static int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, - u16 size, void *data) -{ - void *buf = NULL; - int err = -ENOMEM; - - netdev_dbg(dev->net, "asix_write_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n", - cmd, value, index, size); - - if (data) { - buf = kmemdup(data, size, GFP_KERNEL); - if (!buf) - goto out; - } - - err = usb_control_msg( - dev->udev, - usb_sndctrlpipe(dev->udev, 0), - cmd, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, - index, - buf, - size, - USB_CTRL_SET_TIMEOUT); - kfree(buf); - -out: - return err; -} - -static void asix_async_cmd_callback(struct urb *urb) -{ - struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; - int status = urb->status; - - if (status < 0) - printk(KERN_DEBUG "asix_async_cmd_callback() failed with %d", - 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; - - netdev_dbg(dev->net, "asix_write_cmd_async() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n", - cmd, value, index, size); - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) { - netdev_err(dev->net, "Error allocating URB in write_cmd_async!\n"); - return; - } - - req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); - if (!req) { - netdev_err(dev->net, "Failed to allocate memory for control request\n"); - 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); - - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status < 0) { - netdev_err(dev->net, "Error submitting the control message: status=%d\n", - status); - kfree(req); - usb_free_urb(urb); - } -} - -static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb) -{ - int offset = 0; - - while (offset + sizeof(u32) < skb->len) { - struct sk_buff *ax_skb; - u16 size; - u32 header = get_unaligned_le32(skb->data + offset); - - offset += sizeof(u32); - - /* get the packet length */ - size = (u16) (header & 0x7ff); - if (size != ((~header >> 16) & 0x07ff)) { - netdev_err(dev->net, "asix_rx_fixup() Bad Header Length\n"); - return 0; - } - - if ((size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) || - (size + offset > skb->len)) { - netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n", - size); - return 0; - } - ax_skb = netdev_alloc_skb_ip_align(dev->net, size); - if (!ax_skb) - return 0; - - skb_put(ax_skb, size); - memcpy(ax_skb->data, skb->data + offset, size); - usbnet_skb_return(dev, ax_skb); - - offset += (size + 1) & 0xfffe; - } - - if (skb->len != offset) { - netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d\n", - 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) & (dev->maxpacket - 1)) ? 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 (padlen) { - 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); - netdev_dbg(dev->net, "Link Status is: %d\n", 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) - netdev_err(dev->net, "Failed to enable software MII access\n"); - 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) - netdev_err(dev->net, "Failed to enable hardware MII access\n"); - return ret; -} - -static inline int asix_get_phy_addr(struct usbnet *dev) -{ - u8 buf[2]; - int ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf); - - netdev_dbg(dev->net, "asix_get_phy_addr()\n"); - - if (ret < 0) { - netdev_err(dev->net, "Error reading PHYID register: %02x\n", ret); - goto out; - } - netdev_dbg(dev->net, "asix_get_phy_addr() returning 0x%04x\n", - *((__le16 *)buf)); - ret = buf[1]; - -out: - 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) - netdev_err(dev->net, "Failed to send software reset: %02x\n", ret); - - return ret; -} - -static u16 asix_read_rx_ctl(struct usbnet *dev) -{ - __le16 v; - int ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL, 0, 0, 2, &v); - - if (ret < 0) { - netdev_err(dev->net, "Error reading RX_CTL register: %02x\n", ret); - goto out; - } - ret = le16_to_cpu(v); -out: - return ret; -} - -static int asix_write_rx_ctl(struct usbnet *dev, u16 mode) -{ - int ret; - - netdev_dbg(dev->net, "asix_write_rx_ctl() - mode = 0x%04x\n", mode); - ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL); - if (ret < 0) - netdev_err(dev->net, "Failed to write RX_CTL mode to 0x%04x: %02x\n", - mode, ret); - - return ret; -} - -static u16 asix_read_medium_status(struct usbnet *dev) -{ - __le16 v; - int ret = asix_read_cmd(dev, AX_CMD_READ_MEDIUM_STATUS, 0, 0, 2, &v); - - if (ret < 0) { - netdev_err(dev->net, "Error reading Medium Status register: %02x\n", - ret); - return ret; /* TODO: callers not checking for error ret */ - } - - return le16_to_cpu(v); - -} - -static int asix_write_medium_mode(struct usbnet *dev, u16 mode) -{ - int ret; - - netdev_dbg(dev->net, "asix_write_medium_mode() - mode = 0x%04x\n", mode); - ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); - if (ret < 0) - netdev_err(dev->net, "Failed to write Medium Mode mode to 0x%04x: %02x\n", - mode, ret); - - return ret; -} - -static int asix_write_gpio(struct usbnet *dev, u16 value, int sleep) -{ - int ret; - - netdev_dbg(dev->net, "asix_write_gpio() - value = 0x%04x\n", value); - ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL); - if (ret < 0) - netdev_err(dev->net, "Failed to write GPIO value 0x%04x: %02x\n", - 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 || - netdev_mc_count(net) > AX_MAX_MCAST) { - rx_ctl |= AX_RX_CTL_AMALL; - } else if (netdev_mc_empty(net)) { - /* 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 netdev_hw_addr *ha; - u32 crc_bits; - - memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); - - /* Build the multicast hash filter. */ - netdev_for_each_mc_addr(ha, net) { - crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; - data->multi_filter[crc_bits >> 3] |= - 1 << (crc_bits & 7); - } - - 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); - __le16 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, &res); - asix_set_hw_mii(dev); - mutex_unlock(&dev->phy_mutex); - - netdev_dbg(dev->net, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n", - phy_id, loc, le16_to_cpu(res)); - - return le16_to_cpu(res); -} - -static void -asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) -{ - struct usbnet *dev = netdev_priv(netdev); - __le16 res = cpu_to_le16(val); - - netdev_dbg(dev->net, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n", - 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, &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; - int i; - - /* Poll for the rare case the FW or phy isn't ready yet. */ - for (i = 0; i < 100; i++) { - phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID1); - if (phy_reg != 0 && phy_reg != 0xFFFF) - break; - mdelay(1); - } - - if (phy_reg <= 0 || phy_reg == 0xFFFF) - 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_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; - - if (wolinfo->wolopts & WAKE_PHY) - opt |= AX_MONITOR_LINK; - if (wolinfo->wolopts & WAKE_MAGIC) - opt |= AX_MONITOR_MAGIC; - - if (asix_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE, - opt, 0, 0, NULL) < 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); - __le16 *ebuf = (__le16 *)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); -} - -static int asix_set_mac_address(struct net_device *net, void *p) -{ - struct usbnet *dev = netdev_priv(net); - struct asix_data *data = (struct asix_data *)&dev->data; - struct sockaddr *addr = p; - - if (netif_running(net)) - return -EBUSY; - if (!is_valid_ether_addr(addr->sa_data)) - return -EADDRNOTAVAIL; - - memcpy(net->dev_addr, addr->sa_data, ETH_ALEN); - - /* We use the 20 byte dev->data - * for our 6 byte mac buffer - * to avoid allocating memory that - * is tricky to free later */ - memcpy(data->mac_addr, addr->sa_data, ETH_ALEN); - asix_write_cmd_async(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, - data->mac_addr); - - return 0; -} - -/* 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 const 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 || - netdev_mc_count(net) > AX_MAX_MCAST) { - rx_ctl |= 0x02; - } else if (netdev_mc_empty(net)) { - /* 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 netdev_hw_addr *ha; - u32 crc_bits; - - memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); - - /* Build the multicast hash filter. */ - netdev_for_each_mc_addr(ha, net) { - crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; - data->multi_filter[crc_bits >> 3] |= - 1 << (crc_bits & 7); - } - - 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 = { .cmd = ETHTOOL_GSET }; - - 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; - - netdev_dbg(dev->net, "ax88172_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", - ethtool_cmd_speed(&ecmd), ecmd.duplex, mode); - - asix_write_medium_mode(dev, mode); - - return 0; -} - -static const struct net_device_ops ax88172_netdev_ops = { - .ndo_open = usbnet_open, - .ndo_stop = usbnet_stop, - .ndo_start_xmit = usbnet_start_xmit, - .ndo_tx_timeout = usbnet_tx_timeout, - .ndo_change_mtu = usbnet_change_mtu, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, - .ndo_do_ioctl = asix_ioctl, - .ndo_set_rx_mode = ax88172_set_multicast, -}; - -static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf) -{ - int ret = 0; - u8 buf[ETH_ALEN]; - 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); - - /* Toggle the GPIOs in a manufacturer/model specific way */ - for (i = 2; i >= 0; i--) { - ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, - (gpio_bits >> (i * 8)) & 0xff, 0, 0, NULL); - if (ret < 0) - goto out; - msleep(5); - } - - ret = asix_write_rx_ctl(dev, 0x80); - if (ret < 0) - goto out; - - /* Get the MAC address */ - ret = asix_read_cmd(dev, AX88172_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf); - if (ret < 0) { - dbg("read AX_CMD_READ_NODE_ID failed: %d", ret); - goto out; - } - 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->netdev_ops = &ax88172_netdev_ops; - 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; - -out: - return ret; -} - -static const 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 = { .cmd = ETHTOOL_GSET }; - - mii_check_media(&dev->mii, 1, 1); - mii_ethtool_gset(&dev->mii, &ecmd); - mode = AX88772_MEDIUM_DEFAULT; - - if (ethtool_cmd_speed(&ecmd) != SPEED_100) - mode &= ~AX_MEDIUM_PS; - - if (ecmd.duplex != DUPLEX_FULL) - mode &= ~AX_MEDIUM_FD; - - netdev_dbg(dev->net, "ax88772_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", - ethtool_cmd_speed(&ecmd), ecmd.duplex, mode); - - asix_write_medium_mode(dev, mode); - - return 0; -} - -static int ax88772_reset(struct usbnet *dev) -{ - struct asix_data *data = (struct asix_data *)&dev->data; - int ret, embd_phy; - u16 rx_ctl; - - ret = asix_write_gpio(dev, - AX_GPIO_RSE | AX_GPIO_GPO_2 | AX_GPIO_GPO2EN, 5); - if (ret < 0) - goto out; - - embd_phy = ((asix_get_phy_addr(dev) & 0x1f) == 0x10 ? 1 : 0); - - ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL); - if (ret < 0) { - dbg("Select PHY #1 failed: %d", ret); - goto out; - } - - ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL); - if (ret < 0) - goto out; - - msleep(150); - - ret = asix_sw_reset(dev, AX_SWRESET_CLEAR); - if (ret < 0) - goto out; - - msleep(150); - - if (embd_phy) { - ret = asix_sw_reset(dev, AX_SWRESET_IPRL); - if (ret < 0) - goto out; - } else { - ret = asix_sw_reset(dev, AX_SWRESET_PRTE); - if (ret < 0) - goto out; - } - - msleep(150); - rx_ctl = asix_read_rx_ctl(dev); - dbg("RX_CTL is 0x%04x after software reset", rx_ctl); - ret = asix_write_rx_ctl(dev, 0x0000); - if (ret < 0) - goto out; - - rx_ctl = asix_read_rx_ctl(dev); - dbg("RX_CTL is 0x%04x setting to 0x0000", rx_ctl); - - ret = asix_sw_reset(dev, AX_SWRESET_PRL); - if (ret < 0) - goto out; - - msleep(150); - - ret = asix_sw_reset(dev, AX_SWRESET_IPRL | AX_SWRESET_PRL); - if (ret < 0) - goto out; - - msleep(150); - - 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); - - ret = asix_write_medium_mode(dev, AX88772_MEDIUM_DEFAULT); - if (ret < 0) - goto out; - - ret = asix_write_cmd(dev, AX_CMD_WRITE_IPG0, - AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT, - AX88772_IPG2_DEFAULT, 0, NULL); - if (ret < 0) { - dbg("Write IPG,IPG1,IPG2 failed: %d", ret); - goto out; - } - - /* Rewrite MAC address */ - memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN); - ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, - data->mac_addr); - if (ret < 0) - goto out; - - /* Set RX_CTL to default values with 2k buffer, and enable cactus */ - ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL); - if (ret < 0) - goto out; - - 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); - - return 0; - -out: - return ret; - -} - -static const struct net_device_ops ax88772_netdev_ops = { - .ndo_open = usbnet_open, - .ndo_stop = usbnet_stop, - .ndo_start_xmit = usbnet_start_xmit, - .ndo_tx_timeout = usbnet_tx_timeout, - .ndo_change_mtu = usbnet_change_mtu, - .ndo_set_mac_address = asix_set_mac_address, - .ndo_validate_addr = eth_validate_addr, - .ndo_do_ioctl = asix_ioctl, - .ndo_set_rx_mode = asix_set_multicast, -}; - - -void check_set_mac(unsigned char *buf); -static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) -{ - int ret, embd_phy; - struct asix_data *data = (struct asix_data *)&dev->data; - u8 buf[ETH_ALEN]; - u32 phyid; - - data->eeprom_len = AX88772_EEPROM_LEN; - - usbnet_get_endpoints(dev,intf); - - /* Get the MAC address */ - ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf); - if (ret < 0) { - dbg("Failed to read MAC address: %d", ret); - return ret; - } - - check_set_mac(buf); - - - 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->mii.phy_id = asix_get_phy_addr(dev); - - dev->net->netdev_ops = &ax88772_netdev_ops; - dev->net->ethtool_ops = &ax88772_ethtool_ops; - - embd_phy = ((dev->mii.phy_id & 0x1f) == 0x10 ? 1 : 0); - - /* Reset the PHY to normal operation mode */ - ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL); - if (ret < 0) { - dbg("Select PHY #1 failed: %d", ret); - return ret; - } - - ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL); - if (ret < 0) - return ret; - - msleep(150); - - ret = asix_sw_reset(dev, AX_SWRESET_CLEAR); - if (ret < 0) - return ret; - - msleep(150); - - ret = asix_sw_reset(dev, embd_phy ? AX_SWRESET_IPRL : AX_SWRESET_PRTE); - - /* Read PHYID register *AFTER* the PHY was reset properly */ - phyid = asix_get_phyid(dev); - dbg("PHYID=0x%08x", phyid); - - /* 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; -} - -static const 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; - - netdev_dbg(dev->net, "marvell_phy_init()\n"); - - reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_MARVELL_STATUS); - netdev_dbg(dev->net, "MII_MARVELL_STATUS = 0x%04x\n", 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); - netdev_dbg(dev->net, "MII_MARVELL_LED_CTRL (1) = 0x%04x\n", 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); - netdev_dbg(dev->net, "MII_MARVELL_LED_CTRL (2) = 0x%04x\n", reg); - reg &= 0xfc0f; - } - - return 0; -} - -static int rtl8211cl_phy_init(struct usbnet *dev) -{ - struct asix_data *data = (struct asix_data *)&dev->data; - - netdev_dbg(dev->net, "rtl8211cl_phy_init()\n"); - - asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0x0005); - asix_mdio_write (dev->net, dev->mii.phy_id, 0x0c, 0); - asix_mdio_write (dev->net, dev->mii.phy_id, 0x01, - asix_mdio_read (dev->net, dev->mii.phy_id, 0x01) | 0x0080); - asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0); - - if (data->ledmode == 12) { - asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0x0002); - asix_mdio_write (dev->net, dev->mii.phy_id, 0x1a, 0x00cb); - asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0); - } - - 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); - - netdev_dbg(dev->net, "marvell_led_status() read 0x%04x\n", 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; - } - - netdev_dbg(dev->net, "marvell_led_status() writing 0x%04x\n", reg); - asix_mdio_write(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL, reg); - - return 0; -} - -static int ax88178_reset(struct usbnet *dev) -{ - struct asix_data *data = (struct asix_data *)&dev->data; - int ret; - __le16 eeprom; - u8 status; - int gpio0 = 0; - u32 phyid; - - asix_read_cmd(dev, AX_CMD_READ_GPIOS, 0, 0, 1, &status); - dbg("GPIO Status: 0x%04x", status); - - 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 == cpu_to_le16(0xffff)) { - data->phymode = PHY_MODE_MARVELL; - data->ledmode = 0; - gpio0 = 1; - } else { - data->phymode = le16_to_cpu(eeprom) & 0x7F; - data->ledmode = le16_to_cpu(eeprom) >> 8; - gpio0 = (le16_to_cpu(eeprom) & 0x80) ? 0 : 1; - } - dbg("GPIO0: %d, PhyMode: %d", gpio0, data->phymode); - - /* Power up external GigaPHY through AX88178 GPIO pin */ - asix_write_gpio(dev, AX_GPIO_RSE | AX_GPIO_GPO_1 | AX_GPIO_GPO1EN, 40); - if ((le16_to_cpu(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); - } - - /* Read PHYID register *AFTER* powering up PHY */ - phyid = asix_get_phyid(dev); - dbg("PHYID=0x%08x", phyid); - - /* Set AX88178 to enable MII/GMII/RGMII interface for external PHY */ - asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, 0, 0, 0, NULL); - - 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); - - if (data->phymode == PHY_MODE_MARVELL) { - marvell_phy_init(dev); - msleep(60); - } else if (data->phymode == PHY_MODE_RTL8211CL) - rtl8211cl_phy_init(dev); - - 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); - - ret = asix_write_medium_mode(dev, AX88178_MEDIUM_DEFAULT); - if (ret < 0) - return ret; - - /* Rewrite MAC address */ - memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN); - ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, - data->mac_addr); - if (ret < 0) - return ret; - - ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL); - if (ret < 0) - return ret; - - return 0; -} - -static int ax88178_link_reset(struct usbnet *dev) -{ - u16 mode; - struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; - struct asix_data *data = (struct asix_data *)&dev->data; - u32 speed; - - netdev_dbg(dev->net, "ax88178_link_reset()\n"); - - mii_check_media(&dev->mii, 1, 1); - mii_ethtool_gset(&dev->mii, &ecmd); - mode = AX88178_MEDIUM_DEFAULT; - speed = ethtool_cmd_speed(&ecmd); - - if (speed == SPEED_1000) - mode |= AX_MEDIUM_GM; - else if (speed == SPEED_100) - mode |= AX_MEDIUM_PS; - else - mode &= ~(AX_MEDIUM_PS | AX_MEDIUM_GM); - - mode |= AX_MEDIUM_ENCK; - - if (ecmd.duplex == DUPLEX_FULL) - mode |= AX_MEDIUM_FD; - else - mode &= ~AX_MEDIUM_FD; - - netdev_dbg(dev->net, "ax88178_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", - speed, ecmd.duplex, mode); - - asix_write_medium_mode(dev, mode); - - if (data->phymode == PHY_MODE_MARVELL && data->ledmode) - marvell_led_status(dev, 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; - - netdev_dbg(dev->net, "ax88178_change_mtu() new_mtu=%d\n", 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 const struct net_device_ops ax88178_netdev_ops = { - .ndo_open = usbnet_open, - .ndo_stop = usbnet_stop, - .ndo_start_xmit = usbnet_start_xmit, - .ndo_tx_timeout = usbnet_tx_timeout, - .ndo_set_mac_address = asix_set_mac_address, - .ndo_validate_addr = eth_validate_addr, - .ndo_set_rx_mode = asix_set_multicast, - .ndo_do_ioctl = asix_ioctl, - .ndo_change_mtu = ax88178_change_mtu, -}; - -static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf) -{ - int ret; - u8 buf[ETH_ALEN]; - struct asix_data *data = (struct asix_data *)&dev->data; - - data->eeprom_len = AX88772_EEPROM_LEN; - - usbnet_get_endpoints(dev,intf); - - /* Get the MAC address */ - ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf); - if (ret < 0) { - dbg("Failed to read MAC address: %d", ret); - return ret; - } - 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->mii.phy_id = asix_get_phy_addr(dev); - - dev->net->netdev_ops = &ax88178_netdev_ops; - dev->net->ethtool_ops = &ax88178_ethtool_ops; - - /* Blink LEDS so users know driver saw dongle */ - asix_sw_reset(dev, 0); - msleep(150); - - asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD); - msleep(150); - - /* 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; -} - -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 | FLAG_LINK_INTR, - .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 | FLAG_LINK_INTR, - .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 | FLAG_LINK_INTR, - .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 | FLAG_LINK_INTR, - .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_reset, - .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET, - .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_reset, - .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR, - .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, -}, { - // Buffalo LUA-U2-GT 10/100/1000 - USB_DEVICE (0x0411, 0x006e), - .driver_info = (unsigned long) &ax88178_info, -}, { - // Sitecom LN-029 "USB 2.0 10/100 Ethernet adapter" - USB_DEVICE (0x6189, 0x182d), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // Sitecom LN-031 "USB 2.0 10/100/1000 Ethernet adapter" - USB_DEVICE (0x0df6, 0x0056), - .driver_info = (unsigned long) &ax88178_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 AX88772B 10/100 - USB_DEVICE (0x0b95, 0x772b), - .driver_info = (unsigned long) &ax88772_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, -}, { - // Logitec LAN-GTJ/U2A - USB_DEVICE (0x0789, 0x0160), - .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, -}, { - // Belkin F5D5055 - USB_DEVICE(0x050d, 0x5055), - .driver_info = (unsigned long) &ax88178_info, -}, { - // Apple USB Ethernet Adapter - USB_DEVICE(0x05ac, 0x1402), - .driver_info = (unsigned long) &ax88772_info, -}, { - // Cables-to-Go USB Ethernet Adapter - USB_DEVICE(0x0b95, 0x772a), - .driver_info = (unsigned long) &ax88772_info, -}, { - // ABOCOM for pci - USB_DEVICE(0x14ea, 0xab11), - .driver_info = (unsigned long) &ax88178_info, -}, { - // ASIX 88772a - USB_DEVICE(0x0db0, 0xa877), - .driver_info = (unsigned long) &ax88772_info, -}, { - // Asus USB Ethernet Adapter - USB_DEVICE (0x0b95, 0x7e2b), - .driver_info = (unsigned long) &ax88772_info, -}, - { }, // END -}; -MODULE_DEVICE_TABLE(usb, products); - -static struct usb_driver asix_driver = { - .name = DRIVER_NAME, - .id_table = products, - .probe = usbnet_probe, - .suspend = usbnet_suspend, - .resume = usbnet_resume, - .disconnect = usbnet_disconnect, - .supports_autosuspend = 1, -}; - -module_usb_driver(asix_driver); - -MODULE_AUTHOR("David Hollis"); -MODULE_VERSION(DRIVER_VERSION); -MODULE_DESCRIPTION("ASIX AX8817X based USB 2.0 Ethernet Devices"); -MODULE_LICENSE("GPL"); - diff --git a/ANDROID_3.4.5/drivers/net/usb/catc.c b/ANDROID_3.4.5/drivers/net/usb/catc.c deleted file mode 100644 index 182cfb4a..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/catc.c +++ /dev/null @@ -1,952 +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/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 <linux/gfp.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; - - 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; - int status = urb->status; - - if (!catc->is_f5u011) { - clear_bit(RX_RUNNING, &catc->flags); - pkt_offset = 2; - } - - if (status) { - dbg("rx_done, status %d, length %d", 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->netdev->stats.rx_length_errors++; - catc->netdev->stats.rx_errors++; - break; - } - } else { - pkt_len = urb->actual_length; - } - - if (!(skb = dev_alloc_skb(pkt_len))) - return; - - skb_copy_to_linear_data(skb, pkt_start + pkt_offset, pkt_len); - skb_put(skb, pkt_len); - - skb->protocol = eth_type_trans(skb, catc->netdev); - netif_rx(skb); - - catc->netdev->stats.rx_packets++; - catc->netdev->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); - - if (catc->is_f5u011) { - if (atomic_read(&catc->recq_sz)) { - int state; - atomic_dec(&catc->recq_sz); - dbg("getting extra packet"); - urb->dev = catc->usbdev; - if ((state = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { - dbg("submit(rx_urb) status %d", state); - } - } 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 = urb->status; - unsigned int hasdata = 0, linksts = LinkNoChange; - int res; - - 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 (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.", 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 ((res = usb_submit_urb(catc->rx_urb, GFP_ATOMIC)) < 0) { - err("submit(rx_urb) status %d", res); - } - } - } -resubmit: - res = usb_submit_urb (urb, GFP_ATOMIC); - if (res) - err ("can't resubmit intr, %s-%s, status %d", - catc->usbdev->bus->bus_name, - catc->usbdev->devpath, res); -} - -/* - * 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, status = urb->status; - - if (status == -ECONNRESET) { - dbg("Tx Reset."); - urb->status = 0; - catc->netdev->trans_start = jiffies; - catc->netdev->stats.tx_errors++; - clear_bit(TX_RUNNING, &catc->flags); - netif_wake_queue(catc->netdev); - return; - } - - if (status) { - dbg("tx_done, status %d, length %d", 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 netdev_tx_t catc_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; - if (catc->is_f5u011) - *(__be16 *)tx_buf = cpu_to_be16(skb->len); - else - *(__le16 *)tx_buf = cpu_to_le16(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->netdev->stats.tx_bytes += skb->len; - catc->netdev->stats.tx_packets++; - } - - dev_kfree_skb(skb); - - return NETDEV_TX_OK; -} - -static void catc_tx_timeout(struct net_device *netdev) -{ - struct catc *catc = netdev_priv(netdev); - - dev_warn(&netdev->dev, "Transmit timed out.\n"); - 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_ATOMIC))) - 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; - int status = urb->status; - - if (status) - dbg("ctrl_done, status %d, len %d.", 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->netdev->stats.collisions += data - last; - break; - case TxExcessColl: - catc->netdev->stats.tx_aborted_errors += data - last; - catc->netdev->stats.tx_errors += data - last; - break; - case RxFramErr: - catc->netdev->stats.rx_frame_errors += data - last; - catc->netdev->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); -} - -/* - * 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 netdev_hw_addr *ha; - u8 broadcast[6]; - u8 rx = RxEnable | RxPolarity | RxMultiCast; - - 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 { - netdev_for_each_mc_addr(ha, netdev) { - u32 crc = ether_crc_le(6, ha->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; - ethtool_cmd_speed_set(cmd, 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 const 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; -} - -static const struct net_device_ops catc_netdev_ops = { - .ndo_open = catc_open, - .ndo_stop = catc_stop, - .ndo_start_xmit = catc_start_xmit, - - .ndo_tx_timeout = catc_tx_timeout, - .ndo_set_rx_mode = catc_set_multicast_list, - .ndo_change_mtu = eth_change_mtu, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -/* - * 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->netdev_ops = &catc_netdev_ops; - netdev->watchdog_timeo = TX_TIMEOUT; - 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: - dev_warn(&intf->dev, - "Couldn't detect memory size, assuming 32k\n"); - 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, %pM.\n", - netdev->name, (catc->is_f5u011) ? "Belkin F5U011" : "CATC EL1210A NetMate", - usbdev->bus->bus_name, usbdev->devpath, netdev->dev_addr); - 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, -}; - -module_usb_driver(catc_driver); diff --git a/ANDROID_3.4.5/drivers/net/usb/cdc-phonet.c b/ANDROID_3.4.5/drivers/net/usb/cdc-phonet.c deleted file mode 100644 index 3e41b00c..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/cdc-phonet.c +++ /dev/null @@ -1,466 +0,0 @@ -/* - * phonet.c -- USB CDC Phonet host driver - * - * Copyright (C) 2008-2009 Nokia Corporation. All rights reserved. - * - * Author: Rémi Denis-Courmont - * - * 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. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/gfp.h> -#include <linux/usb.h> -#include <linux/usb/cdc.h> -#include <linux/netdevice.h> -#include <linux/if_arp.h> -#include <linux/if_phonet.h> -#include <linux/phonet.h> - -#define PN_MEDIA_USB 0x1B - -static const unsigned rxq_size = 17; - -struct usbpn_dev { - struct net_device *dev; - - struct usb_interface *intf, *data_intf; - struct usb_device *usb; - unsigned int tx_pipe, rx_pipe; - u8 active_setting; - u8 disconnected; - - unsigned tx_queue; - spinlock_t tx_lock; - - spinlock_t rx_lock; - struct sk_buff *rx_skb; - struct urb *urbs[0]; -}; - -static void tx_complete(struct urb *req); -static void rx_complete(struct urb *req); - -/* - * Network device callbacks - */ -static netdev_tx_t usbpn_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct usbpn_dev *pnd = netdev_priv(dev); - struct urb *req = NULL; - unsigned long flags; - int err; - - if (skb->protocol != htons(ETH_P_PHONET)) - goto drop; - - req = usb_alloc_urb(0, GFP_ATOMIC); - if (!req) - goto drop; - usb_fill_bulk_urb(req, pnd->usb, pnd->tx_pipe, skb->data, skb->len, - tx_complete, skb); - req->transfer_flags = URB_ZERO_PACKET; - err = usb_submit_urb(req, GFP_ATOMIC); - if (err) { - usb_free_urb(req); - goto drop; - } - - spin_lock_irqsave(&pnd->tx_lock, flags); - pnd->tx_queue++; - if (pnd->tx_queue >= dev->tx_queue_len) - netif_stop_queue(dev); - spin_unlock_irqrestore(&pnd->tx_lock, flags); - return NETDEV_TX_OK; - -drop: - dev_kfree_skb(skb); - dev->stats.tx_dropped++; - return NETDEV_TX_OK; -} - -static void tx_complete(struct urb *req) -{ - struct sk_buff *skb = req->context; - struct net_device *dev = skb->dev; - struct usbpn_dev *pnd = netdev_priv(dev); - int status = req->status; - - switch (status) { - case 0: - dev->stats.tx_bytes += skb->len; - break; - - case -ENOENT: - case -ECONNRESET: - case -ESHUTDOWN: - dev->stats.tx_aborted_errors++; - default: - dev->stats.tx_errors++; - dev_dbg(&dev->dev, "TX error (%d)\n", status); - } - dev->stats.tx_packets++; - - spin_lock(&pnd->tx_lock); - pnd->tx_queue--; - netif_wake_queue(dev); - spin_unlock(&pnd->tx_lock); - - dev_kfree_skb_any(skb); - usb_free_urb(req); -} - -static int rx_submit(struct usbpn_dev *pnd, struct urb *req, gfp_t gfp_flags) -{ - struct net_device *dev = pnd->dev; - struct page *page; - int err; - - page = alloc_page(gfp_flags); - if (!page) - return -ENOMEM; - - usb_fill_bulk_urb(req, pnd->usb, pnd->rx_pipe, page_address(page), - PAGE_SIZE, rx_complete, dev); - req->transfer_flags = 0; - err = usb_submit_urb(req, gfp_flags); - if (unlikely(err)) { - dev_dbg(&dev->dev, "RX submit error (%d)\n", err); - put_page(page); - } - return err; -} - -static void rx_complete(struct urb *req) -{ - struct net_device *dev = req->context; - struct usbpn_dev *pnd = netdev_priv(dev); - struct page *page = virt_to_page(req->transfer_buffer); - struct sk_buff *skb; - unsigned long flags; - int status = req->status; - - switch (status) { - case 0: - spin_lock_irqsave(&pnd->rx_lock, flags); - skb = pnd->rx_skb; - if (!skb) { - skb = pnd->rx_skb = netdev_alloc_skb(dev, 12); - if (likely(skb)) { - /* Can't use pskb_pull() on page in IRQ */ - memcpy(skb_put(skb, 1), page_address(page), 1); - skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, - page, 1, req->actual_length, - PAGE_SIZE); - page = NULL; - } - } else { - skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, - page, 0, req->actual_length, - PAGE_SIZE); - page = NULL; - } - if (req->actual_length < PAGE_SIZE) - pnd->rx_skb = NULL; /* Last fragment */ - else - skb = NULL; - spin_unlock_irqrestore(&pnd->rx_lock, flags); - if (skb) { - skb->protocol = htons(ETH_P_PHONET); - skb_reset_mac_header(skb); - __skb_pull(skb, 1); - skb->dev = dev; - dev->stats.rx_packets++; - dev->stats.rx_bytes += skb->len; - - netif_rx(skb); - } - goto resubmit; - - case -ENOENT: - case -ECONNRESET: - case -ESHUTDOWN: - req = NULL; - break; - - case -EOVERFLOW: - dev->stats.rx_over_errors++; - dev_dbg(&dev->dev, "RX overflow\n"); - break; - - case -EILSEQ: - dev->stats.rx_crc_errors++; - break; - } - - dev->stats.rx_errors++; -resubmit: - if (page) - put_page(page); - if (req) - rx_submit(pnd, req, GFP_ATOMIC | __GFP_COLD); -} - -static int usbpn_close(struct net_device *dev); - -static int usbpn_open(struct net_device *dev) -{ - struct usbpn_dev *pnd = netdev_priv(dev); - int err; - unsigned i; - unsigned num = pnd->data_intf->cur_altsetting->desc.bInterfaceNumber; - - err = usb_set_interface(pnd->usb, num, pnd->active_setting); - if (err) - return err; - - for (i = 0; i < rxq_size; i++) { - struct urb *req = usb_alloc_urb(0, GFP_KERNEL); - - if (!req || rx_submit(pnd, req, GFP_KERNEL | __GFP_COLD)) { - usbpn_close(dev); - return -ENOMEM; - } - pnd->urbs[i] = req; - } - - netif_wake_queue(dev); - return 0; -} - -static int usbpn_close(struct net_device *dev) -{ - struct usbpn_dev *pnd = netdev_priv(dev); - unsigned i; - unsigned num = pnd->data_intf->cur_altsetting->desc.bInterfaceNumber; - - netif_stop_queue(dev); - - for (i = 0; i < rxq_size; i++) { - struct urb *req = pnd->urbs[i]; - - if (!req) - continue; - usb_kill_urb(req); - usb_free_urb(req); - pnd->urbs[i] = NULL; - } - - return usb_set_interface(pnd->usb, num, !pnd->active_setting); -} - -static int usbpn_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - struct if_phonet_req *req = (struct if_phonet_req *)ifr; - - switch (cmd) { - case SIOCPNGAUTOCONF: - req->ifr_phonet_autoconf.device = PN_DEV_PC; - return 0; - } - return -ENOIOCTLCMD; -} - -static int usbpn_set_mtu(struct net_device *dev, int new_mtu) -{ - if ((new_mtu < PHONET_MIN_MTU) || (new_mtu > PHONET_MAX_MTU)) - return -EINVAL; - - dev->mtu = new_mtu; - return 0; -} - -static const struct net_device_ops usbpn_ops = { - .ndo_open = usbpn_open, - .ndo_stop = usbpn_close, - .ndo_start_xmit = usbpn_xmit, - .ndo_do_ioctl = usbpn_ioctl, - .ndo_change_mtu = usbpn_set_mtu, -}; - -static void usbpn_setup(struct net_device *dev) -{ - dev->features = 0; - dev->netdev_ops = &usbpn_ops, - dev->header_ops = &phonet_header_ops; - dev->type = ARPHRD_PHONET; - dev->flags = IFF_POINTOPOINT | IFF_NOARP; - dev->mtu = PHONET_MAX_MTU; - dev->hard_header_len = 1; - dev->dev_addr[0] = PN_MEDIA_USB; - dev->addr_len = 1; - dev->tx_queue_len = 3; - - dev->destructor = free_netdev; -} - -/* - * USB driver callbacks - */ -static struct usb_device_id usbpn_ids[] = { - { - .match_flags = USB_DEVICE_ID_MATCH_VENDOR - | USB_DEVICE_ID_MATCH_INT_CLASS - | USB_DEVICE_ID_MATCH_INT_SUBCLASS, - .idVendor = 0x0421, /* Nokia */ - .bInterfaceClass = USB_CLASS_COMM, - .bInterfaceSubClass = 0xFE, - }, - { }, -}; - -MODULE_DEVICE_TABLE(usb, usbpn_ids); - -static struct usb_driver usbpn_driver; - -int usbpn_probe(struct usb_interface *intf, const struct usb_device_id *id) -{ - static const char ifname[] = "usbpn%d"; - const struct usb_cdc_union_desc *union_header = NULL; - const struct usb_host_interface *data_desc; - struct usb_interface *data_intf; - struct usb_device *usbdev = interface_to_usbdev(intf); - struct net_device *dev; - struct usbpn_dev *pnd; - u8 *data; - int phonet = 0; - int len, err; - - data = intf->altsetting->extra; - len = intf->altsetting->extralen; - while (len >= 3) { - u8 dlen = data[0]; - if (dlen < 3) - return -EINVAL; - - /* bDescriptorType */ - if (data[1] == USB_DT_CS_INTERFACE) { - /* bDescriptorSubType */ - switch (data[2]) { - case USB_CDC_UNION_TYPE: - if (union_header || dlen < 5) - break; - union_header = - (struct usb_cdc_union_desc *)data; - break; - case 0xAB: - phonet = 1; - break; - } - } - data += dlen; - len -= dlen; - } - - if (!union_header || !phonet) - return -EINVAL; - - data_intf = usb_ifnum_to_if(usbdev, union_header->bSlaveInterface0); - if (data_intf == NULL) - return -ENODEV; - /* Data interface has one inactive and one active setting */ - if (data_intf->num_altsetting != 2) - return -EINVAL; - if (data_intf->altsetting[0].desc.bNumEndpoints == 0 && - data_intf->altsetting[1].desc.bNumEndpoints == 2) - data_desc = data_intf->altsetting + 1; - else - if (data_intf->altsetting[0].desc.bNumEndpoints == 2 && - data_intf->altsetting[1].desc.bNumEndpoints == 0) - data_desc = data_intf->altsetting; - else - return -EINVAL; - - dev = alloc_netdev(sizeof(*pnd) + sizeof(pnd->urbs[0]) * rxq_size, - ifname, usbpn_setup); - if (!dev) - return -ENOMEM; - - pnd = netdev_priv(dev); - SET_NETDEV_DEV(dev, &intf->dev); - - pnd->dev = dev; - pnd->usb = usb_get_dev(usbdev); - pnd->intf = intf; - pnd->data_intf = data_intf; - spin_lock_init(&pnd->tx_lock); - spin_lock_init(&pnd->rx_lock); - /* Endpoints */ - if (usb_pipein(data_desc->endpoint[0].desc.bEndpointAddress)) { - pnd->rx_pipe = usb_rcvbulkpipe(usbdev, - data_desc->endpoint[0].desc.bEndpointAddress); - pnd->tx_pipe = usb_sndbulkpipe(usbdev, - data_desc->endpoint[1].desc.bEndpointAddress); - } else { - pnd->rx_pipe = usb_rcvbulkpipe(usbdev, - data_desc->endpoint[1].desc.bEndpointAddress); - pnd->tx_pipe = usb_sndbulkpipe(usbdev, - data_desc->endpoint[0].desc.bEndpointAddress); - } - pnd->active_setting = data_desc - data_intf->altsetting; - - err = usb_driver_claim_interface(&usbpn_driver, data_intf, pnd); - if (err) - goto out; - - /* Force inactive mode until the network device is brought UP */ - usb_set_interface(usbdev, union_header->bSlaveInterface0, - !pnd->active_setting); - usb_set_intfdata(intf, pnd); - - err = register_netdev(dev); - if (err) { - usb_driver_release_interface(&usbpn_driver, data_intf); - goto out; - } - - dev_dbg(&dev->dev, "USB CDC Phonet device found\n"); - return 0; - -out: - usb_set_intfdata(intf, NULL); - free_netdev(dev); - return err; -} - -static void usbpn_disconnect(struct usb_interface *intf) -{ - struct usbpn_dev *pnd = usb_get_intfdata(intf); - struct usb_device *usb = pnd->usb; - - if (pnd->disconnected) - return; - - pnd->disconnected = 1; - usb_driver_release_interface(&usbpn_driver, - (pnd->intf == intf) ? pnd->data_intf : pnd->intf); - unregister_netdev(pnd->dev); - usb_put_dev(usb); -} - -static struct usb_driver usbpn_driver = { - .name = "cdc_phonet", - .probe = usbpn_probe, - .disconnect = usbpn_disconnect, - .id_table = usbpn_ids, -}; - -module_usb_driver(usbpn_driver); - -MODULE_AUTHOR("Remi Denis-Courmont"); -MODULE_DESCRIPTION("USB CDC Phonet host interface"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/net/usb/cdc_eem.c b/ANDROID_3.4.5/drivers/net/usb/cdc_eem.c deleted file mode 100644 index 685a4e22..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/cdc_eem.c +++ /dev/null @@ -1,377 +0,0 @@ -/* - * USB CDC EEM network interface driver - * Copyright (C) 2009 Oberthur Technologies - * by Omar Laazimani, Olivier Condemine - * - * 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/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/crc32.h> -#include <linux/usb/cdc.h> -#include <linux/usb/usbnet.h> -#include <linux/gfp.h> - - -/* - * This driver is an implementation of the CDC "Ethernet Emulation - * Model" (EEM) specification, which encapsulates Ethernet frames - * for transport over USB using a simpler USB device model than the - * previous CDC "Ethernet Control Model" (ECM, or "CDC Ethernet"). - * - * For details, see www.usb.org/developers/devclass_docs/CDC_EEM10.pdf - * - * This version has been tested with GIGAntIC WuaoW SIM Smart Card on 2.6.24, - * 2.6.27 and 2.6.30rc2 kernel. - * It has also been validated on Openmoko Om 2008.12 (based on 2.6.24 kernel). - * build on 23-April-2009 - */ - -#define EEM_HEAD 2 /* 2 byte header */ - -/*-------------------------------------------------------------------------*/ - -static void eem_linkcmd_complete(struct urb *urb) -{ - dev_kfree_skb(urb->context); - usb_free_urb(urb); -} - -static void eem_linkcmd(struct usbnet *dev, struct sk_buff *skb) -{ - struct urb *urb; - int status; - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) - goto fail; - - usb_fill_bulk_urb(urb, dev->udev, dev->out, - skb->data, skb->len, eem_linkcmd_complete, skb); - - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status) { - usb_free_urb(urb); -fail: - dev_kfree_skb(skb); - netdev_warn(dev->net, "link cmd failure\n"); - return; - } -} - -static int eem_bind(struct usbnet *dev, struct usb_interface *intf) -{ - int status = 0; - - status = usbnet_get_endpoints(dev, intf); - if (status < 0) { - usb_set_intfdata(intf, NULL); - usb_driver_release_interface(driver_of(intf), intf); - return status; - } - - /* no jumbogram (16K) support for now */ - - dev->net->hard_header_len += EEM_HEAD + ETH_FCS_LEN; - dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len; - - return 0; -} - -/* - * EEM permits packing multiple Ethernet frames into USB transfers - * (a "bundle"), but for TX we don't try to do that. - */ -static struct sk_buff *eem_tx_fixup(struct usbnet *dev, struct sk_buff *skb, - gfp_t flags) -{ - struct sk_buff *skb2 = NULL; - u16 len = skb->len; - u32 crc = 0; - int padlen = 0; - - /* When ((len + EEM_HEAD + ETH_FCS_LEN) % dev->maxpacket) is - * zero, stick two bytes of zero length EEM packet on the end. - * Else the framework would add invalid single byte padding, - * since it can't know whether ZLPs will be handled right by - * all the relevant hardware and software. - */ - if (!((len + EEM_HEAD + ETH_FCS_LEN) % dev->maxpacket)) - padlen += 2; - - if (!skb_cloned(skb)) { - int headroom = skb_headroom(skb); - int tailroom = skb_tailroom(skb); - - if ((tailroom >= ETH_FCS_LEN + padlen) && - (headroom >= EEM_HEAD)) - goto done; - - if ((headroom + tailroom) - > (EEM_HEAD + ETH_FCS_LEN + padlen)) { - skb->data = memmove(skb->head + - EEM_HEAD, - skb->data, - skb->len); - skb_set_tail_pointer(skb, len); - goto done; - } - } - - skb2 = skb_copy_expand(skb, EEM_HEAD, ETH_FCS_LEN + padlen, flags); - if (!skb2) - return NULL; - - dev_kfree_skb_any(skb); - skb = skb2; - -done: - /* we don't use the "no Ethernet CRC" option */ - crc = crc32_le(~0, skb->data, skb->len); - crc = ~crc; - - put_unaligned_le32(crc, skb_put(skb, 4)); - - /* EEM packet header format: - * b0..13: length of ethernet frame - * b14: bmCRC (1 == valid Ethernet CRC) - * b15: bmType (0 == data) - */ - len = skb->len; - put_unaligned_le16(BIT(14) | len, skb_push(skb, 2)); - - /* Bundle a zero length EEM packet if needed */ - if (padlen) - put_unaligned_le16(0, skb_put(skb, 2)); - - return skb; -} - -static int eem_rx_fixup(struct usbnet *dev, struct sk_buff *skb) -{ - /* - * Our task here is to strip off framing, leaving skb with one - * data frame for the usbnet framework code to process. But we - * may have received multiple EEM payloads, or command payloads. - * So we must process _everything_ as if it's a header, except - * maybe the last data payload - * - * REVISIT the framework needs updating so that when we consume - * all payloads (the last or only message was a command, or a - * zero length EEM packet) that is not accounted as an rx_error. - */ - do { - struct sk_buff *skb2 = NULL; - u16 header; - u16 len = 0; - - /* incomplete EEM header? */ - if (skb->len < EEM_HEAD) - return 0; - - /* - * EEM packet header format: - * b0..14: EEM type dependent (Data or Command) - * b15: bmType - */ - header = get_unaligned_le16(skb->data); - skb_pull(skb, EEM_HEAD); - - /* - * The bmType bit helps to denote when EEM - * packet is data or command : - * bmType = 0 : EEM data payload - * bmType = 1 : EEM (link) command - */ - if (header & BIT(15)) { - u16 bmEEMCmd; - - /* - * EEM (link) command packet: - * b0..10: bmEEMCmdParam - * b11..13: bmEEMCmd - * b14: bmReserved (must be 0) - * b15: 1 (EEM command) - */ - if (header & BIT(14)) { - netdev_dbg(dev->net, "reserved command %04x\n", - header); - continue; - } - - bmEEMCmd = (header >> 11) & 0x7; - switch (bmEEMCmd) { - - /* Responding to echo requests is mandatory. */ - case 0: /* Echo command */ - len = header & 0x7FF; - - /* bogus command? */ - if (skb->len < len) - return 0; - - skb2 = skb_clone(skb, GFP_ATOMIC); - if (unlikely(!skb2)) - goto next; - skb_trim(skb2, len); - put_unaligned_le16(BIT(15) | (1 << 11) | len, - skb_push(skb2, 2)); - eem_linkcmd(dev, skb2); - break; - - /* - * Host may choose to ignore hints. - * - suspend: peripheral ready to suspend - * - response: suggest N millisec polling - * - response complete: suggest N sec polling - */ - case 2: /* Suspend hint */ - case 3: /* Response hint */ - case 4: /* Response complete hint */ - continue; - - /* - * Hosts should never receive host-to-peripheral - * or reserved command codes; or responses to an - * echo command we didn't send. - */ - case 1: /* Echo response */ - case 5: /* Tickle */ - default: /* reserved */ - netdev_warn(dev->net, - "unexpected link command %d\n", - bmEEMCmd); - continue; - } - - } else { - u32 crc, crc2; - int is_last; - - /* zero length EEM packet? */ - if (header == 0) - continue; - - /* - * EEM data packet header : - * b0..13: length of ethernet frame - * b14: bmCRC - * b15: 0 (EEM data) - */ - len = header & 0x3FFF; - - /* bogus EEM payload? */ - if (skb->len < len) - return 0; - - /* bogus ethernet frame? */ - if (len < (ETH_HLEN + ETH_FCS_LEN)) - goto next; - - /* - * Treat the last payload differently: framework - * code expects our "fixup" to have stripped off - * headers, so "skb" is a data packet (or error). - * Else if it's not the last payload, keep "skb" - * for further processing. - */ - is_last = (len == skb->len); - if (is_last) - skb2 = skb; - else { - skb2 = skb_clone(skb, GFP_ATOMIC); - if (unlikely(!skb2)) - return 0; - } - - /* - * The bmCRC helps to denote when the CRC field in - * the Ethernet frame contains a calculated CRC: - * bmCRC = 1 : CRC is calculated - * bmCRC = 0 : CRC = 0xDEADBEEF - */ - if (header & BIT(14)) { - crc = get_unaligned_le32(skb2->data - + len - ETH_FCS_LEN); - crc2 = ~crc32_le(~0, skb2->data, skb2->len - - ETH_FCS_LEN); - } else { - crc = get_unaligned_be32(skb2->data - + len - ETH_FCS_LEN); - crc2 = 0xdeadbeef; - } - skb_trim(skb2, len - ETH_FCS_LEN); - - if (is_last) - return crc == crc2; - - if (unlikely(crc != crc2)) { - dev->net->stats.rx_errors++; - dev_kfree_skb_any(skb2); - } else - usbnet_skb_return(dev, skb2); - } - -next: - skb_pull(skb, len); - } while (skb->len); - - return 1; -} - -static const struct driver_info eem_info = { - .description = "CDC EEM Device", - .flags = FLAG_ETHER | FLAG_POINTTOPOINT, - .bind = eem_bind, - .rx_fixup = eem_rx_fixup, - .tx_fixup = eem_tx_fixup, -}; - -/*-------------------------------------------------------------------------*/ - -static const struct usb_device_id products[] = { -{ - USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_EEM, - USB_CDC_PROTO_EEM), - .driver_info = (unsigned long) &eem_info, -}, -{ - /* EMPTY == end of list */ -}, -}; -MODULE_DEVICE_TABLE(usb, products); - -static struct usb_driver eem_driver = { - .name = "cdc_eem", - .id_table = products, - .probe = usbnet_probe, - .disconnect = usbnet_disconnect, - .suspend = usbnet_suspend, - .resume = usbnet_resume, -}; - -module_usb_driver(eem_driver); - -MODULE_AUTHOR("Omar Laazimani <omar.oberthur@gmail.com>"); -MODULE_DESCRIPTION("USB CDC EEM"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/net/usb/cdc_ether.c b/ANDROID_3.4.5/drivers/net/usb/cdc_ether.c deleted file mode 100644 index 202af629..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/cdc_ether.c +++ /dev/null @@ -1,660 +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/ethtool.h> -#include <linux/workqueue.h> -#include <linux/mii.h> -#include <linux/usb.h> -#include <linux/usb/cdc.h> -#include <linux/usb/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); -} - -static int is_wireless_rndis(struct usb_interface_descriptor *desc) -{ - return (desc->bInterfaceClass == USB_CLASS_WIRELESS_CONTROLLER && - desc->bInterfaceSubClass == 1 && - desc->bInterfaceProtocol == 3); -} - -#else - -#define is_rndis(desc) 0 -#define is_activesync(desc) 0 -#define is_wireless_rndis(desc) 0 - -#endif - -static const u8 mbm_guid[16] = { - 0xa3, 0x17, 0xa8, 0x8b, 0x04, 0x5e, 0x4f, 0x01, - 0xa6, 0x07, 0xc0, 0xff, 0xcb, 0x7e, 0x39, 0x2a, -}; - -/* - * 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; - bool android_rndis_quirk = false; - struct usb_driver *driver = driver_of(intf); - struct usb_cdc_mdlm_desc *desc = NULL; - struct usb_cdc_mdlm_detail_desc *detail = NULL; - - 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; - dev_dbg(&intf->dev, "CDC descriptors on config\n"); - } - - /* Maybe CDC descriptors are after the endpoint? This bug has - * been seen on some 2Wire Inc RNDIS-ish products. - */ - if (len == 0) { - struct usb_host_endpoint *hep; - - hep = intf->cur_altsetting->endpoint; - if (hep) { - buf = hep->extra; - len = hep->extralen; - } - if (len) - dev_dbg(&intf->dev, - "CDC descriptors on endpoint\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) || - is_wireless_rndis(&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 *acm; - - acm = (void *) buf; - if (acm->bmCapabilities) { - dev_dbg(&intf->dev, - "ACM capabilities %02x, " - "not really RNDIS?\n", - acm->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); - /* fall back to hard-wiring for RNDIS */ - if (rndis) { - android_rndis_quirk = true; - goto next_desc; - } - 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; - case USB_CDC_MDLM_TYPE: - if (desc) { - dev_dbg(&intf->dev, "extra MDLM descriptor\n"); - goto bad_desc; - } - - desc = (void *)buf; - - if (desc->bLength != sizeof(*desc)) - goto bad_desc; - - if (memcmp(&desc->bGUID, mbm_guid, 16)) - goto bad_desc; - break; - case USB_CDC_MDLM_DETAIL_TYPE: - if (detail) { - dev_dbg(&intf->dev, "extra MDLM detail descriptor\n"); - goto bad_desc; - } - - detail = (void *)buf; - - if (detail->bGuidDescriptorType == 0) { - if (detail->bLength < (sizeof(*detail) + 1)) - goto bad_desc; - } else - goto bad_desc; - break; - } -next_desc: - len -= buf [0]; /* bLength */ - buf += buf [0]; - } - - /* Microsoft ActiveSync based and some regular RNDIS devices lack the - * CDC descriptors, so we'll hard-wire the interfaces and not check - * for descriptors. - * - * Some Android RNDIS devices have a CDC Union descriptor pointing - * to non-existing interfaces. Ignore that and attempt the same - * hard-wired 0 and 1 interfaces. - */ - if (rndis && (!info->u || android_rndis_quirk)) { - info->control = usb_ifnum_to_if(dev->udev, 0); - info->data = usb_ifnum_to_if(dev->udev, 1); - if (!info->control || !info->data || info->control != intf) { - dev_dbg(&intf->dev, - "rndis: 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) -{ - netif_info(dev, timer, dev->net, - "link speeds: %u kbps up, %u kbps down\n", - __le32_to_cpu(speeds[0]) / 1000, - __le32_to_cpu(speeds[1]) / 1000); -} - -void usbnet_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: - netif_dbg(dev, timer, dev->net, "CDC: carrier %s\n", - 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 */ - netif_dbg(dev, timer, dev->net, "CDC: speed change (len %d)\n", - 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: - netdev_err(dev->net, "CDC: unexpected notification %02x!\n", - event->bNotificationType); - break; - } -} -EXPORT_SYMBOL_GPL(usbnet_cdc_status); -void check_set_mac(unsigned char *buf); -int usbnet_cdc_bind(struct usbnet *dev, struct usb_interface *intf) -{ - int status; - struct cdc_state *info = (void *) &dev->data; - - BUILD_BUG_ON((sizeof(((struct usbnet *)0)->data) - < sizeof(struct cdc_state))); - - status = usbnet_generic_cdc_bind(dev, intf); - if (status < 0) - return status; - - status = usbnet_get_ethernet_addr(dev, info->ether->iMACAddress); - check_set_mac(dev->net->dev_addr); - 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; -} -EXPORT_SYMBOL_GPL(usbnet_cdc_bind); - -static int cdc_manage_power(struct usbnet *dev, int on) -{ - dev->intf->needs_remote_wakeup = on; - return 0; -} - -static const struct driver_info cdc_info = { - .description = "CDC Ethernet Device", - .flags = FLAG_ETHER | FLAG_POINTTOPOINT, - // .check_connect = cdc_check_connect, - .bind = usbnet_cdc_bind, - .unbind = usbnet_cdc_unbind, - .status = usbnet_cdc_status, - .manage_power = cdc_manage_power, -}; - -static const struct driver_info wwan_info = { - .description = "Mobile Broadband Network Device", - .flags = FLAG_WWAN, - .bind = usbnet_cdc_bind, - .unbind = usbnet_cdc_unbind, - .status = usbnet_cdc_status, - .manage_power = cdc_manage_power, -}; - -/*-------------------------------------------------------------------------*/ - -#define HUAWEI_VENDOR_ID 0x12D1 -#define NOVATEL_VENDOR_ID 0x1410 - -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, -}, - -/* LG Electronics VL600 wants additional headers on every frame */ -{ - USB_DEVICE_AND_INTERFACE_INFO(0x1004, 0x61aa, USB_CLASS_COMM, - USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), - .driver_info = 0, -}, - -/* Logitech Harmony 900 - uses the pseudo-MDLM (BLAN) driver */ -{ - USB_DEVICE_AND_INTERFACE_INFO(0x046d, 0xc11f, USB_CLASS_COMM, - USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), - .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). - */ -{ - /* Novatel USB551L */ - /* This match must come *before* the generic CDC-ETHER match so that - * we get FLAG_WWAN set on the device, since it's descriptors are - * generic CDC-ETHER. - */ - .match_flags = USB_DEVICE_ID_MATCH_VENDOR - | USB_DEVICE_ID_MATCH_PRODUCT - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = NOVATEL_VENDOR_ID, - .idProduct = 0xB001, - .bInterfaceClass = USB_CLASS_COMM, - .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, - .bInterfaceProtocol = USB_CDC_PROTO_NONE, - .driver_info = (unsigned long)&wwan_info, -}, { - USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET, - USB_CDC_PROTO_NONE), - .driver_info = (unsigned long) &cdc_info, -}, { - USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MDLM, - USB_CDC_PROTO_NONE), - .driver_info = (unsigned long)&wwan_info, - -}, { - /* Various Huawei modems with a network port like the UMG1831 */ - .match_flags = USB_DEVICE_ID_MATCH_VENDOR - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = HUAWEI_VENDOR_ID, - .bInterfaceClass = USB_CLASS_COMM, - .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, - .bInterfaceProtocol = 255, - .driver_info = (unsigned long)&wwan_info, -}, - { }, // END -}; -MODULE_DEVICE_TABLE(usb, products); - -struct usb_driver cdc_driver = { - .name = "cdc_ether", - .id_table = products, - .probe = usbnet_probe, - .disconnect = usbnet_disconnect, - .suspend = usbnet_suspend, - .resume = usbnet_resume, - .reset_resume = usbnet_resume, - .supports_autosuspend = 1, -}; -EXPORT_SYMBOL_GPL(cdc_driver); - -module_usb_driver(cdc_driver); - -MODULE_AUTHOR("David Brownell"); -MODULE_DESCRIPTION("USB CDC Ethernet devices"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/net/usb/cdc_ncm.c b/ANDROID_3.4.5/drivers/net/usb/cdc_ncm.c deleted file mode 100644 index 7adc9f6b..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/cdc_ncm.c +++ /dev/null @@ -1,1231 +0,0 @@ -/* - * cdc_ncm.c - * - * Copyright (C) ST-Ericsson 2010-2012 - * Contact: Alexey Orishko <alexey.orishko@stericsson.com> - * Original author: Hans Petter Selasky <hans.petter.selasky@stericsson.com> - * - * USB Host Driver for Network Control Model (NCM) - * http://www.usb.org/developers/devclass_docs/NCM10.zip - * - * The NCM encoding, decoding and initialization logic - * derives from FreeBSD 8.x. if_cdce.c and if_cdcereg.h - * - * This software is available to you under a choice of one of two - * licenses. You may choose this file to be licensed under the terms - * of the GNU General Public License (GPL) Version 2 or the 2-clause - * BSD license listed below: - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/netdevice.h> -#include <linux/ctype.h> -#include <linux/ethtool.h> -#include <linux/workqueue.h> -#include <linux/mii.h> -#include <linux/crc32.h> -#include <linux/usb.h> -#include <linux/hrtimer.h> -#include <linux/atomic.h> -#include <linux/usb/usbnet.h> -#include <linux/usb/cdc.h> - -#define DRIVER_VERSION "14-Mar-2012" - -/* CDC NCM subclass 3.2.1 */ -#define USB_CDC_NCM_NDP16_LENGTH_MIN 0x10 - -/* Maximum NTB length */ -#define CDC_NCM_NTB_MAX_SIZE_TX 32768 /* bytes */ -#define CDC_NCM_NTB_MAX_SIZE_RX 32768 /* bytes */ - -/* Minimum value for MaxDatagramSize, ch. 6.2.9 */ -#define CDC_NCM_MIN_DATAGRAM_SIZE 1514 /* bytes */ - -#define CDC_NCM_MIN_TX_PKT 512 /* bytes */ - -/* Default value for MaxDatagramSize */ -#define CDC_NCM_MAX_DATAGRAM_SIZE 8192 /* bytes */ - -/* - * Maximum amount of datagrams in NCM Datagram Pointer Table, not counting - * the last NULL entry. - */ -#define CDC_NCM_DPT_DATAGRAMS_MAX 40 - -/* Restart the timer, if amount of datagrams is less than given value */ -#define CDC_NCM_RESTART_TIMER_DATAGRAM_CNT 3 -#define CDC_NCM_TIMER_PENDING_CNT 2 -#define CDC_NCM_TIMER_INTERVAL (400UL * NSEC_PER_USEC) - -/* The following macro defines the minimum header space */ -#define CDC_NCM_MIN_HDR_SIZE \ - (sizeof(struct usb_cdc_ncm_nth16) + sizeof(struct usb_cdc_ncm_ndp16) + \ - (CDC_NCM_DPT_DATAGRAMS_MAX + 1) * sizeof(struct usb_cdc_ncm_dpe16)) - -struct cdc_ncm_data { - struct usb_cdc_ncm_nth16 nth16; - struct usb_cdc_ncm_ndp16 ndp16; - struct usb_cdc_ncm_dpe16 dpe16[CDC_NCM_DPT_DATAGRAMS_MAX + 1]; -}; - -struct cdc_ncm_ctx { - struct cdc_ncm_data tx_ncm; - struct usb_cdc_ncm_ntb_parameters ncm_parm; - struct hrtimer tx_timer; - struct tasklet_struct bh; - - const struct usb_cdc_ncm_desc *func_desc; - const struct usb_cdc_header_desc *header_desc; - const struct usb_cdc_union_desc *union_desc; - const struct usb_cdc_ether_desc *ether_desc; - - struct net_device *netdev; - struct usb_device *udev; - struct usb_host_endpoint *in_ep; - struct usb_host_endpoint *out_ep; - struct usb_host_endpoint *status_ep; - struct usb_interface *intf; - struct usb_interface *control; - struct usb_interface *data; - - struct sk_buff *tx_curr_skb; - struct sk_buff *tx_rem_skb; - - spinlock_t mtx; - atomic_t stop; - - u32 tx_timer_pending; - u32 tx_curr_offset; - u32 tx_curr_last_offset; - u32 tx_curr_frame_num; - u32 rx_speed; - u32 tx_speed; - u32 rx_max; - u32 tx_max; - u32 max_datagram_size; - u16 tx_max_datagrams; - u16 tx_remainder; - u16 tx_modulus; - u16 tx_ndp_modulus; - u16 tx_seq; - u16 rx_seq; - u16 connected; -}; - -static void cdc_ncm_txpath_bh(unsigned long param); -static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx); -static enum hrtimer_restart cdc_ncm_tx_timer_cb(struct hrtimer *hr_timer); -static const struct driver_info cdc_ncm_info; -static struct usb_driver cdc_ncm_driver; -static const struct ethtool_ops cdc_ncm_ethtool_ops; - -static const struct usb_device_id cdc_devs[] = { - { USB_INTERFACE_INFO(USB_CLASS_COMM, - USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE), - .driver_info = (unsigned long)&cdc_ncm_info, - }, - { - }, -}; - -MODULE_DEVICE_TABLE(usb, cdc_devs); - -static void -cdc_ncm_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) -{ - struct usbnet *dev = netdev_priv(net); - - strncpy(info->driver, dev->driver_name, sizeof(info->driver)); - strncpy(info->version, DRIVER_VERSION, sizeof(info->version)); - strncpy(info->fw_version, dev->driver_info->description, - sizeof(info->fw_version)); - usb_make_path(dev->udev, info->bus_info, sizeof(info->bus_info)); -} - -static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx) -{ - u32 val; - u8 flags; - u8 iface_no; - int err; - u16 ntb_fmt_supported; - - iface_no = ctx->control->cur_altsetting->desc.bInterfaceNumber; - - err = usb_control_msg(ctx->udev, - usb_rcvctrlpipe(ctx->udev, 0), - USB_CDC_GET_NTB_PARAMETERS, - USB_TYPE_CLASS | USB_DIR_IN - | USB_RECIP_INTERFACE, - 0, iface_no, &ctx->ncm_parm, - sizeof(ctx->ncm_parm), 10000); - if (err < 0) { - pr_debug("failed GET_NTB_PARAMETERS\n"); - return 1; - } - - /* read correct set of parameters according to device mode */ - ctx->rx_max = le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize); - ctx->tx_max = le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize); - ctx->tx_remainder = le16_to_cpu(ctx->ncm_parm.wNdpOutPayloadRemainder); - ctx->tx_modulus = le16_to_cpu(ctx->ncm_parm.wNdpOutDivisor); - ctx->tx_ndp_modulus = le16_to_cpu(ctx->ncm_parm.wNdpOutAlignment); - /* devices prior to NCM Errata shall set this field to zero */ - ctx->tx_max_datagrams = le16_to_cpu(ctx->ncm_parm.wNtbOutMaxDatagrams); - ntb_fmt_supported = le16_to_cpu(ctx->ncm_parm.bmNtbFormatsSupported); - - if (ctx->func_desc != NULL) - flags = ctx->func_desc->bmNetworkCapabilities; - else - flags = 0; - - pr_debug("dwNtbInMaxSize=%u dwNtbOutMaxSize=%u " - "wNdpOutPayloadRemainder=%u wNdpOutDivisor=%u " - "wNdpOutAlignment=%u wNtbOutMaxDatagrams=%u flags=0x%x\n", - ctx->rx_max, ctx->tx_max, ctx->tx_remainder, ctx->tx_modulus, - ctx->tx_ndp_modulus, ctx->tx_max_datagrams, flags); - - /* max count of tx datagrams */ - if ((ctx->tx_max_datagrams == 0) || - (ctx->tx_max_datagrams > CDC_NCM_DPT_DATAGRAMS_MAX)) - ctx->tx_max_datagrams = CDC_NCM_DPT_DATAGRAMS_MAX; - - /* verify maximum size of received NTB in bytes */ - if (ctx->rx_max < USB_CDC_NCM_NTB_MIN_IN_SIZE) { - pr_debug("Using min receive length=%d\n", - USB_CDC_NCM_NTB_MIN_IN_SIZE); - ctx->rx_max = USB_CDC_NCM_NTB_MIN_IN_SIZE; - } - - if (ctx->rx_max > CDC_NCM_NTB_MAX_SIZE_RX) { - pr_debug("Using default maximum receive length=%d\n", - CDC_NCM_NTB_MAX_SIZE_RX); - ctx->rx_max = CDC_NCM_NTB_MAX_SIZE_RX; - } - - /* inform device about NTB input size changes */ - if (ctx->rx_max != le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize)) { - - if (flags & USB_CDC_NCM_NCAP_NTB_INPUT_SIZE) { - struct usb_cdc_ncm_ndp_input_size *ndp_in_sz; - - ndp_in_sz = kzalloc(sizeof(*ndp_in_sz), GFP_KERNEL); - if (!ndp_in_sz) { - err = -ENOMEM; - goto size_err; - } - - err = usb_control_msg(ctx->udev, - usb_sndctrlpipe(ctx->udev, 0), - USB_CDC_SET_NTB_INPUT_SIZE, - USB_TYPE_CLASS | USB_DIR_OUT - | USB_RECIP_INTERFACE, - 0, iface_no, ndp_in_sz, 8, 1000); - kfree(ndp_in_sz); - } else { - __le32 *dwNtbInMaxSize; - dwNtbInMaxSize = kzalloc(sizeof(*dwNtbInMaxSize), - GFP_KERNEL); - if (!dwNtbInMaxSize) { - err = -ENOMEM; - goto size_err; - } - *dwNtbInMaxSize = cpu_to_le32(ctx->rx_max); - - err = usb_control_msg(ctx->udev, - usb_sndctrlpipe(ctx->udev, 0), - USB_CDC_SET_NTB_INPUT_SIZE, - USB_TYPE_CLASS | USB_DIR_OUT - | USB_RECIP_INTERFACE, - 0, iface_no, dwNtbInMaxSize, 4, 1000); - kfree(dwNtbInMaxSize); - } -size_err: - if (err < 0) - pr_debug("Setting NTB Input Size failed\n"); - } - - /* verify maximum size of transmitted NTB in bytes */ - if ((ctx->tx_max < - (CDC_NCM_MIN_HDR_SIZE + CDC_NCM_MIN_DATAGRAM_SIZE)) || - (ctx->tx_max > CDC_NCM_NTB_MAX_SIZE_TX)) { - pr_debug("Using default maximum transmit length=%d\n", - CDC_NCM_NTB_MAX_SIZE_TX); - ctx->tx_max = CDC_NCM_NTB_MAX_SIZE_TX; - } - - /* - * verify that the structure alignment is: - * - power of two - * - not greater than the maximum transmit length - * - not less than four bytes - */ - val = ctx->tx_ndp_modulus; - - if ((val < USB_CDC_NCM_NDP_ALIGN_MIN_SIZE) || - (val != ((-val) & val)) || (val >= ctx->tx_max)) { - pr_debug("Using default alignment: 4 bytes\n"); - ctx->tx_ndp_modulus = USB_CDC_NCM_NDP_ALIGN_MIN_SIZE; - } - - /* - * verify that the payload alignment is: - * - power of two - * - not greater than the maximum transmit length - * - not less than four bytes - */ - val = ctx->tx_modulus; - - if ((val < USB_CDC_NCM_NDP_ALIGN_MIN_SIZE) || - (val != ((-val) & val)) || (val >= ctx->tx_max)) { - pr_debug("Using default transmit modulus: 4 bytes\n"); - ctx->tx_modulus = USB_CDC_NCM_NDP_ALIGN_MIN_SIZE; - } - - /* verify the payload remainder */ - if (ctx->tx_remainder >= ctx->tx_modulus) { - pr_debug("Using default transmit remainder: 0 bytes\n"); - ctx->tx_remainder = 0; - } - - /* adjust TX-remainder according to NCM specification. */ - ctx->tx_remainder = ((ctx->tx_remainder - ETH_HLEN) & - (ctx->tx_modulus - 1)); - - /* additional configuration */ - - /* set CRC Mode */ - if (flags & USB_CDC_NCM_NCAP_CRC_MODE) { - err = usb_control_msg(ctx->udev, usb_sndctrlpipe(ctx->udev, 0), - USB_CDC_SET_CRC_MODE, - USB_TYPE_CLASS | USB_DIR_OUT - | USB_RECIP_INTERFACE, - USB_CDC_NCM_CRC_NOT_APPENDED, - iface_no, NULL, 0, 1000); - if (err < 0) - pr_debug("Setting CRC mode off failed\n"); - } - - /* set NTB format, if both formats are supported */ - if (ntb_fmt_supported & USB_CDC_NCM_NTH32_SIGN) { - err = usb_control_msg(ctx->udev, usb_sndctrlpipe(ctx->udev, 0), - USB_CDC_SET_NTB_FORMAT, USB_TYPE_CLASS - | USB_DIR_OUT | USB_RECIP_INTERFACE, - USB_CDC_NCM_NTB16_FORMAT, - iface_no, NULL, 0, 1000); - if (err < 0) - pr_debug("Setting NTB format to 16-bit failed\n"); - } - - ctx->max_datagram_size = CDC_NCM_MIN_DATAGRAM_SIZE; - - /* set Max Datagram Size (MTU) */ - if (flags & USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE) { - __le16 *max_datagram_size; - u16 eth_max_sz = le16_to_cpu(ctx->ether_desc->wMaxSegmentSize); - - max_datagram_size = kzalloc(sizeof(*max_datagram_size), - GFP_KERNEL); - if (!max_datagram_size) { - err = -ENOMEM; - goto max_dgram_err; - } - - err = usb_control_msg(ctx->udev, usb_rcvctrlpipe(ctx->udev, 0), - USB_CDC_GET_MAX_DATAGRAM_SIZE, - USB_TYPE_CLASS | USB_DIR_IN - | USB_RECIP_INTERFACE, - 0, iface_no, max_datagram_size, - 2, 1000); - if (err < 0) { - pr_debug("GET_MAX_DATAGRAM_SIZE failed, use size=%u\n", - CDC_NCM_MIN_DATAGRAM_SIZE); - } else { - ctx->max_datagram_size = - le16_to_cpu(*max_datagram_size); - /* Check Eth descriptor value */ - if (ctx->max_datagram_size > eth_max_sz) - ctx->max_datagram_size = eth_max_sz; - - if (ctx->max_datagram_size > CDC_NCM_MAX_DATAGRAM_SIZE) - ctx->max_datagram_size = - CDC_NCM_MAX_DATAGRAM_SIZE; - - if (ctx->max_datagram_size < CDC_NCM_MIN_DATAGRAM_SIZE) - ctx->max_datagram_size = - CDC_NCM_MIN_DATAGRAM_SIZE; - - /* if value changed, update device */ - if (ctx->max_datagram_size != - le16_to_cpu(*max_datagram_size)) { - err = usb_control_msg(ctx->udev, - usb_sndctrlpipe(ctx->udev, 0), - USB_CDC_SET_MAX_DATAGRAM_SIZE, - USB_TYPE_CLASS | USB_DIR_OUT - | USB_RECIP_INTERFACE, - 0, - iface_no, max_datagram_size, - 2, 1000); - if (err < 0) - pr_debug("SET_MAX_DGRAM_SIZE failed\n"); - } - } - kfree(max_datagram_size); - } - -max_dgram_err: - if (ctx->netdev->mtu != (ctx->max_datagram_size - ETH_HLEN)) - ctx->netdev->mtu = ctx->max_datagram_size - ETH_HLEN; - - return 0; -} - -static void -cdc_ncm_find_endpoints(struct cdc_ncm_ctx *ctx, struct usb_interface *intf) -{ - struct usb_host_endpoint *e; - u8 ep; - - for (ep = 0; ep < intf->cur_altsetting->desc.bNumEndpoints; ep++) { - - e = intf->cur_altsetting->endpoint + ep; - switch (e->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { - case USB_ENDPOINT_XFER_INT: - if (usb_endpoint_dir_in(&e->desc)) { - if (ctx->status_ep == NULL) - ctx->status_ep = e; - } - break; - - case USB_ENDPOINT_XFER_BULK: - if (usb_endpoint_dir_in(&e->desc)) { - if (ctx->in_ep == NULL) - ctx->in_ep = e; - } else { - if (ctx->out_ep == NULL) - ctx->out_ep = e; - } - break; - - default: - break; - } - } -} - -static void cdc_ncm_free(struct cdc_ncm_ctx *ctx) -{ - if (ctx == NULL) - return; - - if (ctx->tx_rem_skb != NULL) { - dev_kfree_skb_any(ctx->tx_rem_skb); - ctx->tx_rem_skb = NULL; - } - - if (ctx->tx_curr_skb != NULL) { - dev_kfree_skb_any(ctx->tx_curr_skb); - ctx->tx_curr_skb = NULL; - } - - kfree(ctx); -} - -static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf) -{ - struct cdc_ncm_ctx *ctx; - struct usb_driver *driver; - u8 *buf; - int len; - int temp; - u8 iface_no; - - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if (ctx == NULL) - return -ENODEV; - - hrtimer_init(&ctx->tx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - ctx->tx_timer.function = &cdc_ncm_tx_timer_cb; - ctx->bh.data = (unsigned long)ctx; - ctx->bh.func = cdc_ncm_txpath_bh; - atomic_set(&ctx->stop, 0); - spin_lock_init(&ctx->mtx); - ctx->netdev = dev->net; - - /* store ctx pointer in device data field */ - dev->data[0] = (unsigned long)ctx; - - /* get some pointers */ - driver = driver_of(intf); - buf = intf->cur_altsetting->extra; - len = intf->cur_altsetting->extralen; - - ctx->udev = dev->udev; - ctx->intf = intf; - - /* parse through descriptors associated with control interface */ - while ((len > 0) && (buf[0] > 2) && (buf[0] <= len)) { - - if (buf[1] != USB_DT_CS_INTERFACE) - goto advance; - - switch (buf[2]) { - case USB_CDC_UNION_TYPE: - if (buf[0] < sizeof(*(ctx->union_desc))) - break; - - ctx->union_desc = - (const struct usb_cdc_union_desc *)buf; - - ctx->control = usb_ifnum_to_if(dev->udev, - ctx->union_desc->bMasterInterface0); - ctx->data = usb_ifnum_to_if(dev->udev, - ctx->union_desc->bSlaveInterface0); - break; - - case USB_CDC_ETHERNET_TYPE: - if (buf[0] < sizeof(*(ctx->ether_desc))) - break; - - ctx->ether_desc = - (const struct usb_cdc_ether_desc *)buf; - dev->hard_mtu = - le16_to_cpu(ctx->ether_desc->wMaxSegmentSize); - - if (dev->hard_mtu < CDC_NCM_MIN_DATAGRAM_SIZE) - dev->hard_mtu = CDC_NCM_MIN_DATAGRAM_SIZE; - else if (dev->hard_mtu > CDC_NCM_MAX_DATAGRAM_SIZE) - dev->hard_mtu = CDC_NCM_MAX_DATAGRAM_SIZE; - break; - - case USB_CDC_NCM_TYPE: - if (buf[0] < sizeof(*(ctx->func_desc))) - break; - - ctx->func_desc = (const struct usb_cdc_ncm_desc *)buf; - break; - - default: - break; - } -advance: - /* advance to next descriptor */ - temp = buf[0]; - buf += temp; - len -= temp; - } - - /* check if we got everything */ - if ((ctx->control == NULL) || (ctx->data == NULL) || - (ctx->ether_desc == NULL) || (ctx->control != intf)) - goto error; - - /* claim interfaces, if any */ - temp = usb_driver_claim_interface(driver, ctx->data, dev); - if (temp) - goto error; - - iface_no = ctx->data->cur_altsetting->desc.bInterfaceNumber; - - /* reset data interface */ - temp = usb_set_interface(dev->udev, iface_no, 0); - if (temp) - goto error2; - - /* initialize data interface */ - if (cdc_ncm_setup(ctx)) - goto error2; - - /* configure data interface */ - temp = usb_set_interface(dev->udev, iface_no, 1); - if (temp) - goto error2; - - cdc_ncm_find_endpoints(ctx, ctx->data); - cdc_ncm_find_endpoints(ctx, ctx->control); - - if ((ctx->in_ep == NULL) || (ctx->out_ep == NULL) || - (ctx->status_ep == NULL)) - goto error2; - - dev->net->ethtool_ops = &cdc_ncm_ethtool_ops; - - usb_set_intfdata(ctx->data, dev); - usb_set_intfdata(ctx->control, dev); - usb_set_intfdata(ctx->intf, dev); - - temp = usbnet_get_ethernet_addr(dev, ctx->ether_desc->iMACAddress); - if (temp) - goto error2; - - dev_info(&dev->udev->dev, "MAC-Address: %pM\n", dev->net->dev_addr); - - dev->in = usb_rcvbulkpipe(dev->udev, - ctx->in_ep->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); - dev->out = usb_sndbulkpipe(dev->udev, - ctx->out_ep->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); - dev->status = ctx->status_ep; - dev->rx_urb_size = ctx->rx_max; - - /* - * We should get an event when network connection is "connected" or - * "disconnected". Set network connection in "disconnected" state - * (carrier is OFF) during attach, so the IP network stack does not - * start IPv6 negotiation and more. - */ - netif_carrier_off(dev->net); - ctx->tx_speed = ctx->rx_speed = 0; - return 0; - -error2: - usb_set_intfdata(ctx->control, NULL); - usb_set_intfdata(ctx->data, NULL); - usb_driver_release_interface(driver, ctx->data); -error: - cdc_ncm_free((struct cdc_ncm_ctx *)dev->data[0]); - dev->data[0] = 0; - dev_info(&dev->udev->dev, "bind() failure\n"); - return -ENODEV; -} - -static void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf) -{ - struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0]; - struct usb_driver *driver = driver_of(intf); - - if (ctx == NULL) - return; /* no setup */ - - atomic_set(&ctx->stop, 1); - - if (hrtimer_active(&ctx->tx_timer)) - hrtimer_cancel(&ctx->tx_timer); - - tasklet_kill(&ctx->bh); - - /* disconnect master --> disconnect slave */ - if (intf == ctx->control && ctx->data) { - usb_set_intfdata(ctx->data, NULL); - usb_driver_release_interface(driver, ctx->data); - ctx->data = NULL; - - } else if (intf == ctx->data && ctx->control) { - usb_set_intfdata(ctx->control, NULL); - usb_driver_release_interface(driver, ctx->control); - ctx->control = NULL; - } - - usb_set_intfdata(ctx->intf, NULL); - cdc_ncm_free(ctx); -} - -static void cdc_ncm_zero_fill(u8 *ptr, u32 first, u32 end, u32 max) -{ - if (first >= max) - return; - if (first >= end) - return; - if (end > max) - end = max; - memset(ptr + first, 0, end - first); -} - -static struct sk_buff * -cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb) -{ - struct sk_buff *skb_out; - u32 rem; - u32 offset; - u32 last_offset; - u16 n = 0, index; - u8 ready2send = 0; - - /* if there is a remaining skb, it gets priority */ - if (skb != NULL) - swap(skb, ctx->tx_rem_skb); - else - ready2send = 1; - - /* - * +----------------+ - * | skb_out | - * +----------------+ - * ^ offset - * ^ last_offset - */ - - /* check if we are resuming an OUT skb */ - if (ctx->tx_curr_skb != NULL) { - /* pop variables */ - skb_out = ctx->tx_curr_skb; - offset = ctx->tx_curr_offset; - last_offset = ctx->tx_curr_last_offset; - n = ctx->tx_curr_frame_num; - - } else { - /* reset variables */ - skb_out = alloc_skb((ctx->tx_max + 1), GFP_ATOMIC); - if (skb_out == NULL) { - if (skb != NULL) { - dev_kfree_skb_any(skb); - ctx->netdev->stats.tx_dropped++; - } - goto exit_no_skb; - } - - /* make room for NTH and NDP */ - offset = ALIGN(sizeof(struct usb_cdc_ncm_nth16), - ctx->tx_ndp_modulus) + - sizeof(struct usb_cdc_ncm_ndp16) + - (ctx->tx_max_datagrams + 1) * - sizeof(struct usb_cdc_ncm_dpe16); - - /* store last valid offset before alignment */ - last_offset = offset; - /* align first Datagram offset correctly */ - offset = ALIGN(offset, ctx->tx_modulus) + ctx->tx_remainder; - /* zero buffer till the first IP datagram */ - cdc_ncm_zero_fill(skb_out->data, 0, offset, offset); - n = 0; - ctx->tx_curr_frame_num = 0; - } - - for (; n < ctx->tx_max_datagrams; n++) { - /* check if end of transmit buffer is reached */ - if (offset >= ctx->tx_max) { - ready2send = 1; - break; - } - /* compute maximum buffer size */ - rem = ctx->tx_max - offset; - - if (skb == NULL) { - skb = ctx->tx_rem_skb; - ctx->tx_rem_skb = NULL; - - /* check for end of skb */ - if (skb == NULL) - break; - } - - if (skb->len > rem) { - if (n == 0) { - /* won't fit, MTU problem? */ - dev_kfree_skb_any(skb); - skb = NULL; - ctx->netdev->stats.tx_dropped++; - } else { - /* no room for skb - store for later */ - if (ctx->tx_rem_skb != NULL) { - dev_kfree_skb_any(ctx->tx_rem_skb); - ctx->netdev->stats.tx_dropped++; - } - ctx->tx_rem_skb = skb; - skb = NULL; - ready2send = 1; - } - break; - } - - memcpy(((u8 *)skb_out->data) + offset, skb->data, skb->len); - - ctx->tx_ncm.dpe16[n].wDatagramLength = cpu_to_le16(skb->len); - ctx->tx_ncm.dpe16[n].wDatagramIndex = cpu_to_le16(offset); - - /* update offset */ - offset += skb->len; - - /* store last valid offset before alignment */ - last_offset = offset; - - /* align offset correctly */ - offset = ALIGN(offset, ctx->tx_modulus) + ctx->tx_remainder; - - /* zero padding */ - cdc_ncm_zero_fill(skb_out->data, last_offset, offset, - ctx->tx_max); - dev_kfree_skb_any(skb); - skb = NULL; - } - - /* free up any dangling skb */ - if (skb != NULL) { - dev_kfree_skb_any(skb); - skb = NULL; - ctx->netdev->stats.tx_dropped++; - } - - ctx->tx_curr_frame_num = n; - - if (n == 0) { - /* wait for more frames */ - /* push variables */ - ctx->tx_curr_skb = skb_out; - ctx->tx_curr_offset = offset; - ctx->tx_curr_last_offset = last_offset; - goto exit_no_skb; - - } else if ((n < ctx->tx_max_datagrams) && (ready2send == 0)) { - /* wait for more frames */ - /* push variables */ - ctx->tx_curr_skb = skb_out; - ctx->tx_curr_offset = offset; - ctx->tx_curr_last_offset = last_offset; - /* set the pending count */ - if (n < CDC_NCM_RESTART_TIMER_DATAGRAM_CNT) - ctx->tx_timer_pending = CDC_NCM_TIMER_PENDING_CNT; - goto exit_no_skb; - - } else { - /* frame goes out */ - /* variables will be reset at next call */ - } - - /* check for overflow */ - if (last_offset > ctx->tx_max) - last_offset = ctx->tx_max; - - /* revert offset */ - offset = last_offset; - - /* - * If collected data size is less or equal CDC_NCM_MIN_TX_PKT bytes, - * we send buffers as it is. If we get more data, it would be more - * efficient for USB HS mobile device with DMA engine to receive a full - * size NTB, than canceling DMA transfer and receiving a short packet. - */ - if (offset > CDC_NCM_MIN_TX_PKT) - offset = ctx->tx_max; - - /* final zero padding */ - cdc_ncm_zero_fill(skb_out->data, last_offset, offset, ctx->tx_max); - - /* store last offset */ - last_offset = offset; - - if (((last_offset < ctx->tx_max) && ((last_offset % - le16_to_cpu(ctx->out_ep->desc.wMaxPacketSize)) == 0)) || - (((last_offset == ctx->tx_max) && ((ctx->tx_max % - le16_to_cpu(ctx->out_ep->desc.wMaxPacketSize)) == 0)) && - (ctx->tx_max < le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize)))) { - /* force short packet */ - *(((u8 *)skb_out->data) + last_offset) = 0; - last_offset++; - } - - /* zero the rest of the DPEs plus the last NULL entry */ - for (; n <= CDC_NCM_DPT_DATAGRAMS_MAX; n++) { - ctx->tx_ncm.dpe16[n].wDatagramLength = 0; - ctx->tx_ncm.dpe16[n].wDatagramIndex = 0; - } - - /* fill out 16-bit NTB header */ - ctx->tx_ncm.nth16.dwSignature = cpu_to_le32(USB_CDC_NCM_NTH16_SIGN); - ctx->tx_ncm.nth16.wHeaderLength = - cpu_to_le16(sizeof(ctx->tx_ncm.nth16)); - ctx->tx_ncm.nth16.wSequence = cpu_to_le16(ctx->tx_seq); - ctx->tx_ncm.nth16.wBlockLength = cpu_to_le16(last_offset); - index = ALIGN(sizeof(struct usb_cdc_ncm_nth16), ctx->tx_ndp_modulus); - ctx->tx_ncm.nth16.wNdpIndex = cpu_to_le16(index); - - memcpy(skb_out->data, &(ctx->tx_ncm.nth16), sizeof(ctx->tx_ncm.nth16)); - ctx->tx_seq++; - - /* fill out 16-bit NDP table */ - ctx->tx_ncm.ndp16.dwSignature = - cpu_to_le32(USB_CDC_NCM_NDP16_NOCRC_SIGN); - rem = sizeof(ctx->tx_ncm.ndp16) + ((ctx->tx_curr_frame_num + 1) * - sizeof(struct usb_cdc_ncm_dpe16)); - ctx->tx_ncm.ndp16.wLength = cpu_to_le16(rem); - ctx->tx_ncm.ndp16.wNextNdpIndex = 0; /* reserved */ - - memcpy(((u8 *)skb_out->data) + index, - &(ctx->tx_ncm.ndp16), - sizeof(ctx->tx_ncm.ndp16)); - - memcpy(((u8 *)skb_out->data) + index + sizeof(ctx->tx_ncm.ndp16), - &(ctx->tx_ncm.dpe16), - (ctx->tx_curr_frame_num + 1) * - sizeof(struct usb_cdc_ncm_dpe16)); - - /* set frame length */ - skb_put(skb_out, last_offset); - - /* return skb */ - ctx->tx_curr_skb = NULL; - ctx->netdev->stats.tx_packets += ctx->tx_curr_frame_num; - return skb_out; - -exit_no_skb: - /* Start timer, if there is a remaining skb */ - if (ctx->tx_curr_skb != NULL) - cdc_ncm_tx_timeout_start(ctx); - return NULL; -} - -static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx) -{ - /* start timer, if not already started */ - if (!(hrtimer_active(&ctx->tx_timer) || atomic_read(&ctx->stop))) - hrtimer_start(&ctx->tx_timer, - ktime_set(0, CDC_NCM_TIMER_INTERVAL), - HRTIMER_MODE_REL); -} - -static enum hrtimer_restart cdc_ncm_tx_timer_cb(struct hrtimer *timer) -{ - struct cdc_ncm_ctx *ctx = - container_of(timer, struct cdc_ncm_ctx, tx_timer); - - if (!atomic_read(&ctx->stop)) - tasklet_schedule(&ctx->bh); - return HRTIMER_NORESTART; -} - -static void cdc_ncm_txpath_bh(unsigned long param) -{ - struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)param; - - spin_lock_bh(&ctx->mtx); - if (ctx->tx_timer_pending != 0) { - ctx->tx_timer_pending--; - cdc_ncm_tx_timeout_start(ctx); - spin_unlock_bh(&ctx->mtx); - } else if (ctx->netdev != NULL) { - spin_unlock_bh(&ctx->mtx); - netif_tx_lock_bh(ctx->netdev); - usbnet_start_xmit(NULL, ctx->netdev); - netif_tx_unlock_bh(ctx->netdev); - } -} - -static struct sk_buff * -cdc_ncm_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) -{ - struct sk_buff *skb_out; - struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0]; - - /* - * The Ethernet API we are using does not support transmitting - * multiple Ethernet frames in a single call. This driver will - * accumulate multiple Ethernet frames and send out a larger - * USB frame when the USB buffer is full or when a single jiffies - * timeout happens. - */ - if (ctx == NULL) - goto error; - - spin_lock_bh(&ctx->mtx); - skb_out = cdc_ncm_fill_tx_frame(ctx, skb); - spin_unlock_bh(&ctx->mtx); - return skb_out; - -error: - if (skb != NULL) - dev_kfree_skb_any(skb); - - return NULL; -} - -static int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in) -{ - struct sk_buff *skb; - struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0]; - int len; - int nframes; - int x; - int offset; - struct usb_cdc_ncm_nth16 *nth16; - struct usb_cdc_ncm_ndp16 *ndp16; - struct usb_cdc_ncm_dpe16 *dpe16; - - if (ctx == NULL) - goto error; - - if (skb_in->len < (sizeof(struct usb_cdc_ncm_nth16) + - sizeof(struct usb_cdc_ncm_ndp16))) { - pr_debug("frame too short\n"); - goto error; - } - - nth16 = (struct usb_cdc_ncm_nth16 *)skb_in->data; - - if (le32_to_cpu(nth16->dwSignature) != USB_CDC_NCM_NTH16_SIGN) { - pr_debug("invalid NTH16 signature <%u>\n", - le32_to_cpu(nth16->dwSignature)); - goto error; - } - - len = le16_to_cpu(nth16->wBlockLength); - if (len > ctx->rx_max) { - pr_debug("unsupported NTB block length %u/%u\n", len, - ctx->rx_max); - goto error; - } - - if ((ctx->rx_seq + 1) != le16_to_cpu(nth16->wSequence) && - (ctx->rx_seq || le16_to_cpu(nth16->wSequence)) && - !((ctx->rx_seq == 0xffff) && !le16_to_cpu(nth16->wSequence))) { - pr_debug("sequence number glitch prev=%d curr=%d\n", - ctx->rx_seq, le16_to_cpu(nth16->wSequence)); - } - ctx->rx_seq = le16_to_cpu(nth16->wSequence); - - len = le16_to_cpu(nth16->wNdpIndex); - if ((len + sizeof(struct usb_cdc_ncm_ndp16)) > skb_in->len) { - pr_debug("invalid DPT16 index <%u>\n", - le16_to_cpu(nth16->wNdpIndex)); - goto error; - } - - ndp16 = (struct usb_cdc_ncm_ndp16 *)(((u8 *)skb_in->data) + len); - - if (le32_to_cpu(ndp16->dwSignature) != USB_CDC_NCM_NDP16_NOCRC_SIGN) { - pr_debug("invalid DPT16 signature <%u>\n", - le32_to_cpu(ndp16->dwSignature)); - goto error; - } - - if (le16_to_cpu(ndp16->wLength) < USB_CDC_NCM_NDP16_LENGTH_MIN) { - pr_debug("invalid DPT16 length <%u>\n", - le32_to_cpu(ndp16->dwSignature)); - goto error; - } - - nframes = ((le16_to_cpu(ndp16->wLength) - - sizeof(struct usb_cdc_ncm_ndp16)) / - sizeof(struct usb_cdc_ncm_dpe16)); - nframes--; /* we process NDP entries except for the last one */ - - len += sizeof(struct usb_cdc_ncm_ndp16); - - if ((len + nframes * (sizeof(struct usb_cdc_ncm_dpe16))) > - skb_in->len) { - pr_debug("Invalid nframes = %d\n", nframes); - goto error; - } - - dpe16 = (struct usb_cdc_ncm_dpe16 *)(((u8 *)skb_in->data) + len); - - for (x = 0; x < nframes; x++, dpe16++) { - offset = le16_to_cpu(dpe16->wDatagramIndex); - len = le16_to_cpu(dpe16->wDatagramLength); - - /* - * CDC NCM ch. 3.7 - * All entries after first NULL entry are to be ignored - */ - if ((offset == 0) || (len == 0)) { - if (!x) - goto error; /* empty NTB */ - break; - } - - /* sanity checking */ - if (((offset + len) > skb_in->len) || - (len > ctx->rx_max) || (len < ETH_HLEN)) { - pr_debug("invalid frame detected (ignored)" - "offset[%u]=%u, length=%u, skb=%p\n", - x, offset, len, skb_in); - if (!x) - goto error; - break; - - } else { - skb = skb_clone(skb_in, GFP_ATOMIC); - if (!skb) - goto error; - skb->len = len; - skb->data = ((u8 *)skb_in->data) + offset; - skb_set_tail_pointer(skb, len); - usbnet_skb_return(dev, skb); - } - } - return 1; -error: - return 0; -} - -static void -cdc_ncm_speed_change(struct cdc_ncm_ctx *ctx, - struct usb_cdc_speed_change *data) -{ - uint32_t rx_speed = le32_to_cpu(data->DLBitRRate); - uint32_t tx_speed = le32_to_cpu(data->ULBitRate); - - /* - * Currently the USB-NET API does not support reporting the actual - * device speed. Do print it instead. - */ - if ((tx_speed != ctx->tx_speed) || (rx_speed != ctx->rx_speed)) { - ctx->tx_speed = tx_speed; - ctx->rx_speed = rx_speed; - - if ((tx_speed > 1000000) && (rx_speed > 1000000)) { - printk(KERN_INFO KBUILD_MODNAME - ": %s: %u mbit/s downlink " - "%u mbit/s uplink\n", - ctx->netdev->name, - (unsigned int)(rx_speed / 1000000U), - (unsigned int)(tx_speed / 1000000U)); - } else { - printk(KERN_INFO KBUILD_MODNAME - ": %s: %u kbit/s downlink " - "%u kbit/s uplink\n", - ctx->netdev->name, - (unsigned int)(rx_speed / 1000U), - (unsigned int)(tx_speed / 1000U)); - } - } -} - -static void cdc_ncm_status(struct usbnet *dev, struct urb *urb) -{ - struct cdc_ncm_ctx *ctx; - struct usb_cdc_notification *event; - - ctx = (struct cdc_ncm_ctx *)dev->data[0]; - - if (urb->actual_length < sizeof(*event)) - return; - - /* test for split data in 8-byte chunks */ - if (test_and_clear_bit(EVENT_STS_SPLIT, &dev->flags)) { - cdc_ncm_speed_change(ctx, - (struct usb_cdc_speed_change *)urb->transfer_buffer); - return; - } - - event = urb->transfer_buffer; - - switch (event->bNotificationType) { - case USB_CDC_NOTIFY_NETWORK_CONNECTION: - /* - * According to the CDC NCM specification ch.7.1 - * USB_CDC_NOTIFY_NETWORK_CONNECTION notification shall be - * sent by device after USB_CDC_NOTIFY_SPEED_CHANGE. - */ - ctx->connected = event->wValue; - - printk(KERN_INFO KBUILD_MODNAME ": %s: network connection:" - " %sconnected\n", - ctx->netdev->name, ctx->connected ? "" : "dis"); - - if (ctx->connected) - netif_carrier_on(dev->net); - else { - netif_carrier_off(dev->net); - ctx->tx_speed = ctx->rx_speed = 0; - } - break; - - case USB_CDC_NOTIFY_SPEED_CHANGE: - if (urb->actual_length < (sizeof(*event) + - sizeof(struct usb_cdc_speed_change))) - set_bit(EVENT_STS_SPLIT, &dev->flags); - else - cdc_ncm_speed_change(ctx, - (struct usb_cdc_speed_change *) &event[1]); - break; - - default: - dev_err(&dev->udev->dev, "NCM: unexpected " - "notification 0x%02x!\n", event->bNotificationType); - break; - } -} - -static int cdc_ncm_check_connect(struct usbnet *dev) -{ - struct cdc_ncm_ctx *ctx; - - ctx = (struct cdc_ncm_ctx *)dev->data[0]; - if (ctx == NULL) - return 1; /* disconnected */ - - return !ctx->connected; -} - -static int -cdc_ncm_probe(struct usb_interface *udev, const struct usb_device_id *prod) -{ - return usbnet_probe(udev, prod); -} - -static void cdc_ncm_disconnect(struct usb_interface *intf) -{ - struct usbnet *dev = usb_get_intfdata(intf); - - if (dev == NULL) - return; /* already disconnected */ - - usbnet_disconnect(intf); -} - -static int cdc_ncm_manage_power(struct usbnet *dev, int status) -{ - dev->intf->needs_remote_wakeup = status; - return 0; -} - -static const struct driver_info cdc_ncm_info = { - .description = "CDC NCM", - .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET, - .bind = cdc_ncm_bind, - .unbind = cdc_ncm_unbind, - .check_connect = cdc_ncm_check_connect, - .manage_power = cdc_ncm_manage_power, - .status = cdc_ncm_status, - .rx_fixup = cdc_ncm_rx_fixup, - .tx_fixup = cdc_ncm_tx_fixup, -}; - -static struct usb_driver cdc_ncm_driver = { - .name = "cdc_ncm", - .id_table = cdc_devs, - .probe = cdc_ncm_probe, - .disconnect = cdc_ncm_disconnect, - .suspend = usbnet_suspend, - .resume = usbnet_resume, - .reset_resume = usbnet_resume, - .supports_autosuspend = 1, -}; - -static const struct ethtool_ops cdc_ncm_ethtool_ops = { - .get_drvinfo = cdc_ncm_get_drvinfo, - .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, -}; - -module_usb_driver(cdc_ncm_driver); - -MODULE_AUTHOR("Hans Petter Selasky"); -MODULE_DESCRIPTION("USB CDC NCM host driver"); -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/ANDROID_3.4.5/drivers/net/usb/cdc_subset.c b/ANDROID_3.4.5/drivers/net/usb/cdc_subset.c deleted file mode 100644 index b403d934..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/cdc_subset.c +++ /dev/null @@ -1,345 +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 <linux/usb/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", - .flags = FLAG_POINTTOPOINT, -}; - -#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", - .flags = FLAG_POINTTOPOINT, - // 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", - .flags = FLAG_POINTTOPOINT, -}; - -#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, - .flags = FLAG_POINTTOPOINT, - - .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", - .flags = FLAG_POINTTOPOINT, -}; -#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, - .flags = FLAG_POINTTOPOINT, -}; - -static const struct driver_info yopy_info = { - .description = "Yopy", - .check_connect = always_connected, - .flags = FLAG_POINTTOPOINT, -}; - -static const struct driver_info blob_info = { - .description = "Boot Loader OBject", - .check_connect = always_connected, - .flags = FLAG_POINTTOPOINT, -}; - -#endif /* CONFIG_USB_ARMLINUX */ - - -/*-------------------------------------------------------------------------*/ - -#ifndef HAVE_HARDWARE -#warning 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, -}, { - USB_DEVICE (0x1286, 0x8001), // "blob" bootloader - .driver_info = (unsigned long) &blob_info, -}, { - // Linux Ethernet/RNDIS gadget, mostly on PXA, second config - // e.g. Gumstix, current OpenZaurus, ... or anything else - // that just enables this gadget option. - USB_DEVICE (0x0525, 0xa4a2), - .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, -}; - -module_usb_driver(cdc_subset_driver); - -MODULE_AUTHOR("David Brownell"); -MODULE_DESCRIPTION("Simple 'CDC Subset' USB networking links"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/net/usb/ch9x00.c b/ANDROID_3.4.5/drivers/net/usb/ch9x00.c deleted file mode 100755 index 11ac3d50..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/ch9x00.c +++ /dev/null @@ -1,852 +0,0 @@ -/* - * USB 10M/100M ethernet adapter - * - * 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, whther express or implied - */ - -#include <linux/kernel.h> -#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 <linux/usb/usbnet.h> -#include <linux/slab.h> - - -#define CH9x00_VID 0x1A86 -#define CH9x00_PID_8339 0x8339 -#define CH9x00_PID_E091 0xE091 -#define CH9x00_PID_E092 0xE092 - -#define DRIVER_VERSION "29-May-2013" - -#define DEBUG_PRT //for debug -#undef DEBUG_PRT - -#ifdef DEBUG_PRT -#define dbg_prt(format, arg...) printk(KERN_DEBUG format "\n", ## arg) -#else -#define dbg_prt(format, arg...) do {} while (0) -#endif - -/**** Reg and CMD definition for CH9x00_PID_E091 and CH9x00_PID_8339****/ -#define DEVICE_SPEED_10M 0x80 -#define DEVICE_MEDIA_CONNECTED 0x40 -#define DEVICE_DUPLEX_FULL 0x20 -#define DEVICE_PHY 0x10 - -#define REQ_RD_REG (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE) -#define REQ_WR_REG (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE) -#define CTRL_TIMEOUT_MS 1000 - -#define MCAST_MAX 0x40 -#define TX_OVERHEAD 0x04 -#define RX_OVERHEAD 0x04 - -#define GET_MAC_ADDRESS 0x00 -#define SET_HASH_TABLE 0x04 -#define SET_PACKAGE_FILTER 0x05 - #define RECEIVE_ALL 0x08 - #define MULTIPKT_EN 0x04 - #define BROADPKT_EN 0x02 - #define HASH_MULTI_EN 0x01 - #define CTRL_CLOSE 0x00 - #define CTRL_OPEN 0x01 -#define SET_SPEED_DUPLEX 0x06 - #define HALF_DUPLEX 0x00 - #define FULL_DUPLEX 0x01 - #define SPEED_10M 0x00 - #define SPEED_100M 0x02 - #define MT 0x00 - #define AT 0x04 -#define SET_MAC_ADDRESS 0x07 -#define SET_MAC_WAKEUP_FRAME 0x08 -#define SET_WAKEUP_ENABLE 0x09 - #define LINKCHG0_EN 0x01 - #define LINKCHG1_EN 0x02 - #define MAGICPKT_EN 0x04 - #define WAKEUP1_EN 0x08 - #define WAKEUP2_EN 0x10 - #define WAKEUP3_EN 0x20 - #define WAKEUP4_EN 0x40 -#define SET_FULL_DUPLEX_FLOW_CONTROL 0x0A -#define SET_HALF_DUPLEX_FLOW_CONTROL 0x0B - -#define TEST_GET_MAC_ADDRESS -#define TEST_SET_MAC_ADDRESS -//#define TEST_SET_HASH -//#define TEST_SET_PACKAGE_FILTER -#define TEST_SET_SPEED_DUPLEX -//#define TEST_SET_WAKEUP_ENABLE - #if defined(TEST_SET_WAKEUP_ENABLE) - #define WKE1_EN - #define WKE2_EN - #define WKE3_EN - #define WKE4_EN - #define MAGIC_EN - #define LIKCHG1_EN - #define LIKCHG0_EN - #endif - - -/**** Reg and CMD definition for CH9x00_PID_E092 ****/ -// === constant define -#define RX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? 60 : 4) -#define TX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? 60 : 4) - -#define MIN_PACKET sizeof(struct ethhdr) -#define MAX_PACKET 32768 - -#define TX_TIMEOUT_JIFFIES (5 * HZ) -#define THROTTLE_JIFFIES (HZ / 8) -#define UNLINK_TIMEOUT_MS 3 - -// for vendor-specific control operations -#define CONTROL_TIMEOUT_MS 1000 - -// request -#define REQUEST_READ 0x0E -#define REQUEST_WRITE 0x0F - -#define REQUEST_TYPE_READ (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER) -#define REQUEST_TYPE_WRITE (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER) - -// address space -// addr 00---63 : mii addr -// addr 64---128 : mac addr -// note : read/write must be in word (16 bit) - -#define MAC_REG_CTRL 64 -#define MAC_REG_STATUS 66 -#define MAC_REG_INTERRUPT_MASK 68 -#define MAC_REG_PHY_COMMAND 70 -#define MAC_REG_PHY_DATA 72 -#define MAC_REG_STATION_L 74 -#define MAC_REG_STATION_M 76 -#define MAC_REG_STATION_H 78 -#define MAC_REG_HASH_L 80 -#define MAC_REG_HASH_M1 82 -#define MAC_REG_HASH_M2 84 -#define MAC_REG_HASH_H 86 -#define MAC_REG_THRESHOLD 88 -#define MAC_REG_FIFO_DEPTH 90 -#define MAC_REG_PAUSE 92 -#define MAC_REG_FLOW_CONTROL 94 - -// BIT -// control register bit15 and bit13 reserve -#define LOOPBACK (0x01 << 14) -#define BASE100X (0x01 << 12) -#define MBPS_10 (0x01 << 11) -#define DUPLEX_MODE (0x01 << 10) -#define PAUSE_FRAME (0x01 << 9) -#define PROMISCUOUS (0x01 << 8) -#define MULTICAST (0x01 << 7) -#define BROADCAST (0x01 << 6) -#define HASH (0x01 << 5) -#define APPEND_PAD (0x01 << 4) -#define APPEND_CRC (0x01 << 3) -#define TRANSMITTER_ACTION (0x01 << 2) -#define RECEIVER_ACTION (0x01 << 1) -#define DMA_ACTION (0x01 << 0) - -// status register bit15-bit7 reserve -#define ALIGNMENT (0x01 << 6) -#define FIFO_OVER_RUN (0x01 << 5) -#define FIFO_UNDER_RUN (0x01 << 4) -#define RX_ERROR (0x01 << 3) -#define RX_COMPLETE (0x01 << 2) -#define TX_ERROR (0x01 << 1) -#define TX_COMPLETE (0x01 << 0) - -// fifo depth register bit14 and bit6 reserve -#define ETH_TXBD (0x01 << 15) -#define ETN_TX_FIFO_DEPTH // bit13:8 -#define ETH_RXBD (0x01 << 7)// bit -#define ETH_RX_FIFO_DEPTH // bit5:0 - - -// ************************************************** -int speed_status; -int link_status; -int duplex_status; -int phy_status; - - -static void ch9x00_async_cmd_callback( struct urb *urb ) -{ - struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; - - if( urb->status < 0 ) - printk( KERN_DEBUG "%s() failed with %d\n", __FUNCTION__, urb->status); - - kfree(req); - usb_free_urb(urb); -} - - -static void ch9x00_set_reg_async( - struct usbnet *dev, - unsigned char request, - unsigned char requesttype, - unsigned short value, - unsigned short index, - unsigned short 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 allocation URB in write_cmd_async!\n"); - return; - } - - req = kmalloc( sizeof *req, GFP_ATOMIC); - if(!req) { - dev_err( &dev->udev->dev, - "Failed to allocate memory for control request\n"); - goto out; - } - - req->bRequestType = requesttype; - req->bRequest = request; - 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, ch9x00_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\n", ret ); - goto out; - } - return; - -out: - kfree(req); - usb_free_urb(urb); -} - - -static void set_speed_duplex( struct usbnet *dev, unsigned char value_l ) -{ - unsigned short value; - unsigned char value_low = 0x00; - unsigned char value_high = 0x00; - - value_low = value_l; - value = value_low | (value_high << 8 ); - ch9x00_set_reg_async( dev, SET_SPEED_DUPLEX, REQ_WR_REG, value, 0, 0, NULL); - - return; -} - - -static int control_read( struct usbnet *dev, - unsigned char request, unsigned char requesttype, - unsigned short value, unsigned short index, - void *data, unsigned short size, int timeout ) -{ - unsigned char *buf = NULL; - int err = 0; - - dbg_prt("\n--> Control_read() index=0x%02x size=%d\n", index, size ); - - buf = kmalloc( size, GFP_KERNEL ); - if( !buf ) { - err = -ENOMEM; - goto err_out; - } - - err = usb_control_msg( dev->udev, - usb_rcvctrlpipe(dev->udev, 0), - request, requesttype, - value, index, - buf, size, timeout); - if( err == size ) - memcpy( data, buf, size ); - else if( err >= 0 ) - err = -EINVAL; - kfree(buf); - - return err; - -err_out: - return err; -} - - -static int control_write( struct usbnet *dev, - unsigned char request, unsigned char requesttype, - unsigned short value, unsigned short index, - void *data, unsigned short size, int timeout ) -{ - unsigned char *buf = NULL; - int err = 0; - - dbg_prt("\n--> Control_write() index=0x%02x size=%d\n", index, size ); - - if( data ) { - buf = kmalloc( size, GFP_KERNEL ); - if( !buf ) { - err = -ENOMEM; - goto err_out; - } - memcpy( buf, data, size ); - } - - err = usb_control_msg( dev->udev, - usb_sndctrlpipe( dev->udev, 0 ), - request, requesttype, - value, index, - buf, size, timeout ); - if( err >= 0 && err < size ) - err = -EINVAL; - kfree( buf ); - - return 0; - -err_out: - return err; -} - -static int ch9x00_mdio_read( struct net_device *netdev, - int phy_id, int loc ) -{ - struct usbnet *dev = netdev_priv(netdev); - int product_id = dev->udev->descriptor.idProduct; - __le16 res = 0x00; //for E091 - unsigned char buff[2]; //for E092 - - dbg_prt("ch9x00_mdio_read phy_id:%02x loc:%02x\n", phy_id, loc); - - if( product_id == CH9x00_PID_E091 || - product_id == CH9x00_PID_8339 ) { - mutex_lock( &dev->phy_mutex ); - if( phy_id == 0x00 ) { - switch(loc) { - case MII_BMCR: //Basic mode control register - { - if(speed_status == DEVICE_SPEED_10M){ - //Do nothing here - } - else - res |= BMCR_SPEED100; - - if(duplex_status == DEVICE_DUPLEX_FULL) - res |= BMCR_FULLDPLX; - else { - //Do nothing here - } - - res |= BMCR_ANENABLE; - break; - } - case MII_BMSR: //Basic mode status register - { - if(link_status == DEVICE_MEDIA_CONNECTED) //up - res |= BMSR_LSTATUS; - else { //down - //Do nothing - } - - if(speed_status == DEVICE_SPEED_10M) { - if(duplex_status == DEVICE_DUPLEX_FULL) - res |= BMSR_10FULL; - else - res |= BMSR_10HALF; - } - else { - if(duplex_status == DEVICE_DUPLEX_FULL) - res |= BMSR_100FULL; - else - res |= BMSR_100HALF; - } - - break; - } - case MII_ADVERTISE: //Advertisement control reg - { - if(speed_status == DEVICE_SPEED_10M) - res |= ADVERTISE_10FULL; - else - res |= ADVERTISE_10HALF; - - res |= 0x01; //IEEE 802.3 - } - case MII_LPA: //Link partner ability reg - { - if(speed_status == DEVICE_SPEED_10M) { - if(duplex_status == DEVICE_DUPLEX_FULL) - res |= LPA_10FULL; - else - res |= LPA_10HALF; - } - else { - if(duplex_status == DEVICE_DUPLEX_FULL) - res |= LPA_100FULL; - else - res |= LPA_100HALF; - } - - res |= 0x01; //IEEE 802.3 - break; - } - case MII_EXPANSION: //Expansion register - break; - default: - break; - } - } - mutex_unlock( &dev->phy_mutex); - return le16_to_cpu(res); - } - else if( product_id == CH9x00_PID_E092 ) { - if( phy_id ) - return 0; - - control_read( dev, REQUEST_READ, REQUEST_TYPE_READ, - 0, loc*2, buff, 0x02, CONTROL_TIMEOUT_MS ); - - return ( buff[0] | buff[1] << 8 ); - } - - return 0; -} - - -static void ch9x00_mdio_write( struct net_device *netdev, - int phy_id, int loc, int val ) -{ - struct usbnet *dev = netdev_priv(netdev); - int product_id = dev->udev->descriptor.idProduct; - unsigned char value_l = 0; //for E091 - unsigned char buff[2]; //for E092 - - dbg_prt("ch9x00_mdio_write() phy_id=%02x loc:%02x\n", phy_id, loc); - - if( product_id == CH9x00_PID_E091 || - product_id == CH9x00_PID_8339 ) { - mutex_lock( &dev->phy_mutex ); - if(phy_id == 0x00) { - switch(loc) { - case MII_BMCR: //Base mode control register - { - if( val & BMCR_ANRESTART ) { - //Do nothing - } - - if( val & BMCR_ANENABLE ) { - value_l |= AT; - goto set; - } - - if( val & BMCR_SPEED100 ) { - value_l |= SPEED_100M; - } - - // bit 8 duplex mode 1 = full-duplex - if( val & BMCR_FULLDPLX ) { - value_l |= FULL_DUPLEX; - } -set: - set_speed_duplex(dev, value_l); - break; - } - case MII_BMSR: //Basic mode status register - break; - case MII_ADVERTISE: //Advertisement control reg - break; - case MII_LPA: //Link partner ability reg - break; - case MII_EXPANSION: //Expansion register - break; - default: - break; - } - } - mutex_unlock( &dev->phy_mutex ); - return; - } - else if( product_id == CH9x00_PID_E092 ) { - buff[0] = (unsigned char)val; - buff[1] = (unsigned char)(val >> 8); - - if(phy_id) - return; - - control_write( dev, REQUEST_WRITE, REQUEST_TYPE_WRITE, - 0, loc*2, buff, 0x02, CONTROL_TIMEOUT_MS ); - - } - -} - - -static int ch9x00_link_reset( struct usbnet *dev ) -{ - struct ethtool_cmd ecmd; - - mii_check_media( &dev->mii, 1, 1 ); - mii_ethtool_gset( &dev->mii, &ecmd ); - - dbg_prt("\nlink_reset() speed:%d duplex:%d \n", ecmd.speed, ecmd.duplex ); - - return 0; -} - - -static void ch9x00_status( struct usbnet *dev, struct urb *urb ) -{ - int link; - unsigned char *buf; - int product_id = dev->udev->descriptor.idProduct; - - if( product_id == CH9x00_PID_E091 || - product_id == CH9x00_PID_8339 ) { - if( urb->actual_length < 8 ) - return; - - buf = urb->transfer_buffer; - link = !!(buf[0] & DEVICE_MEDIA_CONNECTED ); - link_status = buf[0] & DEVICE_MEDIA_CONNECTED; - speed_status = buf[0] & DEVICE_SPEED_10M; - duplex_status = buf[0] & DEVICE_DUPLEX_FULL; - phy_status = buf[0] & DEVICE_PHY; - - 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); - } - } - } - else if( product_id == CH9x00_PID_E092 ) { - if( urb->actual_length < 16 ) - return; - - buf = urb->transfer_buffer; - link = !!(buf[0] & 0x01); - - if( link ) { - netif_carrier_on(dev->net); - usbnet_defer_kevent(dev, EVENT_LINK_RESET); - } - else { - netif_carrier_off(dev->net); - } - } - - - return; -} - - -static struct sk_buff *ch9x00_tx_fixup( - struct usbnet *dev, struct sk_buff *skb, gfp_t flags ) -{ - int i = 0; - int len = 0; - int tx_overhead = 0; - int product_id = dev->udev->descriptor.idProduct; - - if( product_id == CH9x00_PID_E091 || - product_id == CH9x00_PID_8339 ) - tx_overhead = TX_OVERHEAD; //TX_OVERHEAD: 0x04 - else if( product_id == CH9x00_PID_E092 ) - tx_overhead = 0x40; //64 - - len = skb->len; - if( skb_headroom(skb) < tx_overhead ) { - struct sk_buff *skb2; - - skb2 = skb_copy_expand(skb, tx_overhead, 0, flags); - dev_kfree_skb_any(skb); - skb = skb2; - if( !skb ) - return NULL; - } - - __skb_push(skb, tx_overhead); - /* usbnet adds padding if length is a multiple of packet size - if so, adjust length value in header */ - if( (skb->len % dev->maxpacket) == 0 ) { - len++; - } - - if( product_id == CH9x00_PID_E091 || - product_id == CH9x00_PID_8339 ) { - skb->data[0] = len; - skb->data[1] = len >> 8; - skb->data[2] = 0x00; - skb->data[3] = 0x00; - } - else if( product_id == CH9x00_PID_E092 ) { - skb->data[0] = len; - skb->data[1] = len >> 8; - skb->data[2] = 0x00; - skb->data[3] = 0x80; - - for( i = 4; i < 48; i++ ) - skb->data[i] = 0x00; - - skb->data[48] = len; - skb->data[49] = len >> 8; - skb->data[50] = 0x00; - skb->data[51] = 0x80; - - for( i = 52; i < 64; i++ ) - skb->data[i] = 0x00; - } - - return skb; -} - - -static int ch9x00_rx_fixup( struct usbnet *dev, struct sk_buff *skb ) -{ - int len = 0; - int rx_overhead = 0; - int product_id = dev->udev->descriptor.idProduct; - - if( product_id == CH9x00_PID_E091 || - product_id == CH9x00_PID_8339 ) { - rx_overhead = RX_OVERHEAD; - - if( unlikely(skb->len < rx_overhead) ) { - dev_err( &dev->udev->dev, "unexpected tiny rx frame\n"); - return 0; - } - - len = (skb->data[0] | skb->data[1] << 8 ); - - skb_pull(skb, rx_overhead); - skb_trim(skb, len); - } - else if( product_id == CH9x00_PID_E092 ) { - // Do nothing here - rx_overhead = 64; - - if( unlikely(skb->len < rx_overhead) ) { - dev_err( &dev->udev->dev, "unexpected tiny rx frame\n"); - return 0; - } - - len = (skb->data[skb->len - 16] | skb->data[skb->len - 15] << 8 ); - /*printk("rx_fixup skb->len=%d, len=%d\n", skb->len, len );*/ - - /*skb_pull(skb, rx_overhead);*/ - skb_trim(skb, len); - } - - return 1; -} - - -static int get_mac_address( struct usbnet *dev, unsigned char *data ) -{ - int err = 0; - //for E092 - unsigned char mac_addr[0x06]; - int rd_mac_len = 0; - - dbg_prt("\n--> get_mac_address:\n\tusbnet VID:%0x PID:%0x\n", - dev->udev->descriptor.idVendor, - dev->udev->descriptor.idProduct); - - if( dev->udev->descriptor.idProduct == CH9x00_PID_E091 || - dev->udev->descriptor.idProduct == CH9x00_PID_8339 ) - err = control_read( dev, GET_MAC_ADDRESS, REQ_RD_REG, - 0, 0, data, 0x06, CTRL_TIMEOUT_MS ); - else if( dev->udev->descriptor.idProduct == CH9x00_PID_E092 ) { - memset( mac_addr, 0, sizeof(mac_addr) ); - rd_mac_len = control_read( dev, REQUEST_READ, REQUEST_TYPE_READ, - 0, MAC_REG_STATION_L, mac_addr, 0x02, CONTROL_TIMEOUT_MS ); - rd_mac_len += control_read( dev, REQUEST_READ, REQUEST_TYPE_READ, - 0, MAC_REG_STATION_M, mac_addr+2, 0x02, CONTROL_TIMEOUT_MS ); - rd_mac_len += control_read( dev, REQUEST_READ, REQUEST_TYPE_READ, - 0, MAC_REG_STATION_H, mac_addr+4, 0x02, CONTROL_TIMEOUT_MS ); - if( rd_mac_len != ETH_ALEN ) - err = -EINVAL; - //Set MAC - data[0] = mac_addr[5]; - data[1] = mac_addr[4]; - data[2] = mac_addr[3]; - data[3] = mac_addr[2]; - data[4] = mac_addr[1]; - data[5] = mac_addr[0]; - } - - if( err < 0 ) - goto err_out; - - return 0; - -err_out: - return err; -} - - -static int ch9x00_bind( struct usbnet *dev, struct usb_interface *intf ) -{ - int retval = 0; - unsigned char data[2]; - - //int vendor_id = dev->udev->descriptor.idVendor; - int product_id = dev->udev->descriptor.idProduct; - - retval = usbnet_get_endpoints(dev, intf); - if(retval) - goto err_out; - - // compatibility of E091 and E092 - if( product_id == CH9x00_PID_E091 || - product_id == CH9x00_PID_8339 ) { - if( (retval = get_mac_address(dev, dev->net->dev_addr)) < 0 ) { - return retval; - goto err_out; - } - } - - // Initialize MII structure for Setting Speed Duplex - dev->mii.dev = dev->net; - dev->mii.mdio_read = ch9x00_mdio_read; - dev->mii.mdio_write = ch9x00_mdio_write; - dev->mii.reg_num_mask = 0x1f; - - if( product_id == CH9x00_PID_E091 || - product_id == CH9x00_PID_8339 ) { - dev->mii.phy_id_mask = 0x3f; - /*dev->rx_urb_size = dev->net->mtu + 14 + RX_OVERHEAD;*/ - // Note: Max package length=1518 (MTU + ETH_HELN + RX_OVERHEAD) - dev->rx_urb_size = dev->net->mtu + ETH_HLEN + RX_OVERHEAD; - // Adaptor can restart, when driver rmmoded or insmoded - mii_nway_restart( &dev->mii ); - } - else if( product_id == CH9x00_PID_E092 ) { - dev->mii.phy_id_mask = 0x1f; - - dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len; - // Note: Max package legth= 24*64 + 16 - dev->rx_urb_size = 24*64 + 16; - // Adaptor can restart, when driver rmmoded or insmoded - mii_nway_restart( &dev->mii ); - - // Initilization hardware - data[0] = 0x01; - data[1] = 0x0F; - retval = control_write( dev, REQUEST_WRITE, REQUEST_TYPE_WRITE, - 0, 88, data, 0x02, CONTROL_TIMEOUT_MS ); - - data[0] = 0xA0; - data[1] = 0x90; - retval = control_write( dev, REQUEST_WRITE, REQUEST_TYPE_WRITE, - 0, 90, data, 0x02, CONTROL_TIMEOUT_MS ); - - data[0] = 0x30; - data[1] = 0x00; - retval = control_write( dev, REQUEST_WRITE, REQUEST_TYPE_WRITE, - 0, 92, data, 0x02, CONTROL_TIMEOUT_MS ); - - data[0] = 0x17; - data[1] = 0xD8; - retval = control_write( dev, REQUEST_WRITE, REQUEST_TYPE_WRITE, - 0, 94, data, 0x02, CONTROL_TIMEOUT_MS ); - - data[0] = 0x01; - data[1] = 0x00; - retval = control_write( dev, REQUEST_WRITE, REQUEST_TYPE_WRITE, - 0, 254, data, 0x02, CONTROL_TIMEOUT_MS ); - - data[0] = 0x5F; // 0x0101 1111 - data[1] = 0x0D; // 0x0000 1101 - // Control Register Setting - retval = control_write( dev, REQUEST_WRITE, REQUEST_TYPE_WRITE, - 0, 64, data, 0x02, CONTROL_TIMEOUT_MS ); - - if( (retval = get_mac_address(dev, dev->net->dev_addr)) < 0 ) { - return retval; - goto err_out; - } - } - if( retval < 0 ) - goto err_out; - - return 0; - -err_out: - return retval; -} - - -static const struct driver_info ch9x00_info = { - .description = "CH9x00 USB to Network Adaptor", - .flags = FLAG_ETHER, - .bind = ch9x00_bind, - .rx_fixup = ch9x00_rx_fixup, - .tx_fixup = ch9x00_tx_fixup, - .status = ch9x00_status, - .link_reset = ch9x00_link_reset, - .reset = ch9x00_link_reset, -}; - -static const struct usb_device_id ch9x00_products[] = { - { - USB_DEVICE( 0x1A86, 0xE091 ), - .driver_info = (unsigned long)&ch9x00_info, - }, - { - USB_DEVICE( 0x1A86, 0xE092 ), - .driver_info = (unsigned long)&ch9x00_info, - }, - { USB_DEVICE( 0x1A86, 0x8339 ), - .driver_info = (unsigned long)&ch9x00_info, - }, - {}, -}; -MODULE_DEVICE_TABLE( usb, ch9x00_products ); - -static struct usb_driver ch9x00_driver = { - .name = "ch9x00", - .id_table = ch9x00_products, - .probe = usbnet_probe, - .disconnect = usbnet_disconnect, - .suspend = usbnet_suspend, - .resume = usbnet_resume, -}; - -static int __init ch9x00_init( void ) -{ - printk( KERN_INFO "\tCH9x00 Driver Version:%s\n", DRIVER_VERSION); - return usb_register( &ch9x00_driver ); -} - -static void __exit ch9x00_exit( void ) -{ - usb_deregister( &ch9x00_driver ); -} - -module_init( ch9x00_init ); -module_exit( ch9x00_exit ); - -MODULE_DESCRIPTION( "USB to Network adapter CH9x00" ); -MODULE_LICENSE( "GPL" ); diff --git a/ANDROID_3.4.5/drivers/net/usb/compatibility.h b/ANDROID_3.4.5/drivers/net/usb/compatibility.h deleted file mode 100755 index cb2ed9ae..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/compatibility.h +++ /dev/null @@ -1,387 +0,0 @@ -#ifndef LINUX_COMPATIBILITY_H -#define LINUX_COMPATIBILITY_H - -/* - * Definition and macro - */ - -#include <linux/init.h> -#include <linux/version.h> -#include <linux/in.h> - -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30) -#include <linux/mdio.h> -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) - #define NETIF_F_HW_VLAN_CTAG_RX NETIF_F_HW_VLAN_RX - #define NETIF_F_HW_VLAN_CTAG_TX NETIF_F_HW_VLAN_TX -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0) -/* - static inline __sum16 tcp_v6_check(int len, - const struct in6_addr *saddr, - const struct in6_addr *daddr, - wsum base) - { - return csum_ipv6_magic(saddr, daddr, len, IPPROTO_TCP, base); - }*/ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0) - #define eth_random_addr(addr) random_ether_addr(addr) -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0) - #define ETH_MDIO_SUPPORTS_C22 MDIO_SUPPORTS_C22 - - static inline void eth_hw_addr_random(struct net_device *dev) - { - random_ether_addr(dev->dev_addr); - } -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0) - #define module_usb_driver(__driver) \ - static int __init __driver##_init(void) \ - { \ - return usb_register(&(__driver)); \ - } \ - module_init(__driver##_init); \ - static void __exit __driver##_exit(void) \ - { \ - usb_deregister(&(__driver)); \ - } \ - module_exit(__driver##_exit); - - #define netdev_features_t u32 -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0) - #define PMSG_IS_AUTO(msg) (((msg).event & PM_EVENT_AUTO) != 0) - - static inline struct page *skb_frag_page(const skb_frag_t *frag) - { - return frag->page; - } - - static inline void *skb_frag_address(const skb_frag_t *frag) - { - return page_address(skb_frag_page(frag)) + frag->page_offset; - } - - static inline unsigned int skb_frag_size(const skb_frag_t *frag) - { - return frag->size; - } -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,1,0) - #define ndo_set_rx_mode ndo_set_multicast_list -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39) - #define NETIF_F_RXCSUM (1 << 29) /* Receive checksumming offload */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) - #define skb_checksum_none_assert(skb_ptr) (skb_ptr)->ip_summed = CHECKSUM_NONE -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) - static inline void usleep_range(unsigned long min, unsigned long max) - { - unsigned long ms = min / 1000; - - if (ms) - mdelay(ms); - - udelay(min % 1000); - } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) - static inline bool pci_dev_run_wake(struct pci_dev *dev) - { - return 1; - } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34) - #define netdev_mc_count(netdev) ((netdev)->mc_count) - #define netdev_mc_empty(netdev) (netdev_mc_count(netdev) == 0) - - #define netif_printk(priv, type, level, netdev, fmt, args...) \ - do { \ - if (netif_msg_##type(priv)) \ - printk(level "%s: " fmt,(netdev)->name , ##args); \ - } while (0) - - #define netif_emerg(priv, type, netdev, fmt, args...) \ - netif_printk(priv, type, KERN_EMERG, netdev, fmt, ##args) - #define netif_alert(priv, type, netdev, fmt, args...) \ - netif_printk(priv, type, KERN_ALERT, netdev, fmt, ##args) - #define netif_crit(priv, type, netdev, fmt, args...) \ - netif_printk(priv, type, KERN_CRIT, netdev, fmt, ##args) - #define netif_err(priv, type, netdev, fmt, args...) \ - netif_printk(priv, type, KERN_ERR, netdev, fmt, ##args) - #define netif_warn(priv, type, netdev, fmt, args...) \ - netif_printk(priv, type, KERN_WARNING, netdev, fmt, ##args) - #define netif_notice(priv, type, netdev, fmt, args...) \ - netif_printk(priv, type, KERN_NOTICE, netdev, fmt, ##args) - #define netif_info(priv, type, netdev, fmt, args...) \ - netif_printk(priv, type, KERN_INFO, (netdev), fmt, ##args) -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33) - #define get_sset_count get_stats_count -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) - #define pm_request_resume(para) - #define pm_runtime_set_suspended(para) - #define pm_schedule_suspend(para1, para2) - #define pm_runtime_get_sync(para) - #define pm_runtime_put_sync(para) - #define pm_runtime_put_noidle(para) - #define pm_runtime_idle(para) - #define pm_runtime_set_active(para) - #define pm_runtime_enable(para) - #define pm_runtime_disable(para) - typedef int netdev_tx_t; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31) - #define USB_SPEED_SUPER (USB_SPEED_VARIABLE + 1) -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) - static inline void usb_autopm_put_interface_async(struct usb_interface *intf) - { - struct usb_device *udev = interface_to_usbdev(intf); - int status = 0; - - if (intf->condition == USB_INTERFACE_UNBOUND) { - status = -ENODEV; - } else { - udev->last_busy = jiffies; - --intf->pm_usage_cnt; - if (udev->autosuspend_disabled || udev->autosuspend_delay < 0) - status = -EPERM; - } - } - - static inline int usb_autopm_get_interface_async(struct usb_interface *intf) - { - struct usb_device *udev = interface_to_usbdev(intf); - int status = 0; - - if (intf->condition == USB_INTERFACE_UNBOUND) - status = -ENODEV; - else if (udev->autoresume_disabled) - status = -EPERM; - else - ++intf->pm_usage_cnt; - return status; - } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) - static inline void __skb_queue_splice(const struct sk_buff_head *list, - struct sk_buff *prev, - struct sk_buff *next) - { - struct sk_buff *first = list->next; - struct sk_buff *last = list->prev; - - first->prev = prev; - prev->next = first; - - last->next = next; - next->prev = last; - } - - static inline void skb_queue_splice(const struct sk_buff_head *list, - struct sk_buff_head *head) - { - if (!skb_queue_empty(list)) { - __skb_queue_splice(list, (struct sk_buff *) head, head->next); - head->qlen += list->qlen; - } - } - - static inline void __skb_queue_head_init(struct sk_buff_head *list) - { - list->prev = list->next = (struct sk_buff *)list; - list->qlen = 0; - } - - static inline void skb_queue_splice_init(struct sk_buff_head *list, - struct sk_buff_head *head) - { - if (!skb_queue_empty(list)) { - __skb_queue_splice(list, (struct sk_buff *) head, head->next); - head->qlen += list->qlen; - __skb_queue_head_init(list); - } - } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) - #define PM_EVENT_AUTO 0x0400 -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) - #define napi_enable(napi_ptr) netif_poll_enable(tp->dev) - #define napi_disable(napi_ptr) netif_poll_disable(tp->dev) - #define napi_schedule(napi_ptr) netif_rx_schedule(tp->dev) - #define napi_complete(napi_ptr) netif_rx_complete(tp->dev) - #define netif_napi_del(napi_ptr) - #define netif_napi_add(ndev, napi_ptr, function, weight_t) \ - ndev->poll = function; \ - ndev->weight = weight_t; - typedef unsigned long uintptr_t; - #define DMA_BIT_MASK(value) \ - (value < 64 ? ((1ULL << value) - 1) : 0xFFFFFFFFFFFFFFFFULL) -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) - #define NETIF_F_IPV6_CSUM 16 - #define cancel_delayed_work_sync cancel_delayed_work - - static inline int skb_cow_head(struct sk_buff *skb, unsigned int headroom) - { - int delta = 0; - - if (headroom > skb_headroom(skb)) - delta = headroom - skb_headroom(skb); - - if (delta || skb_header_cloned(skb)) - return pskb_expand_head(skb, ALIGN(delta, NET_SKB_PAD), 0, - GFP_ATOMIC); - return 0; - } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) - #define ip_hdr(skb_ptr) (skb_ptr)->nh.iph - #define ipv6hdr(skb_ptr) (skb_ptr)->nh.ipv6h -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21) - #define vlan_group_set_device(vlgrp, vid, value) \ - if (vlgrp) \ - vlgrp->vlan_devices[vid] = value; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) - #define delayed_work work_struct - #define INIT_DELAYED_WORK(a,b) INIT_WORK(a,b,tp) -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) - #define CHECKSUM_PARTIAL CHECKSUM_HW - - static inline void *kmemdup(const void *src, size_t len, gfp_t gfp) - { - void *p; - - p = kmalloc_track_caller(len, gfp); - if (p) - memcpy(p, src, len); - return p; - } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) - #define skb_is_gso(skb_ptr) skb_shinfo(skb_ptr)->tso_size - #define netdev_alloc_skb(dev, len) dev_alloc_skb(len) - #define IRQF_SHARED SA_SHIRQ - - static inline struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features) - { - return NULL; - } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) -#ifndef __LINUX_MUTEX_H - #define mutex semaphore - #define mutex_lock down - #define mutex_unlock up - #define mutex_lock_interruptible down_interruptible - #define mutex_init init_MUTEX -#endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) - #define ADVERTISED_Pause (1 << 13) - #define ADVERTISED_Asym_Pause (1 << 14) -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) - #define skb_header_cloned(skb) skb_cloned(skb) -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) */ -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) */ -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) */ -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) */ -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) */ -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) */ -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21) */ -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) */ -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) */ -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) */ -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) */ -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) */ -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) */ -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31) */ -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) */ -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33) */ -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34) */ -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) */ -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) */ -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) */ -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39) */ -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,1,0) */ -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0) */ -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0) */ -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0) */ -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0) */ -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0) */ -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) */ - -#ifndef FALSE - #define TRUE 1 - #define FALSE 0 -#endif - -/* - * inline function - */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33) -static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev, - unsigned int length) -{ - struct sk_buff *skb = netdev_alloc_skb(dev, length + NET_IP_ALIGN); - - if (NET_IP_ALIGN && skb) - skb_reserve(skb, NET_IP_ALIGN); - return skb; -} -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) -static inline void skb_copy_from_linear_data(const struct sk_buff *skb, - void *to, - const unsigned int len) -{ - memcpy(to, skb->data, len); -} -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) */ -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33) */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23) -/** - * netif_napi_del - remove a napi context - * @napi: napi context - * - * netif_napi_del() removes a napi context from the network device napi list - */ -static inline void netif_napi_del(struct napi_struct *napi) -{ -#ifdef CONFIG_NETPOLL - list_del(&napi->dev_list); -#endif -} -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31) - #define skb_tx_timestamp(skb) (tp->netdev->trans_start = jiffies) -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) - #define skb_tx_timestamp(skb) -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31) */ - -enum rtl_cmd { - RTLTOOL_PLA_OCP_READ_DWORD = 0, - RTLTOOL_PLA_OCP_WRITE_DWORD, - RTLTOOL_USB_OCP_READ_DWORD, - RTLTOOL_USB_OCP_WRITE_DWORD, - RTLTOOL_PLA_OCP_READ, - RTLTOOL_PLA_OCP_WRITE, - RTLTOOL_USB_OCP_READ, - RTLTOOL_USB_OCP_WRITE, - RTLTOOL_USB_INFO, - RTL_ENABLE_USB_DIAG, - RTL_DISABLE_USB_DIAG, - - RTLTOOL_INVALID -}; - -struct usb_device_info { - __u16 idVendor; - __u16 idProduct; - __u16 bcdDevice; - __u8 dev_addr[8]; - char devpath[16]; -}; - -struct rtltool_cmd { - __u32 cmd; - __u32 offset; - __u32 byteen; - __u32 data; - void *buf; - struct usb_device_info nic_info; - struct sockaddr ifru_addr; - struct sockaddr ifru_netmask; - struct sockaddr ifru_hwaddr; -}; - -#endif /* LINUX_COMPATIBILITY_H */ diff --git a/ANDROID_3.4.5/drivers/net/usb/cx82310_eth.c b/ANDROID_3.4.5/drivers/net/usb/cx82310_eth.c deleted file mode 100644 index 0e053135..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/cx82310_eth.c +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Driver for USB ethernet port of Conexant CX82310-based ADSL routers - * Copyright (C) 2010 by Ondrej Zary - * some parts inspired by the cxacru driver - * - * 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/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/usbnet.h> - -enum cx82310_cmd { - CMD_START = 0x84, /* no effect? */ - CMD_STOP = 0x85, /* no effect? */ - CMD_GET_STATUS = 0x90, /* returns nothing? */ - CMD_GET_MAC_ADDR = 0x91, /* read MAC address */ - CMD_GET_LINK_STATUS = 0x92, /* not useful, link is always up */ - CMD_ETHERNET_MODE = 0x99, /* unknown, needed during init */ -}; - -enum cx82310_status { - STATUS_UNDEFINED, - STATUS_SUCCESS, - STATUS_ERROR, - STATUS_UNSUPPORTED, - STATUS_UNIMPLEMENTED, - STATUS_PARAMETER_ERROR, - STATUS_DBG_LOOPBACK, -}; - -#define CMD_PACKET_SIZE 64 -/* first command after power on can take around 8 seconds */ -#define CMD_TIMEOUT 15000 -#define CMD_REPLY_RETRY 5 - -#define CX82310_MTU 1514 -#define CMD_EP 0x01 - -/* - * execute control command - * - optionally send some data (command parameters) - * - optionally wait for the reply - * - optionally read some data from the reply - */ -static int cx82310_cmd(struct usbnet *dev, enum cx82310_cmd cmd, bool reply, - u8 *wdata, int wlen, u8 *rdata, int rlen) -{ - int actual_len, retries, ret; - struct usb_device *udev = dev->udev; - u8 *buf = kzalloc(CMD_PACKET_SIZE, GFP_KERNEL); - - if (!buf) - return -ENOMEM; - - /* create command packet */ - buf[0] = cmd; - if (wdata) - memcpy(buf + 4, wdata, min_t(int, wlen, CMD_PACKET_SIZE - 4)); - - /* send command packet */ - ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, CMD_EP), buf, - CMD_PACKET_SIZE, &actual_len, CMD_TIMEOUT); - if (ret < 0) { - dev_err(&dev->udev->dev, "send command %#x: error %d\n", - cmd, ret); - goto end; - } - - if (reply) { - /* wait for reply, retry if it's empty */ - for (retries = 0; retries < CMD_REPLY_RETRY; retries++) { - ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, CMD_EP), - buf, CMD_PACKET_SIZE, &actual_len, - CMD_TIMEOUT); - if (ret < 0) { - dev_err(&dev->udev->dev, - "reply receive error %d\n", ret); - goto end; - } - if (actual_len > 0) - break; - } - if (actual_len == 0) { - dev_err(&dev->udev->dev, "no reply to command %#x\n", - cmd); - ret = -EIO; - goto end; - } - if (buf[0] != cmd) { - dev_err(&dev->udev->dev, - "got reply to command %#x, expected: %#x\n", - buf[0], cmd); - ret = -EIO; - goto end; - } - if (buf[1] != STATUS_SUCCESS) { - dev_err(&dev->udev->dev, "command %#x failed: %#x\n", - cmd, buf[1]); - ret = -EIO; - goto end; - } - if (rdata) - memcpy(rdata, buf + 4, - min_t(int, rlen, CMD_PACKET_SIZE - 4)); - } -end: - kfree(buf); - return ret; -} - -#define partial_len data[0] /* length of partial packet data */ -#define partial_rem data[1] /* remaining (missing) data length */ -#define partial_data data[2] /* partial packet data */ - -static int cx82310_bind(struct usbnet *dev, struct usb_interface *intf) -{ - int ret; - char buf[15]; - struct usb_device *udev = dev->udev; - - /* avoid ADSL modems - continue only if iProduct is "USB NET CARD" */ - if (usb_string(udev, udev->descriptor.iProduct, buf, sizeof(buf)) > 0 - && strcmp(buf, "USB NET CARD")) { - dev_info(&udev->dev, "ignoring: probably an ADSL modem\n"); - return -ENODEV; - } - - ret = usbnet_get_endpoints(dev, intf); - if (ret) - return ret; - - /* - * this must not include ethernet header as the device can send partial - * packets with no header (and sometimes even empty URBs) - */ - dev->net->hard_header_len = 0; - /* we can send at most 1514 bytes of data (+ 2-byte header) per URB */ - dev->hard_mtu = CX82310_MTU + 2; - /* we can receive URBs up to 4KB from the device */ - dev->rx_urb_size = 4096; - - dev->partial_data = (unsigned long) kmalloc(dev->hard_mtu, GFP_KERNEL); - if (!dev->partial_data) - return -ENOMEM; - - /* enable ethernet mode (?) */ - ret = cx82310_cmd(dev, CMD_ETHERNET_MODE, true, "\x01", 1, NULL, 0); - if (ret) { - dev_err(&udev->dev, "unable to enable ethernet mode: %d\n", - ret); - goto err; - } - - /* get the MAC address */ - ret = cx82310_cmd(dev, CMD_GET_MAC_ADDR, true, NULL, 0, - dev->net->dev_addr, ETH_ALEN); - if (ret) { - dev_err(&udev->dev, "unable to read MAC address: %d\n", ret); - goto err; - } - - /* start (does not seem to have any effect?) */ - ret = cx82310_cmd(dev, CMD_START, false, NULL, 0, NULL, 0); - if (ret) - goto err; - - return 0; -err: - kfree((void *)dev->partial_data); - return ret; -} - -static void cx82310_unbind(struct usbnet *dev, struct usb_interface *intf) -{ - kfree((void *)dev->partial_data); -} - -/* - * RX is NOT easy - we can receive multiple packets per skb, each having 2-byte - * packet length at the beginning. - * The last packet might be incomplete (when it crosses the 4KB URB size), - * continuing in the next skb (without any headers). - * If a packet has odd length, there is one extra byte at the end (before next - * packet or at the end of the URB). - */ -static int cx82310_rx_fixup(struct usbnet *dev, struct sk_buff *skb) -{ - int len; - struct sk_buff *skb2; - - /* - * If the last skb ended with an incomplete packet, this skb contains - * end of that packet at the beginning. - */ - if (dev->partial_rem) { - len = dev->partial_len + dev->partial_rem; - skb2 = alloc_skb(len, GFP_ATOMIC); - if (!skb2) - return 0; - skb_put(skb2, len); - memcpy(skb2->data, (void *)dev->partial_data, - dev->partial_len); - memcpy(skb2->data + dev->partial_len, skb->data, - dev->partial_rem); - usbnet_skb_return(dev, skb2); - skb_pull(skb, (dev->partial_rem + 1) & ~1); - dev->partial_rem = 0; - if (skb->len < 2) - return 1; - } - - /* a skb can contain multiple packets */ - while (skb->len > 1) { - /* first two bytes are packet length */ - len = skb->data[0] | (skb->data[1] << 8); - skb_pull(skb, 2); - - /* if last packet in the skb, let usbnet to process it */ - if (len == skb->len || len + 1 == skb->len) { - skb_trim(skb, len); - break; - } - - if (len > CX82310_MTU) { - dev_err(&dev->udev->dev, "RX packet too long: %d B\n", - len); - return 0; - } - - /* incomplete packet, save it for the next skb */ - if (len > skb->len) { - dev->partial_len = skb->len; - dev->partial_rem = len - skb->len; - memcpy((void *)dev->partial_data, skb->data, - dev->partial_len); - skb_pull(skb, skb->len); - break; - } - - skb2 = alloc_skb(len, GFP_ATOMIC); - if (!skb2) - return 0; - skb_put(skb2, len); - memcpy(skb2->data, skb->data, len); - /* process the packet */ - usbnet_skb_return(dev, skb2); - - skb_pull(skb, (len + 1) & ~1); - } - - /* let usbnet process the last packet */ - return 1; -} - -/* TX is easy, just add 2 bytes of length at the beginning */ -static struct sk_buff *cx82310_tx_fixup(struct usbnet *dev, struct sk_buff *skb, - gfp_t flags) -{ - int len = skb->len; - - if (skb_headroom(skb) < 2) { - struct sk_buff *skb2 = skb_copy_expand(skb, 2, 0, flags); - dev_kfree_skb_any(skb); - skb = skb2; - if (!skb) - return NULL; - } - skb_push(skb, 2); - - skb->data[0] = len; - skb->data[1] = len >> 8; - - return skb; -} - - -static const struct driver_info cx82310_info = { - .description = "Conexant CX82310 USB ethernet", - .flags = FLAG_ETHER, - .bind = cx82310_bind, - .unbind = cx82310_unbind, - .rx_fixup = cx82310_rx_fixup, - .tx_fixup = cx82310_tx_fixup, -}; - -#define USB_DEVICE_CLASS(vend, prod, cl, sc, pr) \ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ - USB_DEVICE_ID_MATCH_DEV_INFO, \ - .idVendor = (vend), \ - .idProduct = (prod), \ - .bDeviceClass = (cl), \ - .bDeviceSubClass = (sc), \ - .bDeviceProtocol = (pr) - -static const struct usb_device_id products[] = { - { - USB_DEVICE_CLASS(0x0572, 0xcb01, 0xff, 0, 0), - .driver_info = (unsigned long) &cx82310_info - }, - { }, -}; -MODULE_DEVICE_TABLE(usb, products); - -static struct usb_driver cx82310_driver = { - .name = "cx82310_eth", - .id_table = products, - .probe = usbnet_probe, - .disconnect = usbnet_disconnect, - .suspend = usbnet_suspend, - .resume = usbnet_resume, -}; - -module_usb_driver(cx82310_driver); - -MODULE_AUTHOR("Ondrej Zary"); -MODULE_DESCRIPTION("Conexant CX82310-based ADSL router USB ethernet driver"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/net/usb/dm9601.c b/ANDROID_3.4.5/drivers/net/usb/dm9601.c deleted file mode 100644 index b9722631..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/dm9601.c +++ /dev/null @@ -1,679 +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 <linux/usb/usbnet.h> -#include <linux/slab.h> - -/* datasheet: - http://ptm2.cc.utu.fi/ftp/network/cards/DM9601/From_NET/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) -{ - void *buf; - int err = -ENOMEM; - - netdev_dbg(dev->net, "dm_read() reg=0x%02x length=%d\n", reg, length); - - buf = kmalloc(length, GFP_KERNEL); - if (!buf) - goto out; - - err = usb_control_msg(dev->udev, - usb_rcvctrlpipe(dev->udev, 0), - DM_READ_REGS, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, reg, buf, length, USB_CTRL_SET_TIMEOUT); - if (err == length) - memcpy(data, buf, length); - else if (err >= 0) - err = -EINVAL; - kfree(buf); - - out: - return err; -} - -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) -{ - void *buf = NULL; - int err = -ENOMEM; - - netdev_dbg(dev->net, "dm_write() reg=0x%02x, length=%d\n", reg, length); - - if (data) { - buf = kmemdup(data, length, GFP_KERNEL); - if (!buf) - goto out; - } - - err = usb_control_msg(dev->udev, - usb_sndctrlpipe(dev->udev, 0), - DM_WRITE_REGS, - USB_DIR_OUT | USB_TYPE_VENDOR |USB_RECIP_DEVICE, - 0, reg, buf, length, USB_CTRL_SET_TIMEOUT); - kfree(buf); - if (err >= 0 && err < length) - err = -EINVAL; - out: - return err; -} - -static int dm_write_reg(struct usbnet *dev, u8 reg, u8 value) -{ - netdev_dbg(dev->net, "dm_write_reg() reg=0x%02x, value=0x%02x\n", - 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; - int status = urb->status; - - if (status < 0) - printk(KERN_DEBUG "dm_write_async_callback() failed with %d\n", - status); - - kfree(req); - usb_free_urb(urb); -} - -static void dm_write_async_helper(struct usbnet *dev, u8 reg, u8 value, - u16 length, void *data) -{ - struct usb_ctrlrequest *req; - struct urb *urb; - int status; - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) { - netdev_err(dev->net, "Error allocating URB in dm_write_async_helper!\n"); - return; - } - - req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); - if (!req) { - netdev_err(dev->net, "Failed to allocate memory for control request\n"); - usb_free_urb(urb); - return; - } - - req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; - req->bRequest = length ? DM_WRITE_REGS : DM_WRITE_REG; - req->wValue = cpu_to_le16(value); - 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) { - netdev_err(dev->net, "Error submitting the control message: status=%d\n", - status); - kfree(req); - usb_free_urb(urb); - } -} - -static void dm_write_async(struct usbnet *dev, u8 reg, u16 length, void *data) -{ - netdev_dbg(dev->net, "dm_write_async() reg=0x%02x length=%d\n", reg, length); - - dm_write_async_helper(dev, reg, 0, length, data); -} - -static void dm_write_reg_async(struct usbnet *dev, u8 reg, u8 value) -{ - netdev_dbg(dev->net, "dm_write_reg_async() reg=0x%02x value=0x%02x\n", - reg, value); - - dm_write_async_helper(dev, reg, value, 0, NULL); -} - -static int dm_read_shared_word(struct usbnet *dev, int phy, u8 reg, __le16 *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) { - netdev_err(dev->net, "%s read timed out!\n", phy ? "phy" : "eeprom"); - ret = -EIO; - goto out; - } - - dm_write_reg(dev, DM_SHARED_CTRL, 0x0); - ret = dm_read(dev, DM_SHARED_DATA, 2, value); - - netdev_dbg(dev->net, "read shared %d 0x%02x returned 0x%04x, %d\n", - 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, __le16 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 ? 0x1a : 0x12); - - 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) { - netdev_err(dev->net, "%s write timed out!\n", 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); - __le16 *ebuf = (__le16 *) 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); - - __le16 res; - - if (phy_id) { - netdev_dbg(dev->net, "Only internal phy supported\n"); - return 0; - } - - dm_read_shared_word(dev, 1, loc, &res); - - netdev_dbg(dev->net, - "dm9601_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n", - 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); - __le16 res = cpu_to_le16(val); - - if (phy_id) { - netdev_dbg(dev->net, "Only internal phy supported\n"); - return; - } - - netdev_dbg(dev->net, "dm9601_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n", - 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 const 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 = 0x31; - - memset(hashes, 0x00, DM_MCAST_SIZE); - hashes[DM_MCAST_SIZE - 1] |= 0x80; /* broadcast address */ - - if (net->flags & IFF_PROMISC) { - rx_ctl |= 0x02; - } else if (net->flags & IFF_ALLMULTI || - netdev_mc_count(net) > DM_MAX_MCAST) { - rx_ctl |= 0x04; - } else if (!netdev_mc_empty(net)) { - struct netdev_hw_addr *ha; - - netdev_for_each_mc_addr(ha, net) { - u32 crc = ether_crc(ETH_ALEN, ha->addr) >> 26; - hashes[crc >> 3] |= 1 << (crc & 0x7); - } - } - - dm_write_async(dev, DM_MCAST_ADDR, DM_MCAST_SIZE, hashes); - dm_write_reg_async(dev, DM_RX_CTRL, rx_ctl); -} - -static void __dm9601_set_mac_address(struct usbnet *dev) -{ - dm_write_async(dev, DM_PHY_ADDR, ETH_ALEN, dev->net->dev_addr); -} - -static int dm9601_set_mac_address(struct net_device *net, void *p) -{ - struct sockaddr *addr = p; - struct usbnet *dev = netdev_priv(net); - - if (!is_valid_ether_addr(addr->sa_data)) { - dev_err(&net->dev, "not setting invalid mac address %pM\n", - addr->sa_data); - return -EINVAL; - } - - memcpy(net->dev_addr, addr->sa_data, net->addr_len); - __dm9601_set_mac_address(dev); - - return 0; -} - -static const struct net_device_ops dm9601_netdev_ops = { - .ndo_open = usbnet_open, - .ndo_stop = usbnet_stop, - .ndo_start_xmit = usbnet_start_xmit, - .ndo_tx_timeout = usbnet_tx_timeout, - .ndo_change_mtu = usbnet_change_mtu, - .ndo_validate_addr = eth_validate_addr, - .ndo_do_ioctl = dm9601_ioctl, - .ndo_set_rx_mode = dm9601_set_multicast, - .ndo_set_mac_address = dm9601_set_mac_address, -}; - -static int dm9601_bind(struct usbnet *dev, struct usb_interface *intf) -{ - int ret; - u8 mac[ETH_ALEN]; - - ret = usbnet_get_endpoints(dev, intf); - if (ret) - goto out; - - dev->net->netdev_ops = &dm9601_netdev_ops; - 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 + ETH_HLEN + 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 */ - dm_write_reg(dev, DM_NET_CTRL, 1); - udelay(20); - - /* read MAC */ - if (dm_read(dev, DM_PHY_ADDR, ETH_ALEN, mac) < 0) { - printk(KERN_ERR "Error reading MAC address\n"); - ret = -ENODEV; - goto out; - } - - /* - * Overwrite the auto-generated address only with good ones. - */ - if (is_valid_ether_addr(mac)) - memcpy(dev->net->dev_addr, mac, ETH_ALEN); - else { - printk(KERN_WARNING - "dm9601: No valid MAC address in EEPROM, using %pM\n", - dev->net->dev_addr); - __dm9601_set_mac_address(dev); - } - - /* 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: - b1: rx status - b2: packet length (incl crc) low - b3: packet length (incl crc) high - b4..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->net->stats.rx_fifo_errors++; - if (status & 0x02) dev->net->stats.rx_crc_errors++; - if (status & 0x04) dev->net->stats.rx_frame_errors++; - if (status & 0x20) dev->net->stats.rx_missed_errors++; - if (status & 0x90) dev->net->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: - b1: packet length low - b2: packet length high - b3..n: packet data - */ - - len = skb->len; - - 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); - - /* usbnet adds padding if length is a multiple of packet size - if so, adjust length value in header */ - if ((skb->len % dev->maxpacket) == 0) - len++; - - 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); - netdev_dbg(dev->net, "Link Status is: %d\n", link); - } -} - -static int dm9601_link_reset(struct usbnet *dev) -{ - struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; - - mii_check_media(&dev->mii, 1, 1); - mii_ethtool_gset(&dev->mii, &ecmd); - - netdev_dbg(dev->net, "link_reset() speed: %u duplex: %d\n", - ethtool_cmd_speed(&ecmd), ecmd.duplex); - - return 0; -} - -static const struct driver_info dm9601_info = { - .description = "Davicom DM9601 USB Ethernet", - .flags = FLAG_ETHER | FLAG_LINK_INTR, - .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, - }, - { - USB_DEVICE(0x0a46, 0x8515), /* ADMtek ADM8515 USB NIC */ - .driver_info = (unsigned long)&dm9601_info, - }, - { - USB_DEVICE(0x0a47, 0x9601), /* Hirose USB-100 */ - .driver_info = (unsigned long)&dm9601_info, - }, - { - USB_DEVICE(0x0fe6, 0x8101), /* DM9601 USB to Fast Ethernet Adapter */ - .driver_info = (unsigned long)&dm9601_info, - }, - { - USB_DEVICE(0x0fe6, 0x9700), /* DM9601 USB to Fast Ethernet Adapter */ - .driver_info = (unsigned long)&dm9601_info, - }, - { - USB_DEVICE(0x0a46, 0x9000), /* DM9000E */ - .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, -}; - -module_usb_driver(dm9601_driver); - -MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>"); -MODULE_DESCRIPTION("Davicom DM9601 USB 1.1 ethernet devices"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/net/usb/gl620a.c b/ANDROID_3.4.5/drivers/net/usb/gl620a.c deleted file mode 100644 index 38266bda..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/gl620a.c +++ /dev/null @@ -1,235 +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 <linux/usb/usbnet.h> -#include <linux/gfp.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_POINTTOPOINT | 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, -}; - -module_usb_driver(gl620a_driver); - -MODULE_AUTHOR("Jiun-Jie Huang"); -MODULE_DESCRIPTION("GL620-USB-A Host-to-Host Link cables"); -MODULE_LICENSE("GPL"); - diff --git a/ANDROID_3.4.5/drivers/net/usb/hso.c b/ANDROID_3.4.5/drivers/net/usb/hso.c deleted file mode 100644 index 2d2a6882..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/hso.c +++ /dev/null @@ -1,3380 +0,0 @@ -/****************************************************************************** - * - * Driver for Option High Speed Mobile Devices. - * - * Copyright (C) 2008 Option International - * Filip Aben <f.aben@option.com> - * Denis Joseph Barrow <d.barow@option.com> - * Jan Dumon <j.dumon@option.com> - * Copyright (C) 2007 Andrew Bird (Sphere Systems Ltd) - * <ajb@spheresystems.co.uk> - * Copyright (C) 2008 Greg Kroah-Hartman <gregkh@suse.de> - * Copyright (C) 2008 Novell, Inc. - * - * 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. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA - * - * - *****************************************************************************/ - -/****************************************************************************** - * - * Description of the device: - * - * Interface 0: Contains the IP network interface on the bulk end points. - * The multiplexed serial ports are using the interrupt and - * control endpoints. - * Interrupt contains a bitmap telling which multiplexed - * serialport needs servicing. - * - * Interface 1: Diagnostics port, uses bulk only, do not submit urbs until the - * port is opened, as this have a huge impact on the network port - * throughput. - * - * Interface 2: Standard modem interface - circuit switched interface, this - * can be used to make a standard ppp connection however it - * should not be used in conjunction with the IP network interface - * enabled for USB performance reasons i.e. if using this set - * ideally disable_net=1. - * - *****************************************************************************/ - -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/netdevice.h> -#include <linux/module.h> -#include <linux/ethtool.h> -#include <linux/usb.h> -#include <linux/timer.h> -#include <linux/tty.h> -#include <linux/tty_driver.h> -#include <linux/tty_flip.h> -#include <linux/kmod.h> -#include <linux/rfkill.h> -#include <linux/ip.h> -#include <linux/uaccess.h> -#include <linux/usb/cdc.h> -#include <net/arp.h> -#include <asm/byteorder.h> -#include <linux/serial_core.h> -#include <linux/serial.h> - - -#define MOD_AUTHOR "Option Wireless" -#define MOD_DESCRIPTION "USB High Speed Option driver" -#define MOD_LICENSE "GPL" - -#define HSO_MAX_NET_DEVICES 10 -#define HSO__MAX_MTU 2048 -#define DEFAULT_MTU 1500 -#define DEFAULT_MRU 1500 - -#define CTRL_URB_RX_SIZE 1024 -#define CTRL_URB_TX_SIZE 64 - -#define BULK_URB_RX_SIZE 4096 -#define BULK_URB_TX_SIZE 8192 - -#define MUX_BULK_RX_BUF_SIZE HSO__MAX_MTU -#define MUX_BULK_TX_BUF_SIZE HSO__MAX_MTU -#define MUX_BULK_RX_BUF_COUNT 4 -#define USB_TYPE_OPTION_VENDOR 0x20 - -/* These definitions are used with the struct hso_net flags element */ -/* - use *_bit operations on it. (bit indices not values.) */ -#define HSO_NET_RUNNING 0 - -#define HSO_NET_TX_TIMEOUT (HZ*10) - -#define HSO_SERIAL_MAGIC 0x48534f31 - -/* Number of ttys to handle */ -#define HSO_SERIAL_TTY_MINORS 256 - -#define MAX_RX_URBS 2 - -static inline struct hso_serial *get_serial_by_tty(struct tty_struct *tty) -{ - if (tty) - return tty->driver_data; - return NULL; -} - -/*****************************************************************************/ -/* Debugging functions */ -/*****************************************************************************/ -#define D__(lvl_, fmt, arg...) \ - do { \ - printk(lvl_ "[%d:%s]: " fmt "\n", \ - __LINE__, __func__, ## arg); \ - } while (0) - -#define D_(lvl, args...) \ - do { \ - if (lvl & debug) \ - D__(KERN_INFO, args); \ - } while (0) - -#define D1(args...) D_(0x01, ##args) -#define D2(args...) D_(0x02, ##args) -#define D3(args...) D_(0x04, ##args) -#define D4(args...) D_(0x08, ##args) -#define D5(args...) D_(0x10, ##args) - -/*****************************************************************************/ -/* Enumerators */ -/*****************************************************************************/ -enum pkt_parse_state { - WAIT_IP, - WAIT_DATA, - WAIT_SYNC -}; - -/*****************************************************************************/ -/* Structs */ -/*****************************************************************************/ - -struct hso_shared_int { - struct usb_endpoint_descriptor *intr_endp; - void *shared_intr_buf; - struct urb *shared_intr_urb; - struct usb_device *usb; - int use_count; - int ref_count; - struct mutex shared_int_lock; -}; - -struct hso_net { - struct hso_device *parent; - struct net_device *net; - struct rfkill *rfkill; - - struct usb_endpoint_descriptor *in_endp; - struct usb_endpoint_descriptor *out_endp; - - struct urb *mux_bulk_rx_urb_pool[MUX_BULK_RX_BUF_COUNT]; - struct urb *mux_bulk_tx_urb; - void *mux_bulk_rx_buf_pool[MUX_BULK_RX_BUF_COUNT]; - void *mux_bulk_tx_buf; - - struct sk_buff *skb_rx_buf; - struct sk_buff *skb_tx_buf; - - enum pkt_parse_state rx_parse_state; - spinlock_t net_lock; - - unsigned short rx_buf_size; - unsigned short rx_buf_missing; - struct iphdr rx_ip_hdr; - - unsigned long flags; -}; - -enum rx_ctrl_state{ - RX_IDLE, - RX_SENT, - RX_PENDING -}; - -#define BM_REQUEST_TYPE (0xa1) -#define B_NOTIFICATION (0x20) -#define W_VALUE (0x0) -#define W_INDEX (0x2) -#define W_LENGTH (0x2) - -#define B_OVERRUN (0x1<<6) -#define B_PARITY (0x1<<5) -#define B_FRAMING (0x1<<4) -#define B_RING_SIGNAL (0x1<<3) -#define B_BREAK (0x1<<2) -#define B_TX_CARRIER (0x1<<1) -#define B_RX_CARRIER (0x1<<0) - -struct hso_serial_state_notification { - u8 bmRequestType; - u8 bNotification; - u16 wValue; - u16 wIndex; - u16 wLength; - u16 UART_state_bitmap; -} __packed; - -struct hso_tiocmget { - struct mutex mutex; - wait_queue_head_t waitq; - int intr_completed; - struct usb_endpoint_descriptor *endp; - struct urb *urb; - struct hso_serial_state_notification serial_state_notification; - u16 prev_UART_state_bitmap; - struct uart_icount icount; -}; - - -struct hso_serial { - struct hso_device *parent; - int magic; - u8 minor; - - struct hso_shared_int *shared_int; - - /* rx/tx urb could be either a bulk urb or a control urb depending - on which serial port it is used on. */ - struct urb *rx_urb[MAX_RX_URBS]; - u8 num_rx_urbs; - u8 *rx_data[MAX_RX_URBS]; - u16 rx_data_length; /* should contain allocated length */ - - struct urb *tx_urb; - u8 *tx_data; - u8 *tx_buffer; - u16 tx_data_length; /* should contain allocated length */ - u16 tx_data_count; - u16 tx_buffer_count; - struct usb_ctrlrequest ctrl_req_tx; - struct usb_ctrlrequest ctrl_req_rx; - - struct usb_endpoint_descriptor *in_endp; - struct usb_endpoint_descriptor *out_endp; - - enum rx_ctrl_state rx_state; - u8 rts_state; - u8 dtr_state; - unsigned tx_urb_used:1; - - /* from usb_serial_port */ - struct tty_struct *tty; - int open_count; - spinlock_t serial_lock; - - int (*write_data) (struct hso_serial *serial); - struct hso_tiocmget *tiocmget; - /* Hacks required to get flow control - * working on the serial receive buffers - * so as not to drop characters on the floor. - */ - int curr_rx_urb_idx; - u16 curr_rx_urb_offset; - u8 rx_urb_filled[MAX_RX_URBS]; - struct tasklet_struct unthrottle_tasklet; - struct work_struct retry_unthrottle_workqueue; -}; - -struct hso_device { - union { - struct hso_serial *dev_serial; - struct hso_net *dev_net; - } port_data; - - u32 port_spec; - - u8 is_active; - u8 usb_gone; - struct work_struct async_get_intf; - struct work_struct async_put_intf; - struct work_struct reset_device; - - struct usb_device *usb; - struct usb_interface *interface; - - struct device *dev; - struct kref ref; - struct mutex mutex; -}; - -/* Type of interface */ -#define HSO_INTF_MASK 0xFF00 -#define HSO_INTF_MUX 0x0100 -#define HSO_INTF_BULK 0x0200 - -/* Type of port */ -#define HSO_PORT_MASK 0xFF -#define HSO_PORT_NO_PORT 0x0 -#define HSO_PORT_CONTROL 0x1 -#define HSO_PORT_APP 0x2 -#define HSO_PORT_GPS 0x3 -#define HSO_PORT_PCSC 0x4 -#define HSO_PORT_APP2 0x5 -#define HSO_PORT_GPS_CONTROL 0x6 -#define HSO_PORT_MSD 0x7 -#define HSO_PORT_VOICE 0x8 -#define HSO_PORT_DIAG2 0x9 -#define HSO_PORT_DIAG 0x10 -#define HSO_PORT_MODEM 0x11 -#define HSO_PORT_NETWORK 0x12 - -/* Additional device info */ -#define HSO_INFO_MASK 0xFF000000 -#define HSO_INFO_CRC_BUG 0x01000000 - -/*****************************************************************************/ -/* Prototypes */ -/*****************************************************************************/ -/* Serial driver functions */ -static int hso_serial_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear); -static void ctrl_callback(struct urb *urb); -static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial); -static void hso_kick_transmit(struct hso_serial *serial); -/* Helper functions */ -static int hso_mux_submit_intr_urb(struct hso_shared_int *mux_int, - struct usb_device *usb, gfp_t gfp); -static void handle_usb_error(int status, const char *function, - struct hso_device *hso_dev); -static struct usb_endpoint_descriptor *hso_get_ep(struct usb_interface *intf, - int type, int dir); -static int hso_get_mux_ports(struct usb_interface *intf, unsigned char *ports); -static void hso_free_interface(struct usb_interface *intf); -static int hso_start_serial_device(struct hso_device *hso_dev, gfp_t flags); -static int hso_stop_serial_device(struct hso_device *hso_dev); -static int hso_start_net_device(struct hso_device *hso_dev); -static void hso_free_shared_int(struct hso_shared_int *shared_int); -static int hso_stop_net_device(struct hso_device *hso_dev); -static void hso_serial_ref_free(struct kref *ref); -static void hso_std_serial_read_bulk_callback(struct urb *urb); -static int hso_mux_serial_read(struct hso_serial *serial); -static void async_get_intf(struct work_struct *data); -static void async_put_intf(struct work_struct *data); -static int hso_put_activity(struct hso_device *hso_dev); -static int hso_get_activity(struct hso_device *hso_dev); -static void tiocmget_intr_callback(struct urb *urb); -static void reset_device(struct work_struct *data); -/*****************************************************************************/ -/* Helping functions */ -/*****************************************************************************/ - -/* #define DEBUG */ - -static inline struct hso_net *dev2net(struct hso_device *hso_dev) -{ - return hso_dev->port_data.dev_net; -} - -static inline struct hso_serial *dev2ser(struct hso_device *hso_dev) -{ - return hso_dev->port_data.dev_serial; -} - -/* Debugging functions */ -#ifdef DEBUG -static void dbg_dump(int line_count, const char *func_name, unsigned char *buf, - unsigned int len) -{ - static char name[255]; - - sprintf(name, "hso[%d:%s]", line_count, func_name); - print_hex_dump_bytes(name, DUMP_PREFIX_NONE, buf, len); -} - -#define DUMP(buf_, len_) \ - dbg_dump(__LINE__, __func__, (unsigned char *)buf_, len_) - -#define DUMP1(buf_, len_) \ - do { \ - if (0x01 & debug) \ - DUMP(buf_, len_); \ - } while (0) -#else -#define DUMP(buf_, len_) -#define DUMP1(buf_, len_) -#endif - -/* module parameters */ -static int debug; -static int tty_major; -static int disable_net; - -/* driver info */ -static const char driver_name[] = "hso"; -static const char tty_filename[] = "ttyHS"; -static const char *version = __FILE__ ": " MOD_AUTHOR; -/* the usb driver itself (registered in hso_init) */ -static struct usb_driver hso_driver; -/* serial structures */ -static struct tty_driver *tty_drv; -static struct hso_device *serial_table[HSO_SERIAL_TTY_MINORS]; -static struct hso_device *network_table[HSO_MAX_NET_DEVICES]; -static spinlock_t serial_table_lock; - -static const s32 default_port_spec[] = { - HSO_INTF_MUX | HSO_PORT_NETWORK, - HSO_INTF_BULK | HSO_PORT_DIAG, - HSO_INTF_BULK | HSO_PORT_MODEM, - 0 -}; - -static const s32 icon321_port_spec[] = { - HSO_INTF_MUX | HSO_PORT_NETWORK, - HSO_INTF_BULK | HSO_PORT_DIAG2, - HSO_INTF_BULK | HSO_PORT_MODEM, - HSO_INTF_BULK | HSO_PORT_DIAG, - 0 -}; - -#define default_port_device(vendor, product) \ - USB_DEVICE(vendor, product), \ - .driver_info = (kernel_ulong_t)default_port_spec - -#define icon321_port_device(vendor, product) \ - USB_DEVICE(vendor, product), \ - .driver_info = (kernel_ulong_t)icon321_port_spec - -/* list of devices we support */ -static const struct usb_device_id hso_ids[] = { - {default_port_device(0x0af0, 0x6711)}, - {default_port_device(0x0af0, 0x6731)}, - {default_port_device(0x0af0, 0x6751)}, - {default_port_device(0x0af0, 0x6771)}, - {default_port_device(0x0af0, 0x6791)}, - {default_port_device(0x0af0, 0x6811)}, - {default_port_device(0x0af0, 0x6911)}, - {default_port_device(0x0af0, 0x6951)}, - {default_port_device(0x0af0, 0x6971)}, - {default_port_device(0x0af0, 0x7011)}, - {default_port_device(0x0af0, 0x7031)}, - {default_port_device(0x0af0, 0x7051)}, - {default_port_device(0x0af0, 0x7071)}, - {default_port_device(0x0af0, 0x7111)}, - {default_port_device(0x0af0, 0x7211)}, - {default_port_device(0x0af0, 0x7251)}, - {default_port_device(0x0af0, 0x7271)}, - {default_port_device(0x0af0, 0x7311)}, - {default_port_device(0x0af0, 0xc031)}, /* Icon-Edge */ - {icon321_port_device(0x0af0, 0xd013)}, /* Module HSxPA */ - {icon321_port_device(0x0af0, 0xd031)}, /* Icon-321 */ - {icon321_port_device(0x0af0, 0xd033)}, /* Icon-322 */ - {USB_DEVICE(0x0af0, 0x7301)}, /* GE40x */ - {USB_DEVICE(0x0af0, 0x7361)}, /* GE40x */ - {USB_DEVICE(0x0af0, 0x7381)}, /* GE40x */ - {USB_DEVICE(0x0af0, 0x7401)}, /* GI 0401 */ - {USB_DEVICE(0x0af0, 0x7501)}, /* GTM 382 */ - {USB_DEVICE(0x0af0, 0x7601)}, /* GE40x */ - {USB_DEVICE(0x0af0, 0x7701)}, - {USB_DEVICE(0x0af0, 0x7706)}, - {USB_DEVICE(0x0af0, 0x7801)}, - {USB_DEVICE(0x0af0, 0x7901)}, - {USB_DEVICE(0x0af0, 0x7A01)}, - {USB_DEVICE(0x0af0, 0x7A05)}, - {USB_DEVICE(0x0af0, 0x8200)}, - {USB_DEVICE(0x0af0, 0x8201)}, - {USB_DEVICE(0x0af0, 0x8300)}, - {USB_DEVICE(0x0af0, 0x8302)}, - {USB_DEVICE(0x0af0, 0x8304)}, - {USB_DEVICE(0x0af0, 0x8400)}, - {USB_DEVICE(0x0af0, 0x8600)}, - {USB_DEVICE(0x0af0, 0x8800)}, - {USB_DEVICE(0x0af0, 0x8900)}, - {USB_DEVICE(0x0af0, 0x9000)}, - {USB_DEVICE(0x0af0, 0xd035)}, - {USB_DEVICE(0x0af0, 0xd055)}, - {USB_DEVICE(0x0af0, 0xd155)}, - {USB_DEVICE(0x0af0, 0xd255)}, - {USB_DEVICE(0x0af0, 0xd057)}, - {USB_DEVICE(0x0af0, 0xd157)}, - {USB_DEVICE(0x0af0, 0xd257)}, - {USB_DEVICE(0x0af0, 0xd357)}, - {USB_DEVICE(0x0af0, 0xd058)}, - {USB_DEVICE(0x0af0, 0xc100)}, - {} -}; -MODULE_DEVICE_TABLE(usb, hso_ids); - -/* Sysfs attribute */ -static ssize_t hso_sysfs_show_porttype(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct hso_device *hso_dev = dev_get_drvdata(dev); - char *port_name; - - if (!hso_dev) - return 0; - - switch (hso_dev->port_spec & HSO_PORT_MASK) { - case HSO_PORT_CONTROL: - port_name = "Control"; - break; - case HSO_PORT_APP: - port_name = "Application"; - break; - case HSO_PORT_APP2: - port_name = "Application2"; - break; - case HSO_PORT_GPS: - port_name = "GPS"; - break; - case HSO_PORT_GPS_CONTROL: - port_name = "GPS Control"; - break; - case HSO_PORT_PCSC: - port_name = "PCSC"; - break; - case HSO_PORT_DIAG: - port_name = "Diagnostic"; - break; - case HSO_PORT_DIAG2: - port_name = "Diagnostic2"; - break; - case HSO_PORT_MODEM: - port_name = "Modem"; - break; - case HSO_PORT_NETWORK: - port_name = "Network"; - break; - default: - port_name = "Unknown"; - break; - } - - return sprintf(buf, "%s\n", port_name); -} -static DEVICE_ATTR(hsotype, S_IRUGO, hso_sysfs_show_porttype, NULL); - -static int hso_urb_to_index(struct hso_serial *serial, struct urb *urb) -{ - int idx; - - for (idx = 0; idx < serial->num_rx_urbs; idx++) - if (serial->rx_urb[idx] == urb) - return idx; - dev_err(serial->parent->dev, "hso_urb_to_index failed\n"); - return -1; -} - -/* converts mux value to a port spec value */ -static u32 hso_mux_to_port(int mux) -{ - u32 result; - - switch (mux) { - case 0x1: - result = HSO_PORT_CONTROL; - break; - case 0x2: - result = HSO_PORT_APP; - break; - case 0x4: - result = HSO_PORT_PCSC; - break; - case 0x8: - result = HSO_PORT_GPS; - break; - case 0x10: - result = HSO_PORT_APP2; - break; - default: - result = HSO_PORT_NO_PORT; - } - return result; -} - -/* converts port spec value to a mux value */ -static u32 hso_port_to_mux(int port) -{ - u32 result; - - switch (port & HSO_PORT_MASK) { - case HSO_PORT_CONTROL: - result = 0x0; - break; - case HSO_PORT_APP: - result = 0x1; - break; - case HSO_PORT_PCSC: - result = 0x2; - break; - case HSO_PORT_GPS: - result = 0x3; - break; - case HSO_PORT_APP2: - result = 0x4; - break; - default: - result = 0x0; - } - return result; -} - -static struct hso_serial *get_serial_by_shared_int_and_type( - struct hso_shared_int *shared_int, - int mux) -{ - int i, port; - - port = hso_mux_to_port(mux); - - for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { - if (serial_table[i] && - (dev2ser(serial_table[i])->shared_int == shared_int) && - ((serial_table[i]->port_spec & HSO_PORT_MASK) == port)) { - return dev2ser(serial_table[i]); - } - } - - return NULL; -} - -static struct hso_serial *get_serial_by_index(unsigned index) -{ - struct hso_serial *serial = NULL; - unsigned long flags; - - spin_lock_irqsave(&serial_table_lock, flags); - if (serial_table[index]) - serial = dev2ser(serial_table[index]); - spin_unlock_irqrestore(&serial_table_lock, flags); - - return serial; -} - -static int get_free_serial_index(void) -{ - int index; - unsigned long flags; - - spin_lock_irqsave(&serial_table_lock, flags); - for (index = 0; index < HSO_SERIAL_TTY_MINORS; index++) { - if (serial_table[index] == NULL) { - spin_unlock_irqrestore(&serial_table_lock, flags); - return index; - } - } - spin_unlock_irqrestore(&serial_table_lock, flags); - - printk(KERN_ERR "%s: no free serial devices in table\n", __func__); - return -1; -} - -static void set_serial_by_index(unsigned index, struct hso_serial *serial) -{ - unsigned long flags; - - spin_lock_irqsave(&serial_table_lock, flags); - if (serial) - serial_table[index] = serial->parent; - else - serial_table[index] = NULL; - spin_unlock_irqrestore(&serial_table_lock, flags); -} - -static void handle_usb_error(int status, const char *function, - struct hso_device *hso_dev) -{ - char *explanation; - - switch (status) { - case -ENODEV: - explanation = "no device"; - break; - case -ENOENT: - explanation = "endpoint not enabled"; - break; - case -EPIPE: - explanation = "endpoint stalled"; - break; - case -ENOSPC: - explanation = "not enough bandwidth"; - break; - case -ESHUTDOWN: - explanation = "device disabled"; - break; - case -EHOSTUNREACH: - explanation = "device suspended"; - break; - case -EINVAL: - case -EAGAIN: - case -EFBIG: - case -EMSGSIZE: - explanation = "internal error"; - break; - case -EILSEQ: - case -EPROTO: - case -ETIME: - case -ETIMEDOUT: - explanation = "protocol error"; - if (hso_dev) - schedule_work(&hso_dev->reset_device); - break; - default: - explanation = "unknown status"; - break; - } - - /* log a meaningful explanation of an USB status */ - D1("%s: received USB status - %s (%d)", function, explanation, status); -} - -/* Network interface functions */ - -/* called when net interface is brought up by ifconfig */ -static int hso_net_open(struct net_device *net) -{ - struct hso_net *odev = netdev_priv(net); - unsigned long flags = 0; - - if (!odev) { - dev_err(&net->dev, "No net device !\n"); - return -ENODEV; - } - - odev->skb_tx_buf = NULL; - - /* setup environment */ - spin_lock_irqsave(&odev->net_lock, flags); - odev->rx_parse_state = WAIT_IP; - odev->rx_buf_size = 0; - odev->rx_buf_missing = sizeof(struct iphdr); - spin_unlock_irqrestore(&odev->net_lock, flags); - - /* We are up and running. */ - set_bit(HSO_NET_RUNNING, &odev->flags); - hso_start_net_device(odev->parent); - - /* Tell the kernel we are ready to start receiving from it */ - netif_start_queue(net); - - return 0; -} - -/* called when interface is brought down by ifconfig */ -static int hso_net_close(struct net_device *net) -{ - struct hso_net *odev = netdev_priv(net); - - /* we don't need the queue anymore */ - netif_stop_queue(net); - /* no longer running */ - clear_bit(HSO_NET_RUNNING, &odev->flags); - - hso_stop_net_device(odev->parent); - - /* done */ - return 0; -} - -/* USB tells is xmit done, we should start the netqueue again */ -static void write_bulk_callback(struct urb *urb) -{ - struct hso_net *odev = urb->context; - int status = urb->status; - - /* Sanity check */ - if (!odev || !test_bit(HSO_NET_RUNNING, &odev->flags)) { - dev_err(&urb->dev->dev, "%s: device not running\n", __func__); - return; - } - - /* Do we still have a valid kernel network device? */ - if (!netif_device_present(odev->net)) { - dev_err(&urb->dev->dev, "%s: net device not present\n", - __func__); - return; - } - - /* log status, but don't act on it, we don't need to resubmit anything - * anyhow */ - if (status) - handle_usb_error(status, __func__, odev->parent); - - hso_put_activity(odev->parent); - - /* Tell the network interface we are ready for another frame */ - netif_wake_queue(odev->net); -} - -/* called by kernel when we need to transmit a packet */ -static netdev_tx_t hso_net_start_xmit(struct sk_buff *skb, - struct net_device *net) -{ - struct hso_net *odev = netdev_priv(net); - int result; - - /* Tell the kernel, "No more frames 'til we are done with this one." */ - netif_stop_queue(net); - if (hso_get_activity(odev->parent) == -EAGAIN) { - odev->skb_tx_buf = skb; - return NETDEV_TX_OK; - } - - /* log if asked */ - DUMP1(skb->data, skb->len); - /* Copy it from kernel memory to OUR memory */ - memcpy(odev->mux_bulk_tx_buf, skb->data, skb->len); - D1("len: %d/%d", skb->len, MUX_BULK_TX_BUF_SIZE); - - /* Fill in the URB for shipping it out. */ - usb_fill_bulk_urb(odev->mux_bulk_tx_urb, - odev->parent->usb, - usb_sndbulkpipe(odev->parent->usb, - odev->out_endp-> - bEndpointAddress & 0x7F), - odev->mux_bulk_tx_buf, skb->len, write_bulk_callback, - odev); - - /* Deal with the Zero Length packet problem, I hope */ - odev->mux_bulk_tx_urb->transfer_flags |= URB_ZERO_PACKET; - - /* Send the URB on its merry way. */ - result = usb_submit_urb(odev->mux_bulk_tx_urb, GFP_ATOMIC); - if (result) { - dev_warn(&odev->parent->interface->dev, - "failed mux_bulk_tx_urb %d\n", result); - net->stats.tx_errors++; - netif_start_queue(net); - } else { - net->stats.tx_packets++; - net->stats.tx_bytes += skb->len; - } - dev_kfree_skb(skb); - /* we're done */ - return NETDEV_TX_OK; -} - -static const struct ethtool_ops ops = { - .get_link = ethtool_op_get_link -}; - -/* called when a packet did not ack after watchdogtimeout */ -static void hso_net_tx_timeout(struct net_device *net) -{ - struct hso_net *odev = netdev_priv(net); - - if (!odev) - return; - - /* Tell syslog we are hosed. */ - dev_warn(&net->dev, "Tx timed out.\n"); - - /* Tear the waiting frame off the list */ - if (odev->mux_bulk_tx_urb && - (odev->mux_bulk_tx_urb->status == -EINPROGRESS)) - usb_unlink_urb(odev->mux_bulk_tx_urb); - - /* Update statistics */ - net->stats.tx_errors++; -} - -/* make a real packet from the received USB buffer */ -static void packetizeRx(struct hso_net *odev, unsigned char *ip_pkt, - unsigned int count, unsigned char is_eop) -{ - unsigned short temp_bytes; - unsigned short buffer_offset = 0; - unsigned short frame_len; - unsigned char *tmp_rx_buf; - - /* log if needed */ - D1("Rx %d bytes", count); - DUMP(ip_pkt, min(128, (int)count)); - - while (count) { - switch (odev->rx_parse_state) { - case WAIT_IP: - /* waiting for IP header. */ - /* wanted bytes - size of ip header */ - temp_bytes = - (count < - odev->rx_buf_missing) ? count : odev-> - rx_buf_missing; - - memcpy(((unsigned char *)(&odev->rx_ip_hdr)) + - odev->rx_buf_size, ip_pkt + buffer_offset, - temp_bytes); - - odev->rx_buf_size += temp_bytes; - buffer_offset += temp_bytes; - odev->rx_buf_missing -= temp_bytes; - count -= temp_bytes; - - if (!odev->rx_buf_missing) { - /* header is complete allocate an sk_buffer and - * continue to WAIT_DATA */ - frame_len = ntohs(odev->rx_ip_hdr.tot_len); - - if ((frame_len > DEFAULT_MRU) || - (frame_len < sizeof(struct iphdr))) { - dev_err(&odev->net->dev, - "Invalid frame (%d) length\n", - frame_len); - odev->rx_parse_state = WAIT_SYNC; - continue; - } - /* Allocate an sk_buff */ - odev->skb_rx_buf = netdev_alloc_skb(odev->net, - frame_len); - if (!odev->skb_rx_buf) { - /* We got no receive buffer. */ - D1("could not allocate memory"); - odev->rx_parse_state = WAIT_SYNC; - return; - } - - /* Copy what we got so far. make room for iphdr - * after tail. */ - tmp_rx_buf = - skb_put(odev->skb_rx_buf, - sizeof(struct iphdr)); - memcpy(tmp_rx_buf, (char *)&(odev->rx_ip_hdr), - sizeof(struct iphdr)); - - /* ETH_HLEN */ - odev->rx_buf_size = sizeof(struct iphdr); - - /* Filip actually use .tot_len */ - odev->rx_buf_missing = - frame_len - sizeof(struct iphdr); - odev->rx_parse_state = WAIT_DATA; - } - break; - - case WAIT_DATA: - temp_bytes = (count < odev->rx_buf_missing) - ? count : odev->rx_buf_missing; - - /* Copy the rest of the bytes that are left in the - * buffer into the waiting sk_buf. */ - /* Make room for temp_bytes after tail. */ - tmp_rx_buf = skb_put(odev->skb_rx_buf, temp_bytes); - memcpy(tmp_rx_buf, ip_pkt + buffer_offset, temp_bytes); - - odev->rx_buf_missing -= temp_bytes; - count -= temp_bytes; - buffer_offset += temp_bytes; - odev->rx_buf_size += temp_bytes; - if (!odev->rx_buf_missing) { - /* Packet is complete. Inject into stack. */ - /* We have IP packet here */ - odev->skb_rx_buf->protocol = cpu_to_be16(ETH_P_IP); - skb_reset_mac_header(odev->skb_rx_buf); - - /* Ship it off to the kernel */ - netif_rx(odev->skb_rx_buf); - /* No longer our buffer. */ - odev->skb_rx_buf = NULL; - - /* update out statistics */ - odev->net->stats.rx_packets++; - - odev->net->stats.rx_bytes += odev->rx_buf_size; - - odev->rx_buf_size = 0; - odev->rx_buf_missing = sizeof(struct iphdr); - odev->rx_parse_state = WAIT_IP; - } - break; - - case WAIT_SYNC: - D1(" W_S"); - count = 0; - break; - default: - D1(" "); - count--; - break; - } - } - - /* Recovery mechanism for WAIT_SYNC state. */ - if (is_eop) { - if (odev->rx_parse_state == WAIT_SYNC) { - odev->rx_parse_state = WAIT_IP; - odev->rx_buf_size = 0; - odev->rx_buf_missing = sizeof(struct iphdr); - } - } -} - -static void fix_crc_bug(struct urb *urb, __le16 max_packet_size) -{ - static const u8 crc_check[4] = { 0xDE, 0xAD, 0xBE, 0xEF }; - u32 rest = urb->actual_length % le16_to_cpu(max_packet_size); - - if (((rest == 5) || (rest == 6)) && - !memcmp(((u8 *)urb->transfer_buffer) + urb->actual_length - 4, - crc_check, 4)) { - urb->actual_length -= 4; - } -} - -/* Moving data from usb to kernel (in interrupt state) */ -static void read_bulk_callback(struct urb *urb) -{ - struct hso_net *odev = urb->context; - struct net_device *net; - int result; - int status = urb->status; - - /* is al ok? (Filip: Who's Al ?) */ - if (status) { - handle_usb_error(status, __func__, odev->parent); - return; - } - - /* Sanity check */ - if (!odev || !test_bit(HSO_NET_RUNNING, &odev->flags)) { - D1("BULK IN callback but driver is not active!"); - return; - } - usb_mark_last_busy(urb->dev); - - net = odev->net; - - if (!netif_device_present(net)) { - /* Somebody killed our network interface... */ - return; - } - - if (odev->parent->port_spec & HSO_INFO_CRC_BUG) - fix_crc_bug(urb, odev->in_endp->wMaxPacketSize); - - /* do we even have a packet? */ - if (urb->actual_length) { - /* Handle the IP stream, add header and push it onto network - * stack if the packet is complete. */ - spin_lock(&odev->net_lock); - packetizeRx(odev, urb->transfer_buffer, urb->actual_length, - (urb->transfer_buffer_length > - urb->actual_length) ? 1 : 0); - spin_unlock(&odev->net_lock); - } - - /* We are done with this URB, resubmit it. Prep the USB to wait for - * another frame. Reuse same as received. */ - usb_fill_bulk_urb(urb, - odev->parent->usb, - usb_rcvbulkpipe(odev->parent->usb, - odev->in_endp-> - bEndpointAddress & 0x7F), - urb->transfer_buffer, MUX_BULK_RX_BUF_SIZE, - read_bulk_callback, odev); - - /* Give this to the USB subsystem so it can tell us when more data - * arrives. */ - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) - dev_warn(&odev->parent->interface->dev, - "%s failed submit mux_bulk_rx_urb %d\n", __func__, - result); -} - -/* Serial driver functions */ - -static void hso_init_termios(struct ktermios *termios) -{ - /* - * The default requirements for this device are: - */ - termios->c_iflag &= - ~(IGNBRK /* disable ignore break */ - | BRKINT /* disable break causes interrupt */ - | PARMRK /* disable mark parity errors */ - | ISTRIP /* disable clear high bit of input characters */ - | INLCR /* disable translate NL to CR */ - | IGNCR /* disable ignore CR */ - | ICRNL /* disable translate CR to NL */ - | IXON); /* disable enable XON/XOFF flow control */ - - /* disable postprocess output characters */ - termios->c_oflag &= ~OPOST; - - termios->c_lflag &= - ~(ECHO /* disable echo input characters */ - | ECHONL /* disable echo new line */ - | ICANON /* disable erase, kill, werase, and rprnt - special characters */ - | ISIG /* disable interrupt, quit, and suspend special - characters */ - | IEXTEN); /* disable non-POSIX special characters */ - - termios->c_cflag &= - ~(CSIZE /* no size */ - | PARENB /* disable parity bit */ - | CBAUD /* clear current baud rate */ - | CBAUDEX); /* clear current buad rate */ - - termios->c_cflag |= CS8; /* character size 8 bits */ - - /* baud rate 115200 */ - tty_termios_encode_baud_rate(termios, 115200, 115200); -} - -static void _hso_serial_set_termios(struct tty_struct *tty, - struct ktermios *old) -{ - struct hso_serial *serial = get_serial_by_tty(tty); - struct ktermios *termios; - - if (!serial) { - printk(KERN_ERR "%s: no tty structures", __func__); - return; - } - - D4("port %d", serial->minor); - - /* - * Fix up unsupported bits - */ - termios = tty->termios; - termios->c_iflag &= ~IXON; /* disable enable XON/XOFF flow control */ - - termios->c_cflag &= - ~(CSIZE /* no size */ - | PARENB /* disable parity bit */ - | CBAUD /* clear current baud rate */ - | CBAUDEX); /* clear current buad rate */ - - termios->c_cflag |= CS8; /* character size 8 bits */ - - /* baud rate 115200 */ - tty_encode_baud_rate(tty, 115200, 115200); -} - -static void hso_resubmit_rx_bulk_urb(struct hso_serial *serial, struct urb *urb) -{ - int result; - /* We are done with this URB, resubmit it. Prep the USB to wait for - * another frame */ - usb_fill_bulk_urb(urb, serial->parent->usb, - usb_rcvbulkpipe(serial->parent->usb, - serial->in_endp-> - bEndpointAddress & 0x7F), - urb->transfer_buffer, serial->rx_data_length, - hso_std_serial_read_bulk_callback, serial); - /* Give this to the USB subsystem so it can tell us when more data - * arrives. */ - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) { - dev_err(&urb->dev->dev, "%s failed submit serial rx_urb %d\n", - __func__, result); - } -} - - - - -static void put_rxbuf_data_and_resubmit_bulk_urb(struct hso_serial *serial) -{ - int count; - struct urb *curr_urb; - - while (serial->rx_urb_filled[serial->curr_rx_urb_idx]) { - curr_urb = serial->rx_urb[serial->curr_rx_urb_idx]; - count = put_rxbuf_data(curr_urb, serial); - if (count == -1) - return; - if (count == 0) { - serial->curr_rx_urb_idx++; - if (serial->curr_rx_urb_idx >= serial->num_rx_urbs) - serial->curr_rx_urb_idx = 0; - hso_resubmit_rx_bulk_urb(serial, curr_urb); - } - } -} - -static void put_rxbuf_data_and_resubmit_ctrl_urb(struct hso_serial *serial) -{ - int count = 0; - struct urb *urb; - - urb = serial->rx_urb[0]; - if (serial->open_count > 0) { - count = put_rxbuf_data(urb, serial); - if (count == -1) - return; - } - /* Re issue a read as long as we receive data. */ - - if (count == 0 && ((urb->actual_length != 0) || - (serial->rx_state == RX_PENDING))) { - serial->rx_state = RX_SENT; - hso_mux_serial_read(serial); - } else - serial->rx_state = RX_IDLE; -} - - -/* read callback for Diag and CS port */ -static void hso_std_serial_read_bulk_callback(struct urb *urb) -{ - struct hso_serial *serial = urb->context; - int status = urb->status; - - /* sanity check */ - if (!serial) { - D1("serial == NULL"); - return; - } else if (status) { - handle_usb_error(status, __func__, serial->parent); - return; - } - - D4("\n--- Got serial_read_bulk callback %02x ---", status); - D1("Actual length = %d\n", urb->actual_length); - DUMP1(urb->transfer_buffer, urb->actual_length); - - /* Anyone listening? */ - if (serial->open_count == 0) - return; - - if (status == 0) { - if (serial->parent->port_spec & HSO_INFO_CRC_BUG) - fix_crc_bug(urb, serial->in_endp->wMaxPacketSize); - /* Valid data, handle RX data */ - spin_lock(&serial->serial_lock); - serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 1; - put_rxbuf_data_and_resubmit_bulk_urb(serial); - spin_unlock(&serial->serial_lock); - } else if (status == -ENOENT || status == -ECONNRESET) { - /* Unlinked - check for throttled port. */ - D2("Port %d, successfully unlinked urb", serial->minor); - spin_lock(&serial->serial_lock); - serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0; - hso_resubmit_rx_bulk_urb(serial, urb); - spin_unlock(&serial->serial_lock); - } else { - D2("Port %d, status = %d for read urb", serial->minor, status); - return; - } -} - -/* - * This needs to be a tasklet otherwise we will - * end up recursively calling this function. - */ -static void hso_unthrottle_tasklet(struct hso_serial *serial) -{ - unsigned long flags; - - spin_lock_irqsave(&serial->serial_lock, flags); - if ((serial->parent->port_spec & HSO_INTF_MUX)) - put_rxbuf_data_and_resubmit_ctrl_urb(serial); - else - put_rxbuf_data_and_resubmit_bulk_urb(serial); - spin_unlock_irqrestore(&serial->serial_lock, flags); -} - -static void hso_unthrottle(struct tty_struct *tty) -{ - struct hso_serial *serial = get_serial_by_tty(tty); - - tasklet_hi_schedule(&serial->unthrottle_tasklet); -} - -static void hso_unthrottle_workfunc(struct work_struct *work) -{ - struct hso_serial *serial = - container_of(work, struct hso_serial, - retry_unthrottle_workqueue); - hso_unthrottle_tasklet(serial); -} - -/* open the requested serial port */ -static int hso_serial_open(struct tty_struct *tty, struct file *filp) -{ - struct hso_serial *serial = get_serial_by_index(tty->index); - int result; - - /* sanity check */ - if (serial == NULL || serial->magic != HSO_SERIAL_MAGIC) { - WARN_ON(1); - tty->driver_data = NULL; - D1("Failed to open port"); - return -ENODEV; - } - - mutex_lock(&serial->parent->mutex); - result = usb_autopm_get_interface(serial->parent->interface); - if (result < 0) - goto err_out; - - D1("Opening %d", serial->minor); - kref_get(&serial->parent->ref); - - /* setup */ - spin_lock_irq(&serial->serial_lock); - tty->driver_data = serial; - tty_kref_put(serial->tty); - serial->tty = tty_kref_get(tty); - spin_unlock_irq(&serial->serial_lock); - - /* check for port already opened, if not set the termios */ - serial->open_count++; - if (serial->open_count == 1) { - serial->rx_state = RX_IDLE; - /* Force default termio settings */ - _hso_serial_set_termios(tty, NULL); - tasklet_init(&serial->unthrottle_tasklet, - (void (*)(unsigned long))hso_unthrottle_tasklet, - (unsigned long)serial); - INIT_WORK(&serial->retry_unthrottle_workqueue, - hso_unthrottle_workfunc); - result = hso_start_serial_device(serial->parent, GFP_KERNEL); - if (result) { - hso_stop_serial_device(serial->parent); - serial->open_count--; - kref_put(&serial->parent->ref, hso_serial_ref_free); - } - } else { - D1("Port was already open"); - } - - usb_autopm_put_interface(serial->parent->interface); - - /* done */ - if (result) - hso_serial_tiocmset(tty, TIOCM_RTS | TIOCM_DTR, 0); -err_out: - mutex_unlock(&serial->parent->mutex); - return result; -} - -/* close the requested serial port */ -static void hso_serial_close(struct tty_struct *tty, struct file *filp) -{ - struct hso_serial *serial = tty->driver_data; - u8 usb_gone; - - D1("Closing serial port"); - - /* Open failed, no close cleanup required */ - if (serial == NULL) - return; - - mutex_lock(&serial->parent->mutex); - usb_gone = serial->parent->usb_gone; - - if (!usb_gone) - usb_autopm_get_interface(serial->parent->interface); - - /* reset the rts and dtr */ - /* do the actual close */ - serial->open_count--; - - if (serial->open_count <= 0) { - serial->open_count = 0; - spin_lock_irq(&serial->serial_lock); - if (serial->tty == tty) { - serial->tty->driver_data = NULL; - serial->tty = NULL; - tty_kref_put(tty); - } - spin_unlock_irq(&serial->serial_lock); - if (!usb_gone) - hso_stop_serial_device(serial->parent); - tasklet_kill(&serial->unthrottle_tasklet); - cancel_work_sync(&serial->retry_unthrottle_workqueue); - } - - if (!usb_gone) - usb_autopm_put_interface(serial->parent->interface); - - mutex_unlock(&serial->parent->mutex); - - kref_put(&serial->parent->ref, hso_serial_ref_free); -} - -/* close the requested serial port */ -static int hso_serial_write(struct tty_struct *tty, const unsigned char *buf, - int count) -{ - struct hso_serial *serial = get_serial_by_tty(tty); - int space, tx_bytes; - unsigned long flags; - - /* sanity check */ - if (serial == NULL) { - printk(KERN_ERR "%s: serial is NULL\n", __func__); - return -ENODEV; - } - - spin_lock_irqsave(&serial->serial_lock, flags); - - space = serial->tx_data_length - serial->tx_buffer_count; - tx_bytes = (count < space) ? count : space; - - if (!tx_bytes) - goto out; - - memcpy(serial->tx_buffer + serial->tx_buffer_count, buf, tx_bytes); - serial->tx_buffer_count += tx_bytes; - -out: - spin_unlock_irqrestore(&serial->serial_lock, flags); - - hso_kick_transmit(serial); - /* done */ - return tx_bytes; -} - -/* how much room is there for writing */ -static int hso_serial_write_room(struct tty_struct *tty) -{ - struct hso_serial *serial = get_serial_by_tty(tty); - int room; - unsigned long flags; - - spin_lock_irqsave(&serial->serial_lock, flags); - room = serial->tx_data_length - serial->tx_buffer_count; - spin_unlock_irqrestore(&serial->serial_lock, flags); - - /* return free room */ - return room; -} - -/* setup the term */ -static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old) -{ - struct hso_serial *serial = get_serial_by_tty(tty); - unsigned long flags; - - if (old) - D5("Termios called with: cflags new[%d] - old[%d]", - tty->termios->c_cflag, old->c_cflag); - - /* the actual setup */ - spin_lock_irqsave(&serial->serial_lock, flags); - if (serial->open_count) - _hso_serial_set_termios(tty, old); - else - tty->termios = old; - spin_unlock_irqrestore(&serial->serial_lock, flags); - - /* done */ -} - -/* how many characters in the buffer */ -static int hso_serial_chars_in_buffer(struct tty_struct *tty) -{ - struct hso_serial *serial = get_serial_by_tty(tty); - int chars; - unsigned long flags; - - /* sanity check */ - if (serial == NULL) - return 0; - - spin_lock_irqsave(&serial->serial_lock, flags); - chars = serial->tx_buffer_count; - spin_unlock_irqrestore(&serial->serial_lock, flags); - - return chars; -} -static int tiocmget_submit_urb(struct hso_serial *serial, - struct hso_tiocmget *tiocmget, - struct usb_device *usb) -{ - int result; - - if (serial->parent->usb_gone) - return -ENODEV; - usb_fill_int_urb(tiocmget->urb, usb, - usb_rcvintpipe(usb, - tiocmget->endp-> - bEndpointAddress & 0x7F), - &tiocmget->serial_state_notification, - sizeof(struct hso_serial_state_notification), - tiocmget_intr_callback, serial, - tiocmget->endp->bInterval); - result = usb_submit_urb(tiocmget->urb, GFP_ATOMIC); - if (result) { - dev_warn(&usb->dev, "%s usb_submit_urb failed %d\n", __func__, - result); - } - return result; - -} - -static void tiocmget_intr_callback(struct urb *urb) -{ - struct hso_serial *serial = urb->context; - struct hso_tiocmget *tiocmget; - int status = urb->status; - u16 UART_state_bitmap, prev_UART_state_bitmap; - struct uart_icount *icount; - struct hso_serial_state_notification *serial_state_notification; - struct usb_device *usb; - - /* Sanity checks */ - if (!serial) - return; - if (status) { - handle_usb_error(status, __func__, serial->parent); - return; - } - tiocmget = serial->tiocmget; - if (!tiocmget) - return; - usb = serial->parent->usb; - serial_state_notification = &tiocmget->serial_state_notification; - if (serial_state_notification->bmRequestType != BM_REQUEST_TYPE || - serial_state_notification->bNotification != B_NOTIFICATION || - le16_to_cpu(serial_state_notification->wValue) != W_VALUE || - le16_to_cpu(serial_state_notification->wIndex) != W_INDEX || - le16_to_cpu(serial_state_notification->wLength) != W_LENGTH) { - dev_warn(&usb->dev, - "hso received invalid serial state notification\n"); - DUMP(serial_state_notification, - sizeof(struct hso_serial_state_notification)); - } else { - - UART_state_bitmap = le16_to_cpu(serial_state_notification-> - UART_state_bitmap); - prev_UART_state_bitmap = tiocmget->prev_UART_state_bitmap; - icount = &tiocmget->icount; - spin_lock(&serial->serial_lock); - if ((UART_state_bitmap & B_OVERRUN) != - (prev_UART_state_bitmap & B_OVERRUN)) - icount->parity++; - if ((UART_state_bitmap & B_PARITY) != - (prev_UART_state_bitmap & B_PARITY)) - icount->parity++; - if ((UART_state_bitmap & B_FRAMING) != - (prev_UART_state_bitmap & B_FRAMING)) - icount->frame++; - if ((UART_state_bitmap & B_RING_SIGNAL) && - !(prev_UART_state_bitmap & B_RING_SIGNAL)) - icount->rng++; - if ((UART_state_bitmap & B_BREAK) != - (prev_UART_state_bitmap & B_BREAK)) - icount->brk++; - if ((UART_state_bitmap & B_TX_CARRIER) != - (prev_UART_state_bitmap & B_TX_CARRIER)) - icount->dsr++; - if ((UART_state_bitmap & B_RX_CARRIER) != - (prev_UART_state_bitmap & B_RX_CARRIER)) - icount->dcd++; - tiocmget->prev_UART_state_bitmap = UART_state_bitmap; - spin_unlock(&serial->serial_lock); - tiocmget->intr_completed = 1; - wake_up_interruptible(&tiocmget->waitq); - } - memset(serial_state_notification, 0, - sizeof(struct hso_serial_state_notification)); - tiocmget_submit_urb(serial, - tiocmget, - serial->parent->usb); -} - -/* - * next few functions largely stolen from drivers/serial/serial_core.c - */ -/* Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change - * - mask passed in arg for lines of interest - * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) - * Caller should use TIOCGICOUNT to see which one it was - */ -static int -hso_wait_modem_status(struct hso_serial *serial, unsigned long arg) -{ - DECLARE_WAITQUEUE(wait, current); - struct uart_icount cprev, cnow; - struct hso_tiocmget *tiocmget; - int ret; - - tiocmget = serial->tiocmget; - if (!tiocmget) - return -ENOENT; - /* - * note the counters on entry - */ - spin_lock_irq(&serial->serial_lock); - memcpy(&cprev, &tiocmget->icount, sizeof(struct uart_icount)); - spin_unlock_irq(&serial->serial_lock); - add_wait_queue(&tiocmget->waitq, &wait); - for (;;) { - spin_lock_irq(&serial->serial_lock); - memcpy(&cnow, &tiocmget->icount, sizeof(struct uart_icount)); - spin_unlock_irq(&serial->serial_lock); - set_current_state(TASK_INTERRUPTIBLE); - if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd))) { - ret = 0; - break; - } - schedule(); - /* see if a signal did it */ - if (signal_pending(current)) { - ret = -ERESTARTSYS; - break; - } - cprev = cnow; - } - current->state = TASK_RUNNING; - remove_wait_queue(&tiocmget->waitq, &wait); - - return ret; -} - -/* - * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) - * Return: write counters to the user passed counter struct - * NB: both 1->0 and 0->1 transitions are counted except for - * RI where only 0->1 is counted. - */ -static int hso_get_count(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - struct uart_icount cnow; - struct hso_serial *serial = get_serial_by_tty(tty); - struct hso_tiocmget *tiocmget = serial->tiocmget; - - memset(icount, 0, sizeof(struct serial_icounter_struct)); - - if (!tiocmget) - return -ENOENT; - spin_lock_irq(&serial->serial_lock); - memcpy(&cnow, &tiocmget->icount, sizeof(struct uart_icount)); - spin_unlock_irq(&serial->serial_lock); - - icount->cts = cnow.cts; - icount->dsr = cnow.dsr; - icount->rng = cnow.rng; - icount->dcd = cnow.dcd; - icount->rx = cnow.rx; - icount->tx = cnow.tx; - icount->frame = cnow.frame; - icount->overrun = cnow.overrun; - icount->parity = cnow.parity; - icount->brk = cnow.brk; - icount->buf_overrun = cnow.buf_overrun; - - return 0; -} - - -static int hso_serial_tiocmget(struct tty_struct *tty) -{ - int retval; - struct hso_serial *serial = get_serial_by_tty(tty); - struct hso_tiocmget *tiocmget; - u16 UART_state_bitmap; - - /* sanity check */ - if (!serial) { - D1("no tty structures"); - return -EINVAL; - } - spin_lock_irq(&serial->serial_lock); - retval = ((serial->rts_state) ? TIOCM_RTS : 0) | - ((serial->dtr_state) ? TIOCM_DTR : 0); - tiocmget = serial->tiocmget; - if (tiocmget) { - - UART_state_bitmap = le16_to_cpu( - tiocmget->prev_UART_state_bitmap); - if (UART_state_bitmap & B_RING_SIGNAL) - retval |= TIOCM_RNG; - if (UART_state_bitmap & B_RX_CARRIER) - retval |= TIOCM_CD; - if (UART_state_bitmap & B_TX_CARRIER) - retval |= TIOCM_DSR; - } - spin_unlock_irq(&serial->serial_lock); - return retval; -} - -static int hso_serial_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - int val = 0; - unsigned long flags; - int if_num; - struct hso_serial *serial = get_serial_by_tty(tty); - - /* sanity check */ - if (!serial) { - D1("no tty structures"); - return -EINVAL; - } - - if ((serial->parent->port_spec & HSO_PORT_MASK) != HSO_PORT_MODEM) - return -EINVAL; - - if_num = serial->parent->interface->altsetting->desc.bInterfaceNumber; - - spin_lock_irqsave(&serial->serial_lock, flags); - if (set & TIOCM_RTS) - serial->rts_state = 1; - if (set & TIOCM_DTR) - serial->dtr_state = 1; - - if (clear & TIOCM_RTS) - serial->rts_state = 0; - if (clear & TIOCM_DTR) - serial->dtr_state = 0; - - if (serial->dtr_state) - val |= 0x01; - if (serial->rts_state) - val |= 0x02; - - spin_unlock_irqrestore(&serial->serial_lock, flags); - - return usb_control_msg(serial->parent->usb, - usb_rcvctrlpipe(serial->parent->usb, 0), 0x22, - 0x21, val, if_num, NULL, 0, - USB_CTRL_SET_TIMEOUT); -} - -static int hso_serial_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct hso_serial *serial = get_serial_by_tty(tty); - int ret = 0; - D4("IOCTL cmd: %d, arg: %ld", cmd, arg); - - if (!serial) - return -ENODEV; - switch (cmd) { - case TIOCMIWAIT: - ret = hso_wait_modem_status(serial, arg); - break; - default: - ret = -ENOIOCTLCMD; - break; - } - return ret; -} - - -/* starts a transmit */ -static void hso_kick_transmit(struct hso_serial *serial) -{ - u8 *temp; - unsigned long flags; - int res; - - spin_lock_irqsave(&serial->serial_lock, flags); - if (!serial->tx_buffer_count) - goto out; - - if (serial->tx_urb_used) - goto out; - - /* Wakeup USB interface if necessary */ - if (hso_get_activity(serial->parent) == -EAGAIN) - goto out; - - /* Switch pointers around to avoid memcpy */ - temp = serial->tx_buffer; - serial->tx_buffer = serial->tx_data; - serial->tx_data = temp; - serial->tx_data_count = serial->tx_buffer_count; - serial->tx_buffer_count = 0; - - /* If temp is set, it means we switched buffers */ - if (temp && serial->write_data) { - res = serial->write_data(serial); - if (res >= 0) - serial->tx_urb_used = 1; - } -out: - spin_unlock_irqrestore(&serial->serial_lock, flags); -} - -/* make a request (for reading and writing data to muxed serial port) */ -static int mux_device_request(struct hso_serial *serial, u8 type, u16 port, - struct urb *ctrl_urb, - struct usb_ctrlrequest *ctrl_req, - u8 *ctrl_urb_data, u32 size) -{ - int result; - int pipe; - - /* Sanity check */ - if (!serial || !ctrl_urb || !ctrl_req) { - printk(KERN_ERR "%s: Wrong arguments\n", __func__); - return -EINVAL; - } - - /* initialize */ - ctrl_req->wValue = 0; - ctrl_req->wIndex = cpu_to_le16(hso_port_to_mux(port)); - ctrl_req->wLength = cpu_to_le16(size); - - if (type == USB_CDC_GET_ENCAPSULATED_RESPONSE) { - /* Reading command */ - ctrl_req->bRequestType = USB_DIR_IN | - USB_TYPE_OPTION_VENDOR | - USB_RECIP_INTERFACE; - ctrl_req->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE; - pipe = usb_rcvctrlpipe(serial->parent->usb, 0); - } else { - /* Writing command */ - ctrl_req->bRequestType = USB_DIR_OUT | - USB_TYPE_OPTION_VENDOR | - USB_RECIP_INTERFACE; - ctrl_req->bRequest = USB_CDC_SEND_ENCAPSULATED_COMMAND; - pipe = usb_sndctrlpipe(serial->parent->usb, 0); - } - /* syslog */ - D2("%s command (%02x) len: %d, port: %d", - type == USB_CDC_GET_ENCAPSULATED_RESPONSE ? "Read" : "Write", - ctrl_req->bRequestType, ctrl_req->wLength, port); - - /* Load ctrl urb */ - ctrl_urb->transfer_flags = 0; - usb_fill_control_urb(ctrl_urb, - serial->parent->usb, - pipe, - (u8 *) ctrl_req, - ctrl_urb_data, size, ctrl_callback, serial); - /* Send it on merry way */ - result = usb_submit_urb(ctrl_urb, GFP_ATOMIC); - if (result) { - dev_err(&ctrl_urb->dev->dev, - "%s failed submit ctrl_urb %d type %d\n", __func__, - result, type); - return result; - } - - /* done */ - return size; -} - -/* called by intr_callback when read occurs */ -static int hso_mux_serial_read(struct hso_serial *serial) -{ - if (!serial) - return -EINVAL; - - /* clean data */ - memset(serial->rx_data[0], 0, CTRL_URB_RX_SIZE); - /* make the request */ - - if (serial->num_rx_urbs != 1) { - dev_err(&serial->parent->interface->dev, - "ERROR: mux'd reads with multiple buffers " - "not possible\n"); - return 0; - } - return mux_device_request(serial, - USB_CDC_GET_ENCAPSULATED_RESPONSE, - serial->parent->port_spec & HSO_PORT_MASK, - serial->rx_urb[0], - &serial->ctrl_req_rx, - serial->rx_data[0], serial->rx_data_length); -} - -/* used for muxed serial port callback (muxed serial read) */ -static void intr_callback(struct urb *urb) -{ - struct hso_shared_int *shared_int = urb->context; - struct hso_serial *serial; - unsigned char *port_req; - int status = urb->status; - int i; - - usb_mark_last_busy(urb->dev); - - /* sanity check */ - if (!shared_int) - return; - - /* status check */ - if (status) { - handle_usb_error(status, __func__, NULL); - return; - } - D4("\n--- Got intr callback 0x%02X ---", status); - - /* what request? */ - port_req = urb->transfer_buffer; - D4(" port_req = 0x%.2X\n", *port_req); - /* loop over all muxed ports to find the one sending this */ - for (i = 0; i < 8; i++) { - /* max 8 channels on MUX */ - if (*port_req & (1 << i)) { - serial = get_serial_by_shared_int_and_type(shared_int, - (1 << i)); - if (serial != NULL) { - D1("Pending read interrupt on port %d\n", i); - spin_lock(&serial->serial_lock); - if (serial->rx_state == RX_IDLE && - serial->open_count > 0) { - /* Setup and send a ctrl req read on - * port i */ - if (!serial->rx_urb_filled[0]) { - serial->rx_state = RX_SENT; - hso_mux_serial_read(serial); - } else - serial->rx_state = RX_PENDING; - } else { - D1("Already a read pending on " - "port %d or port not open\n", i); - } - spin_unlock(&serial->serial_lock); - } - } - } - /* Resubmit interrupt urb */ - hso_mux_submit_intr_urb(shared_int, urb->dev, GFP_ATOMIC); -} - -/* called for writing to muxed serial port */ -static int hso_mux_serial_write_data(struct hso_serial *serial) -{ - if (NULL == serial) - return -EINVAL; - - return mux_device_request(serial, - USB_CDC_SEND_ENCAPSULATED_COMMAND, - serial->parent->port_spec & HSO_PORT_MASK, - serial->tx_urb, - &serial->ctrl_req_tx, - serial->tx_data, serial->tx_data_count); -} - -/* write callback for Diag and CS port */ -static void hso_std_serial_write_bulk_callback(struct urb *urb) -{ - struct hso_serial *serial = urb->context; - int status = urb->status; - struct tty_struct *tty; - - /* sanity check */ - if (!serial) { - D1("serial == NULL"); - return; - } - - spin_lock(&serial->serial_lock); - serial->tx_urb_used = 0; - tty = tty_kref_get(serial->tty); - spin_unlock(&serial->serial_lock); - if (status) { - handle_usb_error(status, __func__, serial->parent); - tty_kref_put(tty); - return; - } - hso_put_activity(serial->parent); - if (tty) { - tty_wakeup(tty); - tty_kref_put(tty); - } - hso_kick_transmit(serial); - - D1(" "); -} - -/* called for writing diag or CS serial port */ -static int hso_std_serial_write_data(struct hso_serial *serial) -{ - int count = serial->tx_data_count; - int result; - - usb_fill_bulk_urb(serial->tx_urb, - serial->parent->usb, - usb_sndbulkpipe(serial->parent->usb, - serial->out_endp-> - bEndpointAddress & 0x7F), - serial->tx_data, serial->tx_data_count, - hso_std_serial_write_bulk_callback, serial); - - result = usb_submit_urb(serial->tx_urb, GFP_ATOMIC); - if (result) { - dev_warn(&serial->parent->usb->dev, - "Failed to submit urb - res %d\n", result); - return result; - } - - return count; -} - -/* callback after read or write on muxed serial port */ -static void ctrl_callback(struct urb *urb) -{ - struct hso_serial *serial = urb->context; - struct usb_ctrlrequest *req; - int status = urb->status; - struct tty_struct *tty; - - /* sanity check */ - if (!serial) - return; - - spin_lock(&serial->serial_lock); - serial->tx_urb_used = 0; - tty = tty_kref_get(serial->tty); - spin_unlock(&serial->serial_lock); - if (status) { - handle_usb_error(status, __func__, serial->parent); - tty_kref_put(tty); - return; - } - - /* what request? */ - req = (struct usb_ctrlrequest *)(urb->setup_packet); - D4("\n--- Got muxed ctrl callback 0x%02X ---", status); - D4("Actual length of urb = %d\n", urb->actual_length); - DUMP1(urb->transfer_buffer, urb->actual_length); - - if (req->bRequestType == - (USB_DIR_IN | USB_TYPE_OPTION_VENDOR | USB_RECIP_INTERFACE)) { - /* response to a read command */ - serial->rx_urb_filled[0] = 1; - spin_lock(&serial->serial_lock); - put_rxbuf_data_and_resubmit_ctrl_urb(serial); - spin_unlock(&serial->serial_lock); - } else { - hso_put_activity(serial->parent); - if (tty) - tty_wakeup(tty); - /* response to a write command */ - hso_kick_transmit(serial); - } - tty_kref_put(tty); -} - -/* handle RX data for serial port */ -static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial) -{ - struct tty_struct *tty; - int write_length_remaining = 0; - int curr_write_len; - - /* Sanity check */ - if (urb == NULL || serial == NULL) { - D1("serial = NULL"); - return -2; - } - - /* All callers to put_rxbuf_data hold serial_lock */ - tty = tty_kref_get(serial->tty); - - /* Push data to tty */ - if (tty) { - write_length_remaining = urb->actual_length - - serial->curr_rx_urb_offset; - D1("data to push to tty"); - while (write_length_remaining) { - if (test_bit(TTY_THROTTLED, &tty->flags)) { - tty_kref_put(tty); - return -1; - } - curr_write_len = tty_insert_flip_string - (tty, urb->transfer_buffer + - serial->curr_rx_urb_offset, - write_length_remaining); - serial->curr_rx_urb_offset += curr_write_len; - write_length_remaining -= curr_write_len; - tty_flip_buffer_push(tty); - } - } - if (write_length_remaining == 0) { - serial->curr_rx_urb_offset = 0; - serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0; - } - tty_kref_put(tty); - return write_length_remaining; -} - - -/* Base driver functions */ - -static void hso_log_port(struct hso_device *hso_dev) -{ - char *port_type; - char port_dev[20]; - - switch (hso_dev->port_spec & HSO_PORT_MASK) { - case HSO_PORT_CONTROL: - port_type = "Control"; - break; - case HSO_PORT_APP: - port_type = "Application"; - break; - case HSO_PORT_GPS: - port_type = "GPS"; - break; - case HSO_PORT_GPS_CONTROL: - port_type = "GPS control"; - break; - case HSO_PORT_APP2: - port_type = "Application2"; - break; - case HSO_PORT_PCSC: - port_type = "PCSC"; - break; - case HSO_PORT_DIAG: - port_type = "Diagnostic"; - break; - case HSO_PORT_DIAG2: - port_type = "Diagnostic2"; - break; - case HSO_PORT_MODEM: - port_type = "Modem"; - break; - case HSO_PORT_NETWORK: - port_type = "Network"; - break; - default: - port_type = "Unknown"; - break; - } - if ((hso_dev->port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) { - sprintf(port_dev, "%s", dev2net(hso_dev)->net->name); - } else - sprintf(port_dev, "/dev/%s%d", tty_filename, - dev2ser(hso_dev)->minor); - - dev_dbg(&hso_dev->interface->dev, "HSO: Found %s port %s\n", - port_type, port_dev); -} - -static int hso_start_net_device(struct hso_device *hso_dev) -{ - int i, result = 0; - struct hso_net *hso_net = dev2net(hso_dev); - - if (!hso_net) - return -ENODEV; - - /* send URBs for all read buffers */ - for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) { - - /* Prep a receive URB */ - usb_fill_bulk_urb(hso_net->mux_bulk_rx_urb_pool[i], - hso_dev->usb, - usb_rcvbulkpipe(hso_dev->usb, - hso_net->in_endp-> - bEndpointAddress & 0x7F), - hso_net->mux_bulk_rx_buf_pool[i], - MUX_BULK_RX_BUF_SIZE, read_bulk_callback, - hso_net); - - /* Put it out there so the device can send us stuff */ - result = usb_submit_urb(hso_net->mux_bulk_rx_urb_pool[i], - GFP_NOIO); - if (result) - dev_warn(&hso_dev->usb->dev, - "%s failed mux_bulk_rx_urb[%d] %d\n", __func__, - i, result); - } - - return result; -} - -static int hso_stop_net_device(struct hso_device *hso_dev) -{ - int i; - struct hso_net *hso_net = dev2net(hso_dev); - - if (!hso_net) - return -ENODEV; - - for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) { - if (hso_net->mux_bulk_rx_urb_pool[i]) - usb_kill_urb(hso_net->mux_bulk_rx_urb_pool[i]); - - } - if (hso_net->mux_bulk_tx_urb) - usb_kill_urb(hso_net->mux_bulk_tx_urb); - - return 0; -} - -static int hso_start_serial_device(struct hso_device *hso_dev, gfp_t flags) -{ - int i, result = 0; - struct hso_serial *serial = dev2ser(hso_dev); - - if (!serial) - return -ENODEV; - - /* If it is not the MUX port fill in and submit a bulk urb (already - * allocated in hso_serial_start) */ - if (!(serial->parent->port_spec & HSO_INTF_MUX)) { - for (i = 0; i < serial->num_rx_urbs; i++) { - usb_fill_bulk_urb(serial->rx_urb[i], - serial->parent->usb, - usb_rcvbulkpipe(serial->parent->usb, - serial->in_endp-> - bEndpointAddress & - 0x7F), - serial->rx_data[i], - serial->rx_data_length, - hso_std_serial_read_bulk_callback, - serial); - result = usb_submit_urb(serial->rx_urb[i], flags); - if (result) { - dev_warn(&serial->parent->usb->dev, - "Failed to submit urb - res %d\n", - result); - break; - } - } - } else { - mutex_lock(&serial->shared_int->shared_int_lock); - if (!serial->shared_int->use_count) { - result = - hso_mux_submit_intr_urb(serial->shared_int, - hso_dev->usb, flags); - } - serial->shared_int->use_count++; - mutex_unlock(&serial->shared_int->shared_int_lock); - } - if (serial->tiocmget) - tiocmget_submit_urb(serial, - serial->tiocmget, - serial->parent->usb); - return result; -} - -static int hso_stop_serial_device(struct hso_device *hso_dev) -{ - int i; - struct hso_serial *serial = dev2ser(hso_dev); - struct hso_tiocmget *tiocmget; - - if (!serial) - return -ENODEV; - - for (i = 0; i < serial->num_rx_urbs; i++) { - if (serial->rx_urb[i]) { - usb_kill_urb(serial->rx_urb[i]); - serial->rx_urb_filled[i] = 0; - } - } - serial->curr_rx_urb_idx = 0; - serial->curr_rx_urb_offset = 0; - - if (serial->tx_urb) - usb_kill_urb(serial->tx_urb); - - if (serial->shared_int) { - mutex_lock(&serial->shared_int->shared_int_lock); - if (serial->shared_int->use_count && - (--serial->shared_int->use_count == 0)) { - struct urb *urb; - - urb = serial->shared_int->shared_intr_urb; - if (urb) - usb_kill_urb(urb); - } - mutex_unlock(&serial->shared_int->shared_int_lock); - } - tiocmget = serial->tiocmget; - if (tiocmget) { - wake_up_interruptible(&tiocmget->waitq); - usb_kill_urb(tiocmget->urb); - } - - return 0; -} - -static void hso_serial_common_free(struct hso_serial *serial) -{ - int i; - - if (serial->parent->dev) - device_remove_file(serial->parent->dev, &dev_attr_hsotype); - - tty_unregister_device(tty_drv, serial->minor); - - for (i = 0; i < serial->num_rx_urbs; i++) { - /* unlink and free RX URB */ - usb_free_urb(serial->rx_urb[i]); - /* free the RX buffer */ - kfree(serial->rx_data[i]); - } - - /* unlink and free TX URB */ - usb_free_urb(serial->tx_urb); - kfree(serial->tx_data); -} - -static int hso_serial_common_create(struct hso_serial *serial, int num_urbs, - int rx_size, int tx_size) -{ - struct device *dev; - int minor; - int i; - - minor = get_free_serial_index(); - if (minor < 0) - goto exit; - - /* register our minor number */ - serial->parent->dev = tty_register_device(tty_drv, minor, - &serial->parent->interface->dev); - dev = serial->parent->dev; - dev_set_drvdata(dev, serial->parent); - i = device_create_file(dev, &dev_attr_hsotype); - - /* fill in specific data for later use */ - serial->minor = minor; - serial->magic = HSO_SERIAL_MAGIC; - spin_lock_init(&serial->serial_lock); - serial->num_rx_urbs = num_urbs; - - /* RX, allocate urb and initialize */ - - /* prepare our RX buffer */ - serial->rx_data_length = rx_size; - for (i = 0; i < serial->num_rx_urbs; i++) { - serial->rx_urb[i] = usb_alloc_urb(0, GFP_KERNEL); - if (!serial->rx_urb[i]) { - dev_err(dev, "Could not allocate urb?\n"); - goto exit; - } - serial->rx_urb[i]->transfer_buffer = NULL; - serial->rx_urb[i]->transfer_buffer_length = 0; - serial->rx_data[i] = kzalloc(serial->rx_data_length, - GFP_KERNEL); - if (!serial->rx_data[i]) { - dev_err(dev, "%s - Out of memory\n", __func__); - goto exit; - } - } - - /* TX, allocate urb and initialize */ - serial->tx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!serial->tx_urb) { - dev_err(dev, "Could not allocate urb?\n"); - goto exit; - } - serial->tx_urb->transfer_buffer = NULL; - serial->tx_urb->transfer_buffer_length = 0; - /* prepare our TX buffer */ - serial->tx_data_count = 0; - serial->tx_buffer_count = 0; - serial->tx_data_length = tx_size; - serial->tx_data = kzalloc(serial->tx_data_length, GFP_KERNEL); - if (!serial->tx_data) { - dev_err(dev, "%s - Out of memory\n", __func__); - goto exit; - } - serial->tx_buffer = kzalloc(serial->tx_data_length, GFP_KERNEL); - if (!serial->tx_buffer) { - dev_err(dev, "%s - Out of memory\n", __func__); - goto exit; - } - - return 0; -exit: - hso_serial_common_free(serial); - return -1; -} - -/* Creates a general hso device */ -static struct hso_device *hso_create_device(struct usb_interface *intf, - int port_spec) -{ - struct hso_device *hso_dev; - - hso_dev = kzalloc(sizeof(*hso_dev), GFP_ATOMIC); - if (!hso_dev) - return NULL; - - hso_dev->port_spec = port_spec; - hso_dev->usb = interface_to_usbdev(intf); - hso_dev->interface = intf; - kref_init(&hso_dev->ref); - mutex_init(&hso_dev->mutex); - - INIT_WORK(&hso_dev->async_get_intf, async_get_intf); - INIT_WORK(&hso_dev->async_put_intf, async_put_intf); - INIT_WORK(&hso_dev->reset_device, reset_device); - - return hso_dev; -} - -/* Removes a network device in the network device table */ -static int remove_net_device(struct hso_device *hso_dev) -{ - int i; - - for (i = 0; i < HSO_MAX_NET_DEVICES; i++) { - if (network_table[i] == hso_dev) { - network_table[i] = NULL; - break; - } - } - if (i == HSO_MAX_NET_DEVICES) - return -1; - return 0; -} - -/* Frees our network device */ -static void hso_free_net_device(struct hso_device *hso_dev) -{ - int i; - struct hso_net *hso_net = dev2net(hso_dev); - - if (!hso_net) - return; - - remove_net_device(hso_net->parent); - - if (hso_net->net) - unregister_netdev(hso_net->net); - - /* start freeing */ - for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) { - usb_free_urb(hso_net->mux_bulk_rx_urb_pool[i]); - kfree(hso_net->mux_bulk_rx_buf_pool[i]); - hso_net->mux_bulk_rx_buf_pool[i] = NULL; - } - usb_free_urb(hso_net->mux_bulk_tx_urb); - kfree(hso_net->mux_bulk_tx_buf); - hso_net->mux_bulk_tx_buf = NULL; - - if (hso_net->net) - free_netdev(hso_net->net); - - kfree(hso_dev); -} - -static const struct net_device_ops hso_netdev_ops = { - .ndo_open = hso_net_open, - .ndo_stop = hso_net_close, - .ndo_start_xmit = hso_net_start_xmit, - .ndo_tx_timeout = hso_net_tx_timeout, -}; - -/* initialize the network interface */ -static void hso_net_init(struct net_device *net) -{ - struct hso_net *hso_net = netdev_priv(net); - - D1("sizeof hso_net is %d", (int)sizeof(*hso_net)); - - /* fill in the other fields */ - net->netdev_ops = &hso_netdev_ops; - net->watchdog_timeo = HSO_NET_TX_TIMEOUT; - net->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; - net->type = ARPHRD_NONE; - net->mtu = DEFAULT_MTU - 14; - net->tx_queue_len = 10; - SET_ETHTOOL_OPS(net, &ops); - - /* and initialize the semaphore */ - spin_lock_init(&hso_net->net_lock); -} - -/* Adds a network device in the network device table */ -static int add_net_device(struct hso_device *hso_dev) -{ - int i; - - for (i = 0; i < HSO_MAX_NET_DEVICES; i++) { - if (network_table[i] == NULL) { - network_table[i] = hso_dev; - break; - } - } - if (i == HSO_MAX_NET_DEVICES) - return -1; - return 0; -} - -static int hso_rfkill_set_block(void *data, bool blocked) -{ - struct hso_device *hso_dev = data; - int enabled = !blocked; - int rv; - - mutex_lock(&hso_dev->mutex); - if (hso_dev->usb_gone) - rv = 0; - else - rv = usb_control_msg(hso_dev->usb, usb_rcvctrlpipe(hso_dev->usb, 0), - enabled ? 0x82 : 0x81, 0x40, 0, 0, NULL, 0, - USB_CTRL_SET_TIMEOUT); - mutex_unlock(&hso_dev->mutex); - return rv; -} - -static const struct rfkill_ops hso_rfkill_ops = { - .set_block = hso_rfkill_set_block, -}; - -/* Creates and sets up everything for rfkill */ -static void hso_create_rfkill(struct hso_device *hso_dev, - struct usb_interface *interface) -{ - struct hso_net *hso_net = dev2net(hso_dev); - struct device *dev = &hso_net->net->dev; - char *rfkn; - - rfkn = kzalloc(20, GFP_KERNEL); - if (!rfkn) - dev_err(dev, "%s - Out of memory\n", __func__); - - snprintf(rfkn, 20, "hso-%d", - interface->altsetting->desc.bInterfaceNumber); - - hso_net->rfkill = rfkill_alloc(rfkn, - &interface_to_usbdev(interface)->dev, - RFKILL_TYPE_WWAN, - &hso_rfkill_ops, hso_dev); - if (!hso_net->rfkill) { - dev_err(dev, "%s - Out of memory\n", __func__); - kfree(rfkn); - return; - } - if (rfkill_register(hso_net->rfkill) < 0) { - rfkill_destroy(hso_net->rfkill); - kfree(rfkn); - hso_net->rfkill = NULL; - dev_err(dev, "%s - Failed to register rfkill\n", __func__); - return; - } -} - -static struct device_type hso_type = { - .name = "wwan", -}; - -/* Creates our network device */ -static struct hso_device *hso_create_net_device(struct usb_interface *interface, - int port_spec) -{ - int result, i; - struct net_device *net; - struct hso_net *hso_net; - struct hso_device *hso_dev; - - hso_dev = hso_create_device(interface, port_spec); - if (!hso_dev) - return NULL; - - /* allocate our network device, then we can put in our private data */ - /* call hso_net_init to do the basic initialization */ - net = alloc_netdev(sizeof(struct hso_net), "hso%d", hso_net_init); - if (!net) { - dev_err(&interface->dev, "Unable to create ethernet device\n"); - goto exit; - } - - hso_net = netdev_priv(net); - - hso_dev->port_data.dev_net = hso_net; - hso_net->net = net; - hso_net->parent = hso_dev; - - hso_net->in_endp = hso_get_ep(interface, USB_ENDPOINT_XFER_BULK, - USB_DIR_IN); - if (!hso_net->in_endp) { - dev_err(&interface->dev, "Can't find BULK IN endpoint\n"); - goto exit; - } - hso_net->out_endp = hso_get_ep(interface, USB_ENDPOINT_XFER_BULK, - USB_DIR_OUT); - if (!hso_net->out_endp) { - dev_err(&interface->dev, "Can't find BULK OUT endpoint\n"); - goto exit; - } - SET_NETDEV_DEV(net, &interface->dev); - SET_NETDEV_DEVTYPE(net, &hso_type); - - /* registering our net device */ - result = register_netdev(net); - if (result) { - dev_err(&interface->dev, "Failed to register device\n"); - goto exit; - } - - /* start allocating */ - for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) { - hso_net->mux_bulk_rx_urb_pool[i] = usb_alloc_urb(0, GFP_KERNEL); - if (!hso_net->mux_bulk_rx_urb_pool[i]) { - dev_err(&interface->dev, "Could not allocate rx urb\n"); - goto exit; - } - hso_net->mux_bulk_rx_buf_pool[i] = kzalloc(MUX_BULK_RX_BUF_SIZE, - GFP_KERNEL); - if (!hso_net->mux_bulk_rx_buf_pool[i]) { - dev_err(&interface->dev, "Could not allocate rx buf\n"); - goto exit; - } - } - hso_net->mux_bulk_tx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!hso_net->mux_bulk_tx_urb) { - dev_err(&interface->dev, "Could not allocate tx urb\n"); - goto exit; - } - hso_net->mux_bulk_tx_buf = kzalloc(MUX_BULK_TX_BUF_SIZE, GFP_KERNEL); - if (!hso_net->mux_bulk_tx_buf) { - dev_err(&interface->dev, "Could not allocate tx buf\n"); - goto exit; - } - - add_net_device(hso_dev); - - hso_log_port(hso_dev); - - hso_create_rfkill(hso_dev, interface); - - return hso_dev; -exit: - hso_free_net_device(hso_dev); - return NULL; -} - -static void hso_free_tiomget(struct hso_serial *serial) -{ - struct hso_tiocmget *tiocmget; - if (!serial) - return; - tiocmget = serial->tiocmget; - if (tiocmget) { - usb_free_urb(tiocmget->urb); - tiocmget->urb = NULL; - serial->tiocmget = NULL; - kfree(tiocmget); - } -} - -/* Frees an AT channel ( goes for both mux and non-mux ) */ -static void hso_free_serial_device(struct hso_device *hso_dev) -{ - struct hso_serial *serial = dev2ser(hso_dev); - - if (!serial) - return; - set_serial_by_index(serial->minor, NULL); - - hso_serial_common_free(serial); - - if (serial->shared_int) { - mutex_lock(&serial->shared_int->shared_int_lock); - if (--serial->shared_int->ref_count == 0) - hso_free_shared_int(serial->shared_int); - else - mutex_unlock(&serial->shared_int->shared_int_lock); - } - hso_free_tiomget(serial); - kfree(serial); - kfree(hso_dev); -} - -/* Creates a bulk AT channel */ -static struct hso_device *hso_create_bulk_serial_device( - struct usb_interface *interface, int port) -{ - struct hso_device *hso_dev; - struct hso_serial *serial; - int num_urbs; - struct hso_tiocmget *tiocmget; - - hso_dev = hso_create_device(interface, port); - if (!hso_dev) - return NULL; - - serial = kzalloc(sizeof(*serial), GFP_KERNEL); - if (!serial) - goto exit; - - serial->parent = hso_dev; - hso_dev->port_data.dev_serial = serial; - - if ((port & HSO_PORT_MASK) == HSO_PORT_MODEM) { - num_urbs = 2; - serial->tiocmget = kzalloc(sizeof(struct hso_tiocmget), - GFP_KERNEL); - /* it isn't going to break our heart if serial->tiocmget - * allocation fails don't bother checking this. - */ - if (serial->tiocmget) { - tiocmget = serial->tiocmget; - tiocmget->urb = usb_alloc_urb(0, GFP_KERNEL); - if (tiocmget->urb) { - mutex_init(&tiocmget->mutex); - init_waitqueue_head(&tiocmget->waitq); - tiocmget->endp = hso_get_ep( - interface, - USB_ENDPOINT_XFER_INT, - USB_DIR_IN); - } else - hso_free_tiomget(serial); - } - } - else - num_urbs = 1; - - if (hso_serial_common_create(serial, num_urbs, BULK_URB_RX_SIZE, - BULK_URB_TX_SIZE)) - goto exit; - - serial->in_endp = hso_get_ep(interface, USB_ENDPOINT_XFER_BULK, - USB_DIR_IN); - if (!serial->in_endp) { - dev_err(&interface->dev, "Failed to find BULK IN ep\n"); - goto exit2; - } - - if (! - (serial->out_endp = - hso_get_ep(interface, USB_ENDPOINT_XFER_BULK, USB_DIR_OUT))) { - dev_err(&interface->dev, "Failed to find BULK IN ep\n"); - goto exit2; - } - - serial->write_data = hso_std_serial_write_data; - - /* and record this serial */ - set_serial_by_index(serial->minor, serial); - - /* setup the proc dirs and files if needed */ - hso_log_port(hso_dev); - - /* done, return it */ - return hso_dev; - -exit2: - hso_serial_common_free(serial); -exit: - hso_free_tiomget(serial); - kfree(serial); - kfree(hso_dev); - return NULL; -} - -/* Creates a multiplexed AT channel */ -static -struct hso_device *hso_create_mux_serial_device(struct usb_interface *interface, - int port, - struct hso_shared_int *mux) -{ - struct hso_device *hso_dev; - struct hso_serial *serial; - int port_spec; - - port_spec = HSO_INTF_MUX; - port_spec &= ~HSO_PORT_MASK; - - port_spec |= hso_mux_to_port(port); - if ((port_spec & HSO_PORT_MASK) == HSO_PORT_NO_PORT) - return NULL; - - hso_dev = hso_create_device(interface, port_spec); - if (!hso_dev) - return NULL; - - serial = kzalloc(sizeof(*serial), GFP_KERNEL); - if (!serial) - goto exit; - - hso_dev->port_data.dev_serial = serial; - serial->parent = hso_dev; - - if (hso_serial_common_create - (serial, 1, CTRL_URB_RX_SIZE, CTRL_URB_TX_SIZE)) - goto exit; - - serial->tx_data_length--; - serial->write_data = hso_mux_serial_write_data; - - serial->shared_int = mux; - mutex_lock(&serial->shared_int->shared_int_lock); - serial->shared_int->ref_count++; - mutex_unlock(&serial->shared_int->shared_int_lock); - - /* and record this serial */ - set_serial_by_index(serial->minor, serial); - - /* setup the proc dirs and files if needed */ - hso_log_port(hso_dev); - - /* done, return it */ - return hso_dev; - -exit: - if (serial) { - tty_unregister_device(tty_drv, serial->minor); - kfree(serial); - } - if (hso_dev) - kfree(hso_dev); - return NULL; - -} - -static void hso_free_shared_int(struct hso_shared_int *mux) -{ - usb_free_urb(mux->shared_intr_urb); - kfree(mux->shared_intr_buf); - mutex_unlock(&mux->shared_int_lock); - kfree(mux); -} - -static -struct hso_shared_int *hso_create_shared_int(struct usb_interface *interface) -{ - struct hso_shared_int *mux = kzalloc(sizeof(*mux), GFP_KERNEL); - - if (!mux) - return NULL; - - mux->intr_endp = hso_get_ep(interface, USB_ENDPOINT_XFER_INT, - USB_DIR_IN); - if (!mux->intr_endp) { - dev_err(&interface->dev, "Can't find INT IN endpoint\n"); - goto exit; - } - - mux->shared_intr_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!mux->shared_intr_urb) { - dev_err(&interface->dev, "Could not allocate intr urb?\n"); - goto exit; - } - mux->shared_intr_buf = - kzalloc(le16_to_cpu(mux->intr_endp->wMaxPacketSize), - GFP_KERNEL); - if (!mux->shared_intr_buf) { - dev_err(&interface->dev, "Could not allocate intr buf?\n"); - goto exit; - } - - mutex_init(&mux->shared_int_lock); - - return mux; - -exit: - kfree(mux->shared_intr_buf); - usb_free_urb(mux->shared_intr_urb); - kfree(mux); - return NULL; -} - -/* Gets the port spec for a certain interface */ -static int hso_get_config_data(struct usb_interface *interface) -{ - struct usb_device *usbdev = interface_to_usbdev(interface); - u8 config_data[17]; - u32 if_num = interface->altsetting->desc.bInterfaceNumber; - s32 result; - - if (usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), - 0x86, 0xC0, 0, 0, config_data, 17, - USB_CTRL_SET_TIMEOUT) != 0x11) { - return -EIO; - } - - switch (config_data[if_num]) { - case 0x0: - result = 0; - break; - case 0x1: - result = HSO_PORT_DIAG; - break; - case 0x2: - result = HSO_PORT_GPS; - break; - case 0x3: - result = HSO_PORT_GPS_CONTROL; - break; - case 0x4: - result = HSO_PORT_APP; - break; - case 0x5: - result = HSO_PORT_APP2; - break; - case 0x6: - result = HSO_PORT_CONTROL; - break; - case 0x7: - result = HSO_PORT_NETWORK; - break; - case 0x8: - result = HSO_PORT_MODEM; - break; - case 0x9: - result = HSO_PORT_MSD; - break; - case 0xa: - result = HSO_PORT_PCSC; - break; - case 0xb: - result = HSO_PORT_VOICE; - break; - default: - result = 0; - } - - if (result) - result |= HSO_INTF_BULK; - - if (config_data[16] & 0x1) - result |= HSO_INFO_CRC_BUG; - - return result; -} - -/* called once for each interface upon device insertion */ -static int hso_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - int mux, i, if_num, port_spec; - unsigned char port_mask; - struct hso_device *hso_dev = NULL; - struct hso_shared_int *shared_int; - struct hso_device *tmp_dev = NULL; - - if_num = interface->altsetting->desc.bInterfaceNumber; - - /* Get the interface/port specification from either driver_info or from - * the device itself */ - if (id->driver_info) - port_spec = ((u32 *)(id->driver_info))[if_num]; - else - port_spec = hso_get_config_data(interface); - - if (interface->cur_altsetting->desc.bInterfaceClass != 0xFF) { - dev_err(&interface->dev, "Not our interface\n"); - return -ENODEV; - } - /* Check if we need to switch to alt interfaces prior to port - * configuration */ - if (interface->num_altsetting > 1) - usb_set_interface(interface_to_usbdev(interface), if_num, 1); - interface->needs_remote_wakeup = 1; - - /* Allocate new hso device(s) */ - switch (port_spec & HSO_INTF_MASK) { - case HSO_INTF_MUX: - if ((port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) { - /* Create the network device */ - if (!disable_net) { - hso_dev = hso_create_net_device(interface, - port_spec); - if (!hso_dev) - goto exit; - tmp_dev = hso_dev; - } - } - - if (hso_get_mux_ports(interface, &port_mask)) - /* TODO: de-allocate everything */ - goto exit; - - shared_int = hso_create_shared_int(interface); - if (!shared_int) - goto exit; - - for (i = 1, mux = 0; i < 0x100; i = i << 1, mux++) { - if (port_mask & i) { - hso_dev = hso_create_mux_serial_device( - interface, i, shared_int); - if (!hso_dev) - goto exit; - } - } - - if (tmp_dev) - hso_dev = tmp_dev; - break; - - case HSO_INTF_BULK: - /* It's a regular bulk interface */ - if ((port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) { - if (!disable_net) - hso_dev = - hso_create_net_device(interface, port_spec); - } else { - hso_dev = - hso_create_bulk_serial_device(interface, port_spec); - } - if (!hso_dev) - goto exit; - break; - default: - goto exit; - } - - /* save our data pointer in this device */ - usb_set_intfdata(interface, hso_dev); - - /* done */ - return 0; -exit: - hso_free_interface(interface); - return -ENODEV; -} - -/* device removed, cleaning up */ -static void hso_disconnect(struct usb_interface *interface) -{ - hso_free_interface(interface); - - /* remove reference of our private data */ - usb_set_intfdata(interface, NULL); -} - -static void async_get_intf(struct work_struct *data) -{ - struct hso_device *hso_dev = - container_of(data, struct hso_device, async_get_intf); - usb_autopm_get_interface(hso_dev->interface); -} - -static void async_put_intf(struct work_struct *data) -{ - struct hso_device *hso_dev = - container_of(data, struct hso_device, async_put_intf); - usb_autopm_put_interface(hso_dev->interface); -} - -static int hso_get_activity(struct hso_device *hso_dev) -{ - if (hso_dev->usb->state == USB_STATE_SUSPENDED) { - if (!hso_dev->is_active) { - hso_dev->is_active = 1; - schedule_work(&hso_dev->async_get_intf); - } - } - - if (hso_dev->usb->state != USB_STATE_CONFIGURED) - return -EAGAIN; - - usb_mark_last_busy(hso_dev->usb); - - return 0; -} - -static int hso_put_activity(struct hso_device *hso_dev) -{ - if (hso_dev->usb->state != USB_STATE_SUSPENDED) { - if (hso_dev->is_active) { - hso_dev->is_active = 0; - schedule_work(&hso_dev->async_put_intf); - return -EAGAIN; - } - } - hso_dev->is_active = 0; - return 0; -} - -/* called by kernel when we need to suspend device */ -static int hso_suspend(struct usb_interface *iface, pm_message_t message) -{ - int i, result; - - /* Stop all serial ports */ - for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { - if (serial_table[i] && (serial_table[i]->interface == iface)) { - result = hso_stop_serial_device(serial_table[i]); - if (result) - goto out; - } - } - - /* Stop all network ports */ - for (i = 0; i < HSO_MAX_NET_DEVICES; i++) { - if (network_table[i] && - (network_table[i]->interface == iface)) { - result = hso_stop_net_device(network_table[i]); - if (result) - goto out; - } - } - -out: - return 0; -} - -/* called by kernel when we need to resume device */ -static int hso_resume(struct usb_interface *iface) -{ - int i, result = 0; - struct hso_net *hso_net; - - /* Start all serial ports */ - for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { - if (serial_table[i] && (serial_table[i]->interface == iface)) { - if (dev2ser(serial_table[i])->open_count) { - result = - hso_start_serial_device(serial_table[i], GFP_NOIO); - hso_kick_transmit(dev2ser(serial_table[i])); - if (result) - goto out; - } - } - } - - /* Start all network ports */ - for (i = 0; i < HSO_MAX_NET_DEVICES; i++) { - if (network_table[i] && - (network_table[i]->interface == iface)) { - hso_net = dev2net(network_table[i]); - if (hso_net->flags & IFF_UP) { - /* First transmit any lingering data, - then restart the device. */ - if (hso_net->skb_tx_buf) { - dev_dbg(&iface->dev, - "Transmitting" - " lingering data\n"); - hso_net_start_xmit(hso_net->skb_tx_buf, - hso_net->net); - hso_net->skb_tx_buf = NULL; - } - result = hso_start_net_device(network_table[i]); - if (result) - goto out; - } - } - } - -out: - return result; -} - -static void reset_device(struct work_struct *data) -{ - struct hso_device *hso_dev = - container_of(data, struct hso_device, reset_device); - struct usb_device *usb = hso_dev->usb; - int result; - - if (hso_dev->usb_gone) { - D1("No reset during disconnect\n"); - } else { - result = usb_lock_device_for_reset(usb, hso_dev->interface); - if (result < 0) - D1("unable to lock device for reset: %d\n", result); - else { - usb_reset_device(usb); - usb_unlock_device(usb); - } - } -} - -static void hso_serial_ref_free(struct kref *ref) -{ - struct hso_device *hso_dev = container_of(ref, struct hso_device, ref); - - hso_free_serial_device(hso_dev); -} - -static void hso_free_interface(struct usb_interface *interface) -{ - struct hso_serial *hso_dev; - struct tty_struct *tty; - int i; - - for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { - if (serial_table[i] && - (serial_table[i]->interface == interface)) { - hso_dev = dev2ser(serial_table[i]); - spin_lock_irq(&hso_dev->serial_lock); - tty = tty_kref_get(hso_dev->tty); - spin_unlock_irq(&hso_dev->serial_lock); - if (tty) - tty_hangup(tty); - mutex_lock(&hso_dev->parent->mutex); - tty_kref_put(tty); - hso_dev->parent->usb_gone = 1; - mutex_unlock(&hso_dev->parent->mutex); - kref_put(&serial_table[i]->ref, hso_serial_ref_free); - } - } - - for (i = 0; i < HSO_MAX_NET_DEVICES; i++) { - if (network_table[i] && - (network_table[i]->interface == interface)) { - struct rfkill *rfk = dev2net(network_table[i])->rfkill; - /* hso_stop_net_device doesn't stop the net queue since - * traffic needs to start it again when suspended */ - netif_stop_queue(dev2net(network_table[i])->net); - hso_stop_net_device(network_table[i]); - cancel_work_sync(&network_table[i]->async_put_intf); - cancel_work_sync(&network_table[i]->async_get_intf); - if (rfk) { - rfkill_unregister(rfk); - rfkill_destroy(rfk); - } - hso_free_net_device(network_table[i]); - } - } -} - -/* Helper functions */ - -/* Get the endpoint ! */ -static struct usb_endpoint_descriptor *hso_get_ep(struct usb_interface *intf, - int type, int dir) -{ - int i; - struct usb_host_interface *iface = intf->cur_altsetting; - struct usb_endpoint_descriptor *endp; - - for (i = 0; i < iface->desc.bNumEndpoints; i++) { - endp = &iface->endpoint[i].desc; - if (((endp->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == dir) && - (usb_endpoint_type(endp) == type)) - return endp; - } - - return NULL; -} - -/* Get the byte that describes which ports are enabled */ -static int hso_get_mux_ports(struct usb_interface *intf, unsigned char *ports) -{ - int i; - struct usb_host_interface *iface = intf->cur_altsetting; - - if (iface->extralen == 3) { - *ports = iface->extra[2]; - return 0; - } - - for (i = 0; i < iface->desc.bNumEndpoints; i++) { - if (iface->endpoint[i].extralen == 3) { - *ports = iface->endpoint[i].extra[2]; - return 0; - } - } - - return -1; -} - -/* interrupt urb needs to be submitted, used for serial read of muxed port */ -static int hso_mux_submit_intr_urb(struct hso_shared_int *shared_int, - struct usb_device *usb, gfp_t gfp) -{ - int result; - - usb_fill_int_urb(shared_int->shared_intr_urb, usb, - usb_rcvintpipe(usb, - shared_int->intr_endp->bEndpointAddress & 0x7F), - shared_int->shared_intr_buf, - 1, - intr_callback, shared_int, - shared_int->intr_endp->bInterval); - - result = usb_submit_urb(shared_int->shared_intr_urb, gfp); - if (result) - dev_warn(&usb->dev, "%s failed mux_intr_urb %d\n", __func__, - result); - - return result; -} - -/* operations setup of the serial interface */ -static const struct tty_operations hso_serial_ops = { - .open = hso_serial_open, - .close = hso_serial_close, - .write = hso_serial_write, - .write_room = hso_serial_write_room, - .ioctl = hso_serial_ioctl, - .set_termios = hso_serial_set_termios, - .chars_in_buffer = hso_serial_chars_in_buffer, - .tiocmget = hso_serial_tiocmget, - .tiocmset = hso_serial_tiocmset, - .get_icount = hso_get_count, - .unthrottle = hso_unthrottle -}; - -static struct usb_driver hso_driver = { - .name = driver_name, - .probe = hso_probe, - .disconnect = hso_disconnect, - .id_table = hso_ids, - .suspend = hso_suspend, - .resume = hso_resume, - .reset_resume = hso_resume, - .supports_autosuspend = 1, -}; - -static int __init hso_init(void) -{ - int i; - int result; - - /* put it in the log */ - printk(KERN_INFO "hso: %s\n", version); - - /* Initialise the serial table semaphore and table */ - spin_lock_init(&serial_table_lock); - for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) - serial_table[i] = NULL; - - /* allocate our driver using the proper amount of supported minors */ - tty_drv = alloc_tty_driver(HSO_SERIAL_TTY_MINORS); - if (!tty_drv) - return -ENOMEM; - - /* fill in all needed values */ - tty_drv->magic = TTY_DRIVER_MAGIC; - tty_drv->driver_name = driver_name; - tty_drv->name = tty_filename; - - /* if major number is provided as parameter, use that one */ - if (tty_major) - tty_drv->major = tty_major; - - tty_drv->minor_start = 0; - tty_drv->type = TTY_DRIVER_TYPE_SERIAL; - tty_drv->subtype = SERIAL_TYPE_NORMAL; - tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; - tty_drv->init_termios = tty_std_termios; - hso_init_termios(&tty_drv->init_termios); - tty_set_operations(tty_drv, &hso_serial_ops); - - /* register the tty driver */ - result = tty_register_driver(tty_drv); - if (result) { - printk(KERN_ERR "%s - tty_register_driver failed(%d)\n", - __func__, result); - return result; - } - - /* register this module as an usb driver */ - result = usb_register(&hso_driver); - if (result) { - printk(KERN_ERR "Could not register hso driver? error: %d\n", - result); - /* cleanup serial interface */ - tty_unregister_driver(tty_drv); - return result; - } - - /* done */ - return 0; -} - -static void __exit hso_exit(void) -{ - printk(KERN_INFO "hso: unloaded\n"); - - tty_unregister_driver(tty_drv); - /* deregister the usb driver */ - usb_deregister(&hso_driver); -} - -/* Module definitions */ -module_init(hso_init); -module_exit(hso_exit); - -MODULE_AUTHOR(MOD_AUTHOR); -MODULE_DESCRIPTION(MOD_DESCRIPTION); -MODULE_LICENSE(MOD_LICENSE); - -/* change the debug level (eg: insmod hso.ko debug=0x04) */ -MODULE_PARM_DESC(debug, "Level of debug [0x01 | 0x02 | 0x04 | 0x08 | 0x10]"); -module_param(debug, int, S_IRUGO | S_IWUSR); - -/* set the major tty number (eg: insmod hso.ko tty_major=245) */ -MODULE_PARM_DESC(tty_major, "Set the major tty number"); -module_param(tty_major, int, S_IRUGO | S_IWUSR); - -/* disable network interface (eg: insmod hso.ko disable_net=1) */ -MODULE_PARM_DESC(disable_net, "Disable the network interface"); -module_param(disable_net, int, S_IRUGO | S_IWUSR); diff --git a/ANDROID_3.4.5/drivers/net/usb/int51x1.c b/ANDROID_3.4.5/drivers/net/usb/int51x1.c deleted file mode 100644 index 12a22a45..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/int51x1.c +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright (c) 2009 Peter Holik - * - * Intellon usb PLC (Powerline Communications) usb net driver - * - * http://www.tandel.be/downloads/INT51X1_Datasheet.pdf - * - * Based on the work of Jan 'RedBully' Seiffert - */ - -/* - * 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/ctype.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/ethtool.h> -#include <linux/slab.h> -#include <linux/mii.h> -#include <linux/usb.h> -#include <linux/usb/usbnet.h> - -#define INT51X1_VENDOR_ID 0x09e1 -#define INT51X1_PRODUCT_ID 0x5121 - -#define INT51X1_HEADER_SIZE 2 /* 2 byte header */ - -#define PACKET_TYPE_PROMISCUOUS (1 << 0) -#define PACKET_TYPE_ALL_MULTICAST (1 << 1) /* no filter */ -#define PACKET_TYPE_DIRECTED (1 << 2) -#define PACKET_TYPE_BROADCAST (1 << 3) -#define PACKET_TYPE_MULTICAST (1 << 4) /* filtered */ - -#define SET_ETHERNET_PACKET_FILTER 0x43 - -static int int51x1_rx_fixup(struct usbnet *dev, struct sk_buff *skb) -{ - int len; - - if (!(pskb_may_pull(skb, INT51X1_HEADER_SIZE))) { - netdev_err(dev->net, "unexpected tiny rx frame\n"); - return 0; - } - - len = le16_to_cpu(*(__le16 *)&skb->data[skb->len - 2]); - - skb_trim(skb, len); - - return 1; -} - -static struct sk_buff *int51x1_tx_fixup(struct usbnet *dev, - struct sk_buff *skb, gfp_t flags) -{ - int pack_len = skb->len; - int pack_with_header_len = pack_len + INT51X1_HEADER_SIZE; - int headroom = skb_headroom(skb); - int tailroom = skb_tailroom(skb); - int need_tail = 0; - __le16 *len; - - /* if packet and our header is smaler than 64 pad to 64 (+ ZLP) */ - if ((pack_with_header_len) < dev->maxpacket) - need_tail = dev->maxpacket - pack_with_header_len + 1; - /* - * usbnet would send a ZLP if packetlength mod urbsize == 0 for us, - * but we need to know ourself, because this would add to the length - * we send down to the device... - */ - else if (!(pack_with_header_len % dev->maxpacket)) - need_tail = 1; - - if (!skb_cloned(skb) && - (headroom + tailroom >= need_tail + INT51X1_HEADER_SIZE)) { - if (headroom < INT51X1_HEADER_SIZE || tailroom < need_tail) { - skb->data = memmove(skb->head + INT51X1_HEADER_SIZE, - skb->data, skb->len); - skb_set_tail_pointer(skb, skb->len); - } - } else { - struct sk_buff *skb2; - - skb2 = skb_copy_expand(skb, - INT51X1_HEADER_SIZE, - need_tail, - flags); - dev_kfree_skb_any(skb); - if (!skb2) - return NULL; - skb = skb2; - } - - pack_len += need_tail; - pack_len &= 0x07ff; - - len = (__le16 *) __skb_push(skb, INT51X1_HEADER_SIZE); - *len = cpu_to_le16(pack_len); - - if(need_tail) - memset(__skb_put(skb, need_tail), 0, need_tail); - - return skb; -} - -static void int51x1_async_cmd_callback(struct urb *urb) -{ - struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; - int status = urb->status; - - if (status < 0) - dev_warn(&urb->dev->dev, "async callback failed with %d\n", status); - - kfree(req); - usb_free_urb(urb); -} - -static void int51x1_set_multicast(struct net_device *netdev) -{ - struct usb_ctrlrequest *req; - int status; - struct urb *urb; - struct usbnet *dev = netdev_priv(netdev); - u16 filter = PACKET_TYPE_DIRECTED | PACKET_TYPE_BROADCAST; - - if (netdev->flags & IFF_PROMISC) { - /* do not expect to see traffic of other PLCs */ - filter |= PACKET_TYPE_PROMISCUOUS; - netdev_info(dev->net, "promiscuous mode enabled\n"); - } else if (!netdev_mc_empty(netdev) || - (netdev->flags & IFF_ALLMULTI)) { - filter |= PACKET_TYPE_ALL_MULTICAST; - netdev_dbg(dev->net, "receive all multicast enabled\n"); - } else { - /* ~PROMISCUOUS, ~MULTICAST */ - netdev_dbg(dev->net, "receive own packets only\n"); - } - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) { - netdev_warn(dev->net, "Error allocating URB\n"); - return; - } - - req = kmalloc(sizeof(*req), GFP_ATOMIC); - if (!req) { - netdev_warn(dev->net, "Error allocating control msg\n"); - goto out; - } - - req->bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE; - req->bRequest = SET_ETHERNET_PACKET_FILTER; - req->wValue = cpu_to_le16(filter); - req->wIndex = 0; - req->wLength = 0; - - usb_fill_control_urb(urb, dev->udev, usb_sndctrlpipe(dev->udev, 0), - (void *)req, NULL, 0, - int51x1_async_cmd_callback, - (void *)req); - - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status < 0) { - netdev_warn(dev->net, "Error submitting control msg, sts=%d\n", - status); - goto out1; - } - return; -out1: - kfree(req); -out: - usb_free_urb(urb); -} - -static const struct net_device_ops int51x1_netdev_ops = { - .ndo_open = usbnet_open, - .ndo_stop = usbnet_stop, - .ndo_start_xmit = usbnet_start_xmit, - .ndo_tx_timeout = usbnet_tx_timeout, - .ndo_change_mtu = usbnet_change_mtu, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, - .ndo_set_rx_mode = int51x1_set_multicast, -}; - -static int int51x1_bind(struct usbnet *dev, struct usb_interface *intf) -{ - int status = usbnet_get_ethernet_addr(dev, 3); - - if (status) - return status; - - dev->net->hard_header_len += INT51X1_HEADER_SIZE; - dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len; - dev->net->netdev_ops = &int51x1_netdev_ops; - - return usbnet_get_endpoints(dev, intf); -} - -static const struct driver_info int51x1_info = { - .description = "Intellon usb powerline adapter", - .bind = int51x1_bind, - .rx_fixup = int51x1_rx_fixup, - .tx_fixup = int51x1_tx_fixup, - .in = 1, - .out = 2, - .flags = FLAG_ETHER, -}; - -static const struct usb_device_id products[] = { - { - USB_DEVICE(INT51X1_VENDOR_ID, INT51X1_PRODUCT_ID), - .driver_info = (unsigned long) &int51x1_info, - }, - {}, -}; -MODULE_DEVICE_TABLE(usb, products); - -static struct usb_driver int51x1_driver = { - .name = "int51x1", - .id_table = products, - .probe = usbnet_probe, - .disconnect = usbnet_disconnect, - .suspend = usbnet_suspend, - .resume = usbnet_resume, -}; - -module_usb_driver(int51x1_driver); - -MODULE_AUTHOR("Peter Holik"); -MODULE_DESCRIPTION("Intellon usb powerline adapter"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/net/usb/ipheth.c b/ANDROID_3.4.5/drivers/net/usb/ipheth.c deleted file mode 100644 index 5cba4151..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/ipheth.c +++ /dev/null @@ -1,560 +0,0 @@ -/* - * ipheth.c - Apple iPhone USB Ethernet driver - * - * Copyright (c) 2009 Diego Giagio <diego@giagio.com> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of GIAGIO.COM nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * Alternatively, provided that this notice is retained in full, this - * software may be distributed under the terms of the GNU General - * Public License ("GPL") version 2, in which case the provisions of the - * GPL apply INSTEAD OF those given above. - * - * The provided data structures and external interfaces from this code - * are not restricted to be used by modules with a GPL compatible license. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * - * Attention: iPhone device must be paired, otherwise it won't respond to our - * driver. For more info: http://giagio.com/wiki/moin.cgi/iPhoneEthernetDriver - * - */ - -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/ethtool.h> -#include <linux/usb.h> -#include <linux/workqueue.h> - -#define USB_VENDOR_APPLE 0x05ac -#define USB_PRODUCT_IPHONE 0x1290 -#define USB_PRODUCT_IPHONE_3G 0x1292 -#define USB_PRODUCT_IPHONE_3GS 0x1294 -#define USB_PRODUCT_IPHONE_4 0x1297 -#define USB_PRODUCT_IPAD 0x129a -#define USB_PRODUCT_IPHONE_4_VZW 0x129c -#define USB_PRODUCT_IPHONE_4S 0x12a0 - -#define IPHETH_USBINTF_CLASS 255 -#define IPHETH_USBINTF_SUBCLASS 253 -#define IPHETH_USBINTF_PROTO 1 - -#define IPHETH_BUF_SIZE 1516 -#define IPHETH_IP_ALIGN 2 /* padding at front of URB */ -#define IPHETH_TX_TIMEOUT (5 * HZ) - -#define IPHETH_INTFNUM 2 -#define IPHETH_ALT_INTFNUM 1 - -#define IPHETH_CTRL_ENDP 0x00 -#define IPHETH_CTRL_BUF_SIZE 0x40 -#define IPHETH_CTRL_TIMEOUT (5 * HZ) - -#define IPHETH_CMD_GET_MACADDR 0x00 -#define IPHETH_CMD_CARRIER_CHECK 0x45 - -#define IPHETH_CARRIER_CHECK_TIMEOUT round_jiffies_relative(1 * HZ) -#define IPHETH_CARRIER_ON 0x04 - -static struct usb_device_id ipheth_table[] = { - { USB_DEVICE_AND_INTERFACE_INFO( - USB_VENDOR_APPLE, USB_PRODUCT_IPHONE, - IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, - IPHETH_USBINTF_PROTO) }, - { USB_DEVICE_AND_INTERFACE_INFO( - USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_3G, - IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, - IPHETH_USBINTF_PROTO) }, - { USB_DEVICE_AND_INTERFACE_INFO( - USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_3GS, - IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, - IPHETH_USBINTF_PROTO) }, - { USB_DEVICE_AND_INTERFACE_INFO( - USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4, - IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, - IPHETH_USBINTF_PROTO) }, - { USB_DEVICE_AND_INTERFACE_INFO( - USB_VENDOR_APPLE, USB_PRODUCT_IPAD, - IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, - IPHETH_USBINTF_PROTO) }, - { USB_DEVICE_AND_INTERFACE_INFO( - USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4_VZW, - IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, - IPHETH_USBINTF_PROTO) }, - { USB_DEVICE_AND_INTERFACE_INFO( - USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4S, - IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, - IPHETH_USBINTF_PROTO) }, - { } -}; -MODULE_DEVICE_TABLE(usb, ipheth_table); - -struct ipheth_device { - struct usb_device *udev; - struct usb_interface *intf; - struct net_device *net; - struct sk_buff *tx_skb; - struct urb *tx_urb; - struct urb *rx_urb; - unsigned char *tx_buf; - unsigned char *rx_buf; - unsigned char *ctrl_buf; - u8 bulk_in; - u8 bulk_out; - struct delayed_work carrier_work; -}; - -static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags); - -static int ipheth_alloc_urbs(struct ipheth_device *iphone) -{ - struct urb *tx_urb = NULL; - struct urb *rx_urb = NULL; - u8 *tx_buf = NULL; - u8 *rx_buf = NULL; - - tx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (tx_urb == NULL) - goto error_nomem; - - rx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (rx_urb == NULL) - goto free_tx_urb; - - tx_buf = usb_alloc_coherent(iphone->udev, IPHETH_BUF_SIZE, - GFP_KERNEL, &tx_urb->transfer_dma); - if (tx_buf == NULL) - goto free_rx_urb; - - rx_buf = usb_alloc_coherent(iphone->udev, IPHETH_BUF_SIZE, - GFP_KERNEL, &rx_urb->transfer_dma); - if (rx_buf == NULL) - goto free_tx_buf; - - - iphone->tx_urb = tx_urb; - iphone->rx_urb = rx_urb; - iphone->tx_buf = tx_buf; - iphone->rx_buf = rx_buf; - return 0; - -free_tx_buf: - usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, tx_buf, - tx_urb->transfer_dma); -free_rx_urb: - usb_free_urb(rx_urb); -free_tx_urb: - usb_free_urb(tx_urb); -error_nomem: - return -ENOMEM; -} - -static void ipheth_free_urbs(struct ipheth_device *iphone) -{ - usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, iphone->rx_buf, - iphone->rx_urb->transfer_dma); - usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, iphone->tx_buf, - iphone->tx_urb->transfer_dma); - usb_free_urb(iphone->rx_urb); - usb_free_urb(iphone->tx_urb); -} - -static void ipheth_kill_urbs(struct ipheth_device *dev) -{ - usb_kill_urb(dev->tx_urb); - usb_kill_urb(dev->rx_urb); -} - -static void ipheth_rcvbulk_callback(struct urb *urb) -{ - struct ipheth_device *dev; - struct sk_buff *skb; - int status; - char *buf; - int len; - - dev = urb->context; - if (dev == NULL) - return; - - status = urb->status; - switch (status) { - case -ENOENT: - case -ECONNRESET: - case -ESHUTDOWN: - return; - case 0: - break; - default: - err("%s: urb status: %d", __func__, status); - return; - } - - if (urb->actual_length <= IPHETH_IP_ALIGN) { - dev->net->stats.rx_length_errors++; - return; - } - len = urb->actual_length - IPHETH_IP_ALIGN; - buf = urb->transfer_buffer + IPHETH_IP_ALIGN; - - skb = dev_alloc_skb(len); - if (!skb) { - err("%s: dev_alloc_skb: -ENOMEM", __func__); - dev->net->stats.rx_dropped++; - return; - } - - memcpy(skb_put(skb, len), buf, len); - skb->dev = dev->net; - skb->protocol = eth_type_trans(skb, dev->net); - - dev->net->stats.rx_packets++; - dev->net->stats.rx_bytes += len; - - netif_rx(skb); - ipheth_rx_submit(dev, GFP_ATOMIC); -} - -static void ipheth_sndbulk_callback(struct urb *urb) -{ - struct ipheth_device *dev; - int status = urb->status; - - dev = urb->context; - if (dev == NULL) - return; - - if (status != 0 && - status != -ENOENT && - status != -ECONNRESET && - status != -ESHUTDOWN) - err("%s: urb status: %d", __func__, status); - - dev_kfree_skb_irq(dev->tx_skb); - netif_wake_queue(dev->net); -} - -static int ipheth_carrier_set(struct ipheth_device *dev) -{ - struct usb_device *udev = dev->udev; - int retval; - - retval = usb_control_msg(udev, - usb_rcvctrlpipe(udev, IPHETH_CTRL_ENDP), - IPHETH_CMD_CARRIER_CHECK, /* request */ - 0xc0, /* request type */ - 0x00, /* value */ - 0x02, /* index */ - dev->ctrl_buf, IPHETH_CTRL_BUF_SIZE, - IPHETH_CTRL_TIMEOUT); - if (retval < 0) { - err("%s: usb_control_msg: %d", __func__, retval); - return retval; - } - - if (dev->ctrl_buf[0] == IPHETH_CARRIER_ON) - netif_carrier_on(dev->net); - else - netif_carrier_off(dev->net); - - return 0; -} - -static void ipheth_carrier_check_work(struct work_struct *work) -{ - struct ipheth_device *dev = container_of(work, struct ipheth_device, - carrier_work.work); - - ipheth_carrier_set(dev); - schedule_delayed_work(&dev->carrier_work, IPHETH_CARRIER_CHECK_TIMEOUT); -} - -static int ipheth_get_macaddr(struct ipheth_device *dev) -{ - struct usb_device *udev = dev->udev; - struct net_device *net = dev->net; - int retval; - - retval = usb_control_msg(udev, - usb_rcvctrlpipe(udev, IPHETH_CTRL_ENDP), - IPHETH_CMD_GET_MACADDR, /* request */ - 0xc0, /* request type */ - 0x00, /* value */ - 0x02, /* index */ - dev->ctrl_buf, - IPHETH_CTRL_BUF_SIZE, - IPHETH_CTRL_TIMEOUT); - if (retval < 0) { - err("%s: usb_control_msg: %d", __func__, retval); - } else if (retval < ETH_ALEN) { - err("%s: usb_control_msg: short packet: %d bytes", - __func__, retval); - retval = -EINVAL; - } else { - memcpy(net->dev_addr, dev->ctrl_buf, ETH_ALEN); - retval = 0; - } - - return retval; -} - -static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags) -{ - struct usb_device *udev = dev->udev; - int retval; - - usb_fill_bulk_urb(dev->rx_urb, udev, - usb_rcvbulkpipe(udev, dev->bulk_in), - dev->rx_buf, IPHETH_BUF_SIZE, - ipheth_rcvbulk_callback, - dev); - dev->rx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - - retval = usb_submit_urb(dev->rx_urb, mem_flags); - if (retval) - err("%s: usb_submit_urb: %d", __func__, retval); - return retval; -} - -static int ipheth_open(struct net_device *net) -{ - struct ipheth_device *dev = netdev_priv(net); - struct usb_device *udev = dev->udev; - int retval = 0; - - usb_set_interface(udev, IPHETH_INTFNUM, IPHETH_ALT_INTFNUM); - - retval = ipheth_carrier_set(dev); - if (retval) - return retval; - - retval = ipheth_rx_submit(dev, GFP_KERNEL); - if (retval) - return retval; - - schedule_delayed_work(&dev->carrier_work, IPHETH_CARRIER_CHECK_TIMEOUT); - netif_start_queue(net); - return retval; -} - -static int ipheth_close(struct net_device *net) -{ - struct ipheth_device *dev = netdev_priv(net); - - cancel_delayed_work_sync(&dev->carrier_work); - netif_stop_queue(net); - return 0; -} - -static int ipheth_tx(struct sk_buff *skb, struct net_device *net) -{ - struct ipheth_device *dev = netdev_priv(net); - struct usb_device *udev = dev->udev; - int retval; - - /* Paranoid */ - if (skb->len > IPHETH_BUF_SIZE) { - WARN(1, "%s: skb too large: %d bytes\n", __func__, skb->len); - dev->net->stats.tx_dropped++; - dev_kfree_skb_irq(skb); - return NETDEV_TX_OK; - } - - memcpy(dev->tx_buf, skb->data, skb->len); - if (skb->len < IPHETH_BUF_SIZE) - memset(dev->tx_buf + skb->len, 0, IPHETH_BUF_SIZE - skb->len); - - usb_fill_bulk_urb(dev->tx_urb, udev, - usb_sndbulkpipe(udev, dev->bulk_out), - dev->tx_buf, IPHETH_BUF_SIZE, - ipheth_sndbulk_callback, - dev); - dev->tx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - - retval = usb_submit_urb(dev->tx_urb, GFP_ATOMIC); - if (retval) { - err("%s: usb_submit_urb: %d", __func__, retval); - dev->net->stats.tx_errors++; - dev_kfree_skb_irq(skb); - } else { - dev->tx_skb = skb; - - dev->net->stats.tx_packets++; - dev->net->stats.tx_bytes += skb->len; - netif_stop_queue(net); - } - - return NETDEV_TX_OK; -} - -static void ipheth_tx_timeout(struct net_device *net) -{ - struct ipheth_device *dev = netdev_priv(net); - - err("%s: TX timeout", __func__); - dev->net->stats.tx_errors++; - usb_unlink_urb(dev->tx_urb); -} - -static u32 ipheth_ethtool_op_get_link(struct net_device *net) -{ - struct ipheth_device *dev = netdev_priv(net); - return netif_carrier_ok(dev->net); -} - -static const struct ethtool_ops ops = { - .get_link = ipheth_ethtool_op_get_link -}; - -static const struct net_device_ops ipheth_netdev_ops = { - .ndo_open = ipheth_open, - .ndo_stop = ipheth_close, - .ndo_start_xmit = ipheth_tx, - .ndo_tx_timeout = ipheth_tx_timeout, -}; - -static int ipheth_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct usb_host_interface *hintf; - struct usb_endpoint_descriptor *endp; - struct ipheth_device *dev; - struct net_device *netdev; - int i; - int retval; - - netdev = alloc_etherdev(sizeof(struct ipheth_device)); - if (!netdev) - return -ENOMEM; - - netdev->netdev_ops = &ipheth_netdev_ops; - netdev->watchdog_timeo = IPHETH_TX_TIMEOUT; - strcpy(netdev->name, "eth%d"); - - dev = netdev_priv(netdev); - dev->udev = udev; - dev->net = netdev; - dev->intf = intf; - - /* Set up endpoints */ - hintf = usb_altnum_to_altsetting(intf, IPHETH_ALT_INTFNUM); - if (hintf == NULL) { - retval = -ENODEV; - err("Unable to find alternate settings interface"); - goto err_endpoints; - } - - for (i = 0; i < hintf->desc.bNumEndpoints; i++) { - endp = &hintf->endpoint[i].desc; - if (usb_endpoint_is_bulk_in(endp)) - dev->bulk_in = endp->bEndpointAddress; - else if (usb_endpoint_is_bulk_out(endp)) - dev->bulk_out = endp->bEndpointAddress; - } - if (!(dev->bulk_in && dev->bulk_out)) { - retval = -ENODEV; - err("Unable to find endpoints"); - goto err_endpoints; - } - - dev->ctrl_buf = kmalloc(IPHETH_CTRL_BUF_SIZE, GFP_KERNEL); - if (dev->ctrl_buf == NULL) { - retval = -ENOMEM; - goto err_alloc_ctrl_buf; - } - - retval = ipheth_get_macaddr(dev); - if (retval) - goto err_get_macaddr; - - INIT_DELAYED_WORK(&dev->carrier_work, ipheth_carrier_check_work); - - retval = ipheth_alloc_urbs(dev); - if (retval) { - err("error allocating urbs: %d", retval); - goto err_alloc_urbs; - } - - usb_set_intfdata(intf, dev); - - SET_NETDEV_DEV(netdev, &intf->dev); - SET_ETHTOOL_OPS(netdev, &ops); - - retval = register_netdev(netdev); - if (retval) { - err("error registering netdev: %d", retval); - retval = -EIO; - goto err_register_netdev; - } - - dev_info(&intf->dev, "Apple iPhone USB Ethernet device attached\n"); - return 0; - -err_register_netdev: - ipheth_free_urbs(dev); -err_alloc_urbs: -err_get_macaddr: -err_alloc_ctrl_buf: - kfree(dev->ctrl_buf); -err_endpoints: - free_netdev(netdev); - return retval; -} - -static void ipheth_disconnect(struct usb_interface *intf) -{ - struct ipheth_device *dev; - - dev = usb_get_intfdata(intf); - if (dev != NULL) { - unregister_netdev(dev->net); - ipheth_kill_urbs(dev); - ipheth_free_urbs(dev); - kfree(dev->ctrl_buf); - free_netdev(dev->net); - } - usb_set_intfdata(intf, NULL); - dev_info(&intf->dev, "Apple iPhone USB Ethernet now disconnected\n"); -} - -static struct usb_driver ipheth_driver = { - .name = "ipheth", - .probe = ipheth_probe, - .disconnect = ipheth_disconnect, - .id_table = ipheth_table, -}; - -module_usb_driver(ipheth_driver); - -MODULE_AUTHOR("Diego Giagio <diego@giagio.com>"); -MODULE_DESCRIPTION("Apple iPhone USB Ethernet driver"); -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/ANDROID_3.4.5/drivers/net/usb/kalmia.c b/ANDROID_3.4.5/drivers/net/usb/kalmia.c deleted file mode 100644 index 7562649b..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/kalmia.c +++ /dev/null @@ -1,382 +0,0 @@ -/* - * USB network interface driver for Samsung Kalmia based LTE USB modem like the - * Samsung GT-B3730 and GT-B3710. - * - * Copyright (C) 2011 Marius Bjoernstad Kotsbak <marius@kotsbak.com> - * - * Sponsored by Quicklink Video Distribution Services Ltd. - * - * Based on the cdc_eem module. - * - * 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. - */ - -#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/crc32.h> -#include <linux/usb/cdc.h> -#include <linux/usb/usbnet.h> -#include <linux/gfp.h> - -/* - * The Samsung Kalmia based LTE USB modems have a CDC ACM port for modem control - * handled by the "option" module and an ethernet data port handled by this - * module. - * - * The stick must first be switched into modem mode by usb_modeswitch - * or similar tool. Then the modem gets sent two initialization packets by - * this module, which gives the MAC address of the device. User space can then - * connect the modem using AT commands through the ACM port and then use - * DHCP on the network interface exposed by this module. Network packets are - * sent to and from the modem in a proprietary format discovered after watching - * the behavior of the windows driver for the modem. - * - * More information about the use of the modem is available in usb_modeswitch - * forum and the project page: - * - * http://www.draisberghof.de/usb_modeswitch/bb/viewtopic.php?t=465 - * https://github.com/mkotsbak/Samsung-GT-B3730-linux-driver - */ - -/* #define DEBUG */ -/* #define VERBOSE */ - -#define KALMIA_HEADER_LENGTH 6 -#define KALMIA_ALIGN_SIZE 4 -#define KALMIA_USB_TIMEOUT 10000 - -/*-------------------------------------------------------------------------*/ - -static int -kalmia_send_init_packet(struct usbnet *dev, u8 *init_msg, u8 init_msg_len, - u8 *buffer, u8 expected_len) -{ - int act_len; - int status; - - netdev_dbg(dev->net, "Sending init packet"); - - status = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 0x02), - init_msg, init_msg_len, &act_len, KALMIA_USB_TIMEOUT); - if (status != 0) { - netdev_err(dev->net, - "Error sending init packet. Status %i, length %i\n", - status, act_len); - return status; - } - else if (act_len != init_msg_len) { - netdev_err(dev->net, - "Did not send all of init packet. Bytes sent: %i", - act_len); - } - else { - netdev_dbg(dev->net, "Successfully sent init packet."); - } - - status = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, 0x81), - buffer, expected_len, &act_len, KALMIA_USB_TIMEOUT); - - if (status != 0) - netdev_err(dev->net, - "Error receiving init result. Status %i, length %i\n", - status, act_len); - else if (act_len != expected_len) - netdev_err(dev->net, "Unexpected init result length: %i\n", - act_len); - - return status; -} - -static int -kalmia_init_and_get_ethernet_addr(struct usbnet *dev, u8 *ethernet_addr) -{ - static const char init_msg_1[] = - { 0x57, 0x50, 0x04, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, - 0x00, 0x00 }; - static const char init_msg_2[] = - { 0x57, 0x50, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xf4, - 0x00, 0x00 }; - static const int buflen = 28; - char *usb_buf; - int status; - - usb_buf = kmalloc(buflen, GFP_DMA | GFP_KERNEL); - if (!usb_buf) - return -ENOMEM; - - memcpy(usb_buf, init_msg_1, 12); - status = kalmia_send_init_packet(dev, usb_buf, sizeof(init_msg_1) - / sizeof(init_msg_1[0]), usb_buf, 24); - if (status != 0) - return status; - - memcpy(usb_buf, init_msg_2, 12); - status = kalmia_send_init_packet(dev, usb_buf, sizeof(init_msg_2) - / sizeof(init_msg_2[0]), usb_buf, 28); - if (status != 0) - return status; - - memcpy(ethernet_addr, usb_buf + 10, ETH_ALEN); - - kfree(usb_buf); - return status; -} - -static int -kalmia_bind(struct usbnet *dev, struct usb_interface *intf) -{ - int status; - u8 ethernet_addr[ETH_ALEN]; - - /* Don't bind to AT command interface */ - if (intf->cur_altsetting->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC) - return -EINVAL; - - dev->in = usb_rcvbulkpipe(dev->udev, 0x81 & USB_ENDPOINT_NUMBER_MASK); - dev->out = usb_sndbulkpipe(dev->udev, 0x02 & USB_ENDPOINT_NUMBER_MASK); - dev->status = NULL; - - dev->net->hard_header_len += KALMIA_HEADER_LENGTH; - dev->hard_mtu = 1400; - dev->rx_urb_size = dev->hard_mtu * 10; // Found as optimal after testing - - status = kalmia_init_and_get_ethernet_addr(dev, ethernet_addr); - - if (status < 0) { - usb_set_intfdata(intf, NULL); - usb_driver_release_interface(driver_of(intf), intf); - return status; - } - - memcpy(dev->net->dev_addr, ethernet_addr, ETH_ALEN); - memcpy(dev->net->perm_addr, ethernet_addr, ETH_ALEN); - - return status; -} - -static struct sk_buff * -kalmia_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) -{ - struct sk_buff *skb2 = NULL; - u16 content_len; - unsigned char *header_start; - unsigned char ether_type_1, ether_type_2; - u8 remainder, padlen = 0; - - if (!skb_cloned(skb)) { - int headroom = skb_headroom(skb); - int tailroom = skb_tailroom(skb); - - if ((tailroom >= KALMIA_ALIGN_SIZE) && (headroom - >= KALMIA_HEADER_LENGTH)) - goto done; - - if ((headroom + tailroom) > (KALMIA_HEADER_LENGTH - + KALMIA_ALIGN_SIZE)) { - skb->data = memmove(skb->head + KALMIA_HEADER_LENGTH, - skb->data, skb->len); - skb_set_tail_pointer(skb, skb->len); - goto done; - } - } - - skb2 = skb_copy_expand(skb, KALMIA_HEADER_LENGTH, - KALMIA_ALIGN_SIZE, flags); - if (!skb2) - return NULL; - - dev_kfree_skb_any(skb); - skb = skb2; - -done: - header_start = skb_push(skb, KALMIA_HEADER_LENGTH); - ether_type_1 = header_start[KALMIA_HEADER_LENGTH + 12]; - ether_type_2 = header_start[KALMIA_HEADER_LENGTH + 13]; - - netdev_dbg(dev->net, "Sending etherType: %02x%02x", ether_type_1, - ether_type_2); - - /* According to empiric data for data packages */ - header_start[0] = 0x57; - header_start[1] = 0x44; - content_len = skb->len - KALMIA_HEADER_LENGTH; - - put_unaligned_le16(content_len, &header_start[2]); - header_start[4] = ether_type_1; - header_start[5] = ether_type_2; - - /* Align to 4 bytes by padding with zeros */ - remainder = skb->len % KALMIA_ALIGN_SIZE; - if (remainder > 0) { - padlen = KALMIA_ALIGN_SIZE - remainder; - memset(skb_put(skb, padlen), 0, padlen); - } - - netdev_dbg( - dev->net, - "Sending package with length %i and padding %i. Header: %02x:%02x:%02x:%02x:%02x:%02x.", - content_len, padlen, header_start[0], header_start[1], - header_start[2], header_start[3], header_start[4], - header_start[5]); - - return skb; -} - -static int -kalmia_rx_fixup(struct usbnet *dev, struct sk_buff *skb) -{ - /* - * Our task here is to strip off framing, leaving skb with one - * data frame for the usbnet framework code to process. - */ - static const u8 HEADER_END_OF_USB_PACKET[] = - { 0x57, 0x5a, 0x00, 0x00, 0x08, 0x00 }; - static const u8 EXPECTED_UNKNOWN_HEADER_1[] = - { 0x57, 0x43, 0x1e, 0x00, 0x15, 0x02 }; - static const u8 EXPECTED_UNKNOWN_HEADER_2[] = - { 0x57, 0x50, 0x0e, 0x00, 0x00, 0x00 }; - int i = 0; - - /* incomplete header? */ - if (skb->len < KALMIA_HEADER_LENGTH) - return 0; - - do { - struct sk_buff *skb2 = NULL; - u8 *header_start; - u16 usb_packet_length, ether_packet_length; - int is_last; - - header_start = skb->data; - - if (unlikely(header_start[0] != 0x57 || header_start[1] != 0x44)) { - if (!memcmp(header_start, EXPECTED_UNKNOWN_HEADER_1, - sizeof(EXPECTED_UNKNOWN_HEADER_1)) || !memcmp( - header_start, EXPECTED_UNKNOWN_HEADER_2, - sizeof(EXPECTED_UNKNOWN_HEADER_2))) { - netdev_dbg( - dev->net, - "Received expected unknown frame header: %02x:%02x:%02x:%02x:%02x:%02x. Package length: %i\n", - header_start[0], header_start[1], - header_start[2], header_start[3], - header_start[4], header_start[5], - skb->len - KALMIA_HEADER_LENGTH); - } - else { - netdev_err( - dev->net, - "Received unknown frame header: %02x:%02x:%02x:%02x:%02x:%02x. Package length: %i\n", - header_start[0], header_start[1], - header_start[2], header_start[3], - header_start[4], header_start[5], - skb->len - KALMIA_HEADER_LENGTH); - return 0; - } - } - else - netdev_dbg( - dev->net, - "Received header: %02x:%02x:%02x:%02x:%02x:%02x. Package length: %i\n", - header_start[0], header_start[1], header_start[2], - header_start[3], header_start[4], header_start[5], - skb->len - KALMIA_HEADER_LENGTH); - - /* subtract start header and end header */ - usb_packet_length = skb->len - (2 * KALMIA_HEADER_LENGTH); - ether_packet_length = get_unaligned_le16(&header_start[2]); - skb_pull(skb, KALMIA_HEADER_LENGTH); - - /* Some small packets misses end marker */ - if (usb_packet_length < ether_packet_length) { - ether_packet_length = usb_packet_length - + KALMIA_HEADER_LENGTH; - is_last = true; - } - else { - netdev_dbg(dev->net, "Correct package length #%i", i - + 1); - - is_last = (memcmp(skb->data + ether_packet_length, - HEADER_END_OF_USB_PACKET, - sizeof(HEADER_END_OF_USB_PACKET)) == 0); - if (!is_last) { - header_start = skb->data + ether_packet_length; - netdev_dbg( - dev->net, - "End header: %02x:%02x:%02x:%02x:%02x:%02x. Package length: %i\n", - header_start[0], header_start[1], - header_start[2], header_start[3], - header_start[4], header_start[5], - skb->len - KALMIA_HEADER_LENGTH); - } - } - - if (is_last) { - skb2 = skb; - } - else { - skb2 = skb_clone(skb, GFP_ATOMIC); - if (unlikely(!skb2)) - return 0; - } - - skb_trim(skb2, ether_packet_length); - - if (is_last) { - return 1; - } - else { - usbnet_skb_return(dev, skb2); - skb_pull(skb, ether_packet_length); - } - - i++; - } - while (skb->len); - - return 1; -} - -static const struct driver_info kalmia_info = { - .description = "Samsung Kalmia LTE USB dongle", - .flags = FLAG_WWAN, - .bind = kalmia_bind, - .rx_fixup = kalmia_rx_fixup, - .tx_fixup = kalmia_tx_fixup -}; - -/*-------------------------------------------------------------------------*/ - -static const struct usb_device_id products[] = { - /* The unswitched USB ID, to get the module auto loaded: */ - { USB_DEVICE(0x04e8, 0x689a) }, - /* The stick swithed into modem (by e.g. usb_modeswitch): */ - { USB_DEVICE(0x04e8, 0x6889), - .driver_info = (unsigned long) &kalmia_info, }, - { /* EMPTY == end of list */} }; -MODULE_DEVICE_TABLE( usb, products); - -static struct usb_driver kalmia_driver = { - .name = "kalmia", - .id_table = products, - .probe = usbnet_probe, - .disconnect = usbnet_disconnect, - .suspend = usbnet_suspend, - .resume = usbnet_resume -}; - -module_usb_driver(kalmia_driver); - -MODULE_AUTHOR("Marius Bjoernstad Kotsbak <marius@kotsbak.com>"); -MODULE_DESCRIPTION("Samsung Kalmia USB network driver"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/net/usb/kaweth.c b/ANDROID_3.4.5/drivers/net/usb/kaweth.c deleted file mode 100644 index df2a2cf3..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/kaweth.c +++ /dev/null @@ -1,1321 +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: - * 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 - * 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 <linux/firmware.h> -#include <asm/uaccess.h> -#include <asm/byteorder.h> - -#undef DEBUG - -#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 (30000) - -#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"); -MODULE_FIRMWARE("kaweth/new_code.bin"); -MODULE_FIRMWARE("kaweth/new_code_fix.bin"); -MODULE_FIRMWARE("kaweth/trigger_code.bin"); -MODULE_FIRMWARE("kaweth/trigger_code_fix.bin"); - -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(0x07c9, 0xb010) }, /* Allied Telesyn AT-USB10 USB Ethernet Adapter */ - { 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; -} __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; - int retval; - - 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_le16(value); - dr->wIndex = cpu_to_le16(index); - dr->wLength = cpu_to_le16(size); - - retval = kaweth_internal_control_msg(kaweth->dev, - pipe, - dr, - data, - size, - timeout); - - kfree(dr); - return retval; -} - -/**************************************************************** - * 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, - const char *fwname, - __u8 interrupt, - __u8 type) -{ - const struct firmware *fw; - int data_len; - int ret; - - ret = request_firmware(&fw, fwname, &kaweth->dev->dev); - if (ret) { - err("Firmware request failed\n"); - return ret; - } - - if (fw->size > KAWETH_FIRMWARE_BUF_SIZE) { - err("Firmware too big: %zu", fw->size); - release_firmware(fw); - return -ENOSPC; - } - data_len = fw->size; - memcpy(kaweth->firmware_buf, fw->data, fw->size); - - release_firmware(fw); - - 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", - fw->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 = usb_reset_configuration(kaweth->dev); - 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; - int status = u->status; - - switch (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 status = urb->status; - - 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(status == -EPIPE)) { - kaweth->stats.rx_errors++; - kaweth->end = 1; - wake_up(&kaweth->term_wait); - dbg("Status was -EPIPE."); - return; - } - if (unlikely(status == -ECONNRESET || status == -ESHUTDOWN)) { - /* we are killed - set a flag and wake the disconnect handler */ - kaweth->end = 1; - wake_up(&kaweth->term_wait); - dbg("Status was -ECONNRESET or -ESHUTDOWN."); - return; - } - if (unlikely(status == -EPROTO || status == -ETIME || - status == -EILSEQ)) { - kaweth->stats.rx_errors++; - dbg("Status was -EPROTO, -ETIME, or -EILSEQ."); - return; - } - if (unlikely(status == -EOVERFLOW)) { - kaweth->stats.rx_errors++; - dbg("Status was -EOVERFLOW."); - } - spin_lock(&kaweth->device_lock); - if (IS_BLOCKED(kaweth->status)) { - spin_unlock(&kaweth->device_lock); - return; - } - spin_unlock(&kaweth->device_lock); - - if(status && status != -EREMOTEIO && count != 1) { - err("%s RX status: %d count: %d packet_len: %d", - net->name, - 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 */ - - skb_copy_to_linear_data(skb, kaweth->rx_buf + 2, pkt_len); - - 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_put_interface(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); - - cancel_delayed_work_sync(&kaweth->lowmem_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_put_interface(kaweth->intf); - - return 0; -} - -static u32 kaweth_get_link(struct net_device *dev) -{ - struct kaweth_device *kaweth = netdev_priv(dev); - - return kaweth->linkstate; -} - -static const struct ethtool_ops ops = { - .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; - int status = urb->status; - - if (unlikely(status != 0)) - if (status != -ENOENT) - dbg("%s: TX status %d.", kaweth->net->name, status); - - netif_wake_queue(kaweth->net); - dev_kfree_skb_irq(skb); -} - -/**************************************************************** - * kaweth_start_xmit - ****************************************************************/ -static netdev_tx_t 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_irq(&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_irq(&kaweth->device_lock); - return NETDEV_TX_OK; - } - } - - 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))) - { - dev_warn(&net->dev, "kaweth failed tx_urb %d\n", 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; - } - - spin_unlock_irq(&kaweth->device_lock); - - return NETDEV_TX_OK; -} - -/**************************************************************** - * 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 (!netdev_mc_empty(net) || (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) -{ - int result; - __u16 packet_filter_bitmap = kaweth->packet_filter_bitmap; - - kaweth->packet_filter_bitmap = 0; - if (packet_filter_bitmap == 0) - return; - - if (in_interrupt()) - return; - - 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); - - dev_warn(&net->dev, "%s: Tx timed out. Resetting.\n", 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 const struct net_device_ops kaweth_netdev_ops = { - .ndo_open = kaweth_open, - .ndo_stop = kaweth_close, - .ndo_start_xmit = kaweth_start_xmit, - .ndo_tx_timeout = kaweth_tx_timeout, - .ndo_set_rx_mode = kaweth_set_rx_mode, - .ndo_get_stats = kaweth_netdev_stats, - .ndo_change_mtu = eth_change_mtu, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -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) { - dev_info(&intf->dev, "Firmware present in device.\n"); - } else { - /* Download the firmware */ - dev_info(&intf->dev, "Downloading firmware...\n"); - kaweth->firmware_buf = (__u8 *)__get_free_page(GFP_KERNEL); - if ((result = kaweth_download_firmware(kaweth, - "kaweth/new_code.bin", - 100, - 2)) < 0) { - err("Error downloading firmware (%d)", result); - goto err_fw; - } - - if ((result = kaweth_download_firmware(kaweth, - "kaweth/new_code_fix.bin", - 100, - 3)) < 0) { - err("Error downloading firmware fix (%d)", result); - goto err_fw; - } - - if ((result = kaweth_download_firmware(kaweth, - "kaweth/trigger_code.bin", - 126, - 2)) < 0) { - err("Error downloading trigger code (%d)", result); - goto err_fw; - - } - - if ((result = kaweth_download_firmware(kaweth, - "kaweth/trigger_code_fix.bin", - 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... */ - dev_info(&intf->dev, "Firmware loaded. I'll be back...\n"); -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; - } - - dev_info(&intf->dev, "Statistics collection: %x\n", kaweth->configuration.statistics_mask); - dev_info(&intf->dev, "Multicast filter limit: %x\n", kaweth->configuration.max_multicast_filters & ((1 << 15) - 1)); - dev_info(&intf->dev, "MTU: %d\n", le16_to_cpu(kaweth->configuration.segment_size)); - dev_info(&intf->dev, "Read MAC address %pM\n", kaweth->configuration.hw_addr); - - 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_alloc_coherent( kaweth->dev, - INTBUFFERSIZE, - GFP_KERNEL, - &kaweth->intbufferhandle); - if (!kaweth->intbuffer) - goto err_tx_and_rx_and_irq; - kaweth->rx_buf = usb_alloc_coherent( 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->netdev_ops = &kaweth_netdev_ops; - netdev->watchdog_timeo = KAWETH_TX_TIMEOUT; - 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); - 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; - } - - dev_info(&intf->dev, "kaweth interface created at %s\n", - kaweth->net->name); - - dbg("Kaweth probe returning."); - - return 0; - -err_intfdata: - usb_set_intfdata(intf, NULL); - usb_free_coherent(kaweth->dev, KAWETH_BUF_SIZE, (void *)kaweth->rx_buf, kaweth->rxbufferhandle); -err_all_but_rxbuf: - usb_free_coherent(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; - - dev_info(&intf->dev, "Unregistering\n"); - - usb_set_intfdata(intf, NULL); - if (!kaweth) { - dev_warn(&intf->dev, "unregistering non-existent device\n"); - 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_free_coherent(kaweth->dev, KAWETH_BUF_SIZE, (void *)kaweth->rx_buf, kaweth->rxbufferhandle); - usb_free_coherent(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 - dev_warn(&urb->dev->dev, "usb_control/bulk_msg: timeout\n"); - 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; - } -} - -module_usb_driver(kaweth_driver); diff --git a/ANDROID_3.4.5/drivers/net/usb/lg-vl600.c b/ANDROID_3.4.5/drivers/net/usb/lg-vl600.c deleted file mode 100644 index 45a981fd..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/lg-vl600.c +++ /dev/null @@ -1,353 +0,0 @@ -/* - * Ethernet interface part of the LG VL600 LTE modem (4G dongle) - * - * Copyright (C) 2011 Intel Corporation - * Author: Andrzej Zaborowski <balrogg@gmail.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 - */ -#include <linux/etherdevice.h> -#include <linux/ethtool.h> -#include <linux/mii.h> -#include <linux/usb.h> -#include <linux/usb/cdc.h> -#include <linux/usb/usbnet.h> -#include <linux/if_ether.h> -#include <linux/if_arp.h> -#include <linux/inetdevice.h> -#include <linux/module.h> - -/* - * The device has a CDC ACM port for modem control (it claims to be - * CDC ACM anyway) and a CDC Ethernet port for actual network data. - * It will however ignore data on both ports that is not encapsulated - * in a specific way, any data returned is also encapsulated the same - * way. The headers don't seem to follow any popular standard. - * - * This driver adds and strips these headers from the ethernet frames - * sent/received from the CDC Ethernet port. The proprietary header - * replaces the standard ethernet header in a packet so only actual - * ethernet frames are allowed. The headers allow some form of - * multiplexing by using non standard values of the .h_proto field. - * Windows/Mac drivers do send a couple of such frames to the device - * during initialisation, with protocol set to 0x0906 or 0x0b06 and (what - * seems to be) a flag in the .dummy_flags. This doesn't seem necessary - * for modem operation but can possibly be used for GPS or other funcitons. - */ - -struct vl600_frame_hdr { - __le32 len; - __le32 serial; - __le32 pkt_cnt; - __le32 dummy_flags; - __le32 dummy; - __le32 magic; -} __attribute__((packed)); - -struct vl600_pkt_hdr { - __le32 dummy[2]; - __le32 len; - __be16 h_proto; -} __attribute__((packed)); - -struct vl600_state { - struct sk_buff *current_rx_buf; -}; - -static int vl600_bind(struct usbnet *dev, struct usb_interface *intf) -{ - int ret; - struct vl600_state *s = kzalloc(sizeof(struct vl600_state), GFP_KERNEL); - - if (!s) - return -ENOMEM; - - ret = usbnet_cdc_bind(dev, intf); - if (ret) { - kfree(s); - return ret; - } - - dev->driver_priv = s; - - /* ARP packets don't go through, but they're also of no use. The - * subnet has only two hosts anyway: us and the gateway / DHCP - * server (probably simulated by modem firmware or network operator) - * whose address changes everytime we connect to the intarwebz and - * who doesn't bother answering ARP requests either. So hardware - * addresses have no meaning, the destination and the source of every - * packet depend only on whether it is on the IN or OUT endpoint. */ - dev->net->flags |= IFF_NOARP; - /* IPv6 NDP relies on multicast. Enable it by default. */ - dev->net->flags |= IFF_MULTICAST; - - return ret; -} - -static void vl600_unbind(struct usbnet *dev, struct usb_interface *intf) -{ - struct vl600_state *s = dev->driver_priv; - - if (s->current_rx_buf) - dev_kfree_skb(s->current_rx_buf); - - kfree(s); - - return usbnet_cdc_unbind(dev, intf); -} - -static int vl600_rx_fixup(struct usbnet *dev, struct sk_buff *skb) -{ - struct vl600_frame_hdr *frame; - struct vl600_pkt_hdr *packet; - struct ethhdr *ethhdr; - int packet_len, count; - struct sk_buff *buf = skb; - struct sk_buff *clone; - struct vl600_state *s = dev->driver_priv; - - /* Frame lengths are generally 4B multiplies but every couple of - * hours there's an odd number of bytes sized yet correct frame, - * so don't require this. */ - - /* Allow a packet (or multiple packets batched together) to be - * split across many frames. We don't allow a new batch to - * begin in the same frame another one is ending however, and no - * leading or trailing pad bytes. */ - if (s->current_rx_buf) { - frame = (struct vl600_frame_hdr *) s->current_rx_buf->data; - if (skb->len + s->current_rx_buf->len > - le32_to_cpup(&frame->len)) { - netif_err(dev, ifup, dev->net, "Fragment too long\n"); - dev->net->stats.rx_length_errors++; - goto error; - } - - buf = s->current_rx_buf; - memcpy(skb_put(buf, skb->len), skb->data, skb->len); - } else if (skb->len < 4) { - netif_err(dev, ifup, dev->net, "Frame too short\n"); - dev->net->stats.rx_length_errors++; - goto error; - } - - frame = (struct vl600_frame_hdr *) buf->data; - /* Yes, check that frame->magic == 0x53544448 (or 0x44544d48), - * otherwise we may run out of memory w/a bad packet */ - if (ntohl(frame->magic) != 0x53544448 && - ntohl(frame->magic) != 0x44544d48) - goto error; - - if (buf->len < sizeof(*frame) || - buf->len != le32_to_cpup(&frame->len)) { - /* Save this fragment for later assembly */ - if (s->current_rx_buf) - return 0; - - s->current_rx_buf = skb_copy_expand(skb, 0, - le32_to_cpup(&frame->len), GFP_ATOMIC); - if (!s->current_rx_buf) { - netif_err(dev, ifup, dev->net, "Reserving %i bytes " - "for packet assembly failed.\n", - le32_to_cpup(&frame->len)); - dev->net->stats.rx_errors++; - } - - return 0; - } - - count = le32_to_cpup(&frame->pkt_cnt); - - skb_pull(buf, sizeof(*frame)); - - while (count--) { - if (buf->len < sizeof(*packet)) { - netif_err(dev, ifup, dev->net, "Packet too short\n"); - goto error; - } - - packet = (struct vl600_pkt_hdr *) buf->data; - packet_len = sizeof(*packet) + le32_to_cpup(&packet->len); - if (packet_len > buf->len) { - netif_err(dev, ifup, dev->net, - "Bad packet length stored in header\n"); - goto error; - } - - /* Packet header is same size as the ethernet header - * (sizeof(*packet) == sizeof(*ethhdr)), additionally - * the h_proto field is in the same place so we just leave it - * alone and fill in the remaining fields. - */ - ethhdr = (struct ethhdr *) skb->data; - if (be16_to_cpup(ðhdr->h_proto) == ETH_P_ARP && - buf->len > 0x26) { - /* Copy the addresses from packet contents */ - memcpy(ethhdr->h_source, - &buf->data[sizeof(*ethhdr) + 0x8], - ETH_ALEN); - memcpy(ethhdr->h_dest, - &buf->data[sizeof(*ethhdr) + 0x12], - ETH_ALEN); - } else { - memset(ethhdr->h_source, 0, ETH_ALEN); - memcpy(ethhdr->h_dest, dev->net->dev_addr, ETH_ALEN); - - /* Inbound IPv6 packets have an IPv4 ethertype (0x800) - * for some reason. Peek at the L3 header to check - * for IPv6 packets, and set the ethertype to IPv6 - * (0x86dd) so Linux can understand it. - */ - if ((buf->data[sizeof(*ethhdr)] & 0xf0) == 0x60) - ethhdr->h_proto = __constant_htons(ETH_P_IPV6); - } - - if (count) { - /* Not the last packet in this batch */ - clone = skb_clone(buf, GFP_ATOMIC); - if (!clone) - goto error; - - skb_trim(clone, packet_len); - usbnet_skb_return(dev, clone); - - skb_pull(buf, (packet_len + 3) & ~3); - } else { - skb_trim(buf, packet_len); - - if (s->current_rx_buf) { - usbnet_skb_return(dev, buf); - s->current_rx_buf = NULL; - return 0; - } - - return 1; - } - } - -error: - if (s->current_rx_buf) { - dev_kfree_skb_any(s->current_rx_buf); - s->current_rx_buf = NULL; - } - dev->net->stats.rx_errors++; - return 0; -} - -static struct sk_buff *vl600_tx_fixup(struct usbnet *dev, - struct sk_buff *skb, gfp_t flags) -{ - struct sk_buff *ret; - struct vl600_frame_hdr *frame; - struct vl600_pkt_hdr *packet; - static uint32_t serial = 1; - int orig_len = skb->len - sizeof(struct ethhdr); - int full_len = (skb->len + sizeof(struct vl600_frame_hdr) + 3) & ~3; - - frame = (struct vl600_frame_hdr *) skb->data; - if (skb->len > sizeof(*frame) && skb->len == le32_to_cpup(&frame->len)) - return skb; /* Already encapsulated? */ - - if (skb->len < sizeof(struct ethhdr)) - /* Drop, device can only deal with ethernet packets */ - return NULL; - - if (!skb_cloned(skb)) { - int headroom = skb_headroom(skb); - int tailroom = skb_tailroom(skb); - - if (tailroom >= full_len - skb->len - sizeof(*frame) && - headroom >= sizeof(*frame)) - /* There's enough head and tail room */ - goto encapsulate; - - if (headroom + tailroom + skb->len >= full_len) { - /* There's enough total room, just readjust */ - skb->data = memmove(skb->head + sizeof(*frame), - skb->data, skb->len); - skb_set_tail_pointer(skb, skb->len); - goto encapsulate; - } - } - - /* Alloc a new skb with the required size */ - ret = skb_copy_expand(skb, sizeof(struct vl600_frame_hdr), full_len - - skb->len - sizeof(struct vl600_frame_hdr), flags); - dev_kfree_skb_any(skb); - if (!ret) - return ret; - skb = ret; - -encapsulate: - /* Packet header is same size as ethernet packet header - * (sizeof(*packet) == sizeof(struct ethhdr)), additionally the - * h_proto field is in the same place so we just leave it alone and - * overwrite the remaining fields. - */ - packet = (struct vl600_pkt_hdr *) skb->data; - /* The VL600 wants IPv6 packets to have an IPv4 ethertype - * Since this modem only supports IPv4 and IPv6, just set all - * frames to 0x0800 (ETH_P_IP) - */ - packet->h_proto = htons(ETH_P_IP); - memset(&packet->dummy, 0, sizeof(packet->dummy)); - packet->len = cpu_to_le32(orig_len); - - frame = (struct vl600_frame_hdr *) skb_push(skb, sizeof(*frame)); - memset(frame, 0, sizeof(*frame)); - frame->len = cpu_to_le32(full_len); - frame->serial = cpu_to_le32(serial++); - frame->pkt_cnt = cpu_to_le32(1); - - if (skb->len < full_len) /* Pad */ - skb_put(skb, full_len - skb->len); - - return skb; -} - -static const struct driver_info vl600_info = { - .description = "LG VL600 modem", - .flags = FLAG_RX_ASSEMBLE | FLAG_WWAN, - .bind = vl600_bind, - .unbind = vl600_unbind, - .status = usbnet_cdc_status, - .rx_fixup = vl600_rx_fixup, - .tx_fixup = vl600_tx_fixup, -}; - -static const struct usb_device_id products[] = { - { - USB_DEVICE_AND_INTERFACE_INFO(0x1004, 0x61aa, USB_CLASS_COMM, - USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), - .driver_info = (unsigned long) &vl600_info, - }, - {}, /* End */ -}; -MODULE_DEVICE_TABLE(usb, products); - -static struct usb_driver lg_vl600_driver = { - .name = "lg-vl600", - .id_table = products, - .probe = usbnet_probe, - .disconnect = usbnet_disconnect, - .suspend = usbnet_suspend, - .resume = usbnet_resume, -}; - -module_usb_driver(lg_vl600_driver); - -MODULE_AUTHOR("Anrzej Zaborowski"); -MODULE_DESCRIPTION("LG-VL600 modem's ethernet link"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/net/usb/mcs7830.c b/ANDROID_3.4.5/drivers/net/usb/mcs7830.c deleted file mode 100644 index c434b6ba..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/mcs7830.c +++ /dev/null @@ -1,698 +0,0 @@ -/* - * MOSCHIP MCS7830 based (7730/7830/7832) USB 2.0 Ethernet Devices - * - * based on usbnet.c, asix.c and the vendor provided mcs7830 driver - * - * Copyright (C) 2010 Andreas Mohr <andi@lisas.de> - * 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. - * - * Definitions gathered from MOSCHIP, Data Sheet_7830DA.pdf (thanks!). - * - * 2010-12-19: add 7832 USB PID ("functionality same as MCS7830"), - * per active notification by manufacturer - * - * TODO: - * - support HIF_REG_CONFIG_SLEEPMODE/HIF_REG_CONFIG_TXENABLE (via autopm?) - * - implement ethtool_ops get_pauseparam/set_pauseparam - * via HIF_REG_PAUSE_THRESHOLD (>= revision C only!) - * - implement get_eeprom/[set_eeprom] - * - switch PHY on/off on ifup/ifdown (perhaps in usbnet.c, via MII) - * - mcs7830_get_regs() handling is weird: for rev 2 we return 32 regs, - * can access only ~ 24, remaining user buffer is uninitialized garbage - * - anything else? - * - * - * 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/slab.h> -#include <linux/usb.h> -#include <linux/usb/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 MCS7832_PRODUCT_ID 0x7832 -#define MCS7830_PRODUCT_ID 0x7830 -#define MCS7730_PRODUCT_ID 0x7730 - -#define SITECOM_VENDOR_ID 0x0DF6 -#define LN_030_PRODUCT_ID 0x0021 - -#define MCS7830_MII_ADVERTISE (ADVERTISE_PAUSE_CAP | ADVERTISE_100FULL | \ - ADVERTISE_100HALF | ADVERTISE_10FULL | \ - ADVERTISE_10HALF | ADVERTISE_CSMA) - -/* HIF_REG_XX corresponding 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, - /* hmm, spec sez: "R/W", "Except bit 3" (likely TXENABLE). */ - 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_PROMISCUOUS = 0x01, - HIF_REG_ETHERNET_ADDR = 0x0f, - HIF_REG_FRAME_DROP_COUNTER = 0x15, /* 0..ff; reset: 0 */ - HIF_REG_PAUSE_THRESHOLD = 0x16, - HIF_REG_PAUSE_THRESHOLD_DEFAULT = 0, -}; - -/* Trailing status byte in Ethernet Rx frame */ -enum { - MCS7830_RX_SHORT_FRAME = 0x01, /* < 64 bytes */ - MCS7830_RX_LENGTH_ERROR = 0x02, /* framelen != Ethernet length field */ - MCS7830_RX_ALIGNMENT_ERROR = 0x04, /* non-even number of nibbles */ - MCS7830_RX_CRC_ERROR = 0x08, - MCS7830_RX_LARGE_FRAME = 0x10, /* > 1518 bytes */ - MCS7830_RX_FRAME_CORRECT = 0x20, /* frame is correct */ - /* [7:6] reserved */ -}; - -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; - void *buffer; - - buffer = kmalloc(size, GFP_NOIO); - if (buffer == NULL) - return -ENOMEM; - - ret = usb_control_msg(xdev, usb_rcvctrlpipe(xdev, 0), MCS7830_RD_BREQ, - MCS7830_RD_BMREQ, 0x0000, index, buffer, - size, MCS7830_CTRL_TIMEOUT); - memcpy(data, buffer, size); - kfree(buffer); - - return ret; -} - -static int mcs7830_set_reg(struct usbnet *dev, u16 index, u16 size, const void *data) -{ - struct usb_device *xdev = dev->udev; - int ret; - void *buffer; - - buffer = kmemdup(data, size, GFP_NOIO); - if (buffer == NULL) - return -ENOMEM; - - ret = usb_control_msg(xdev, usb_sndctrlpipe(xdev, 0), MCS7830_WR_BREQ, - MCS7830_WR_BMREQ, 0x0000, index, buffer, - size, MCS7830_CTRL_TIMEOUT); - kfree(buffer); - return ret; -} - -static void mcs7830_async_cmd_callback(struct urb *urb) -{ - struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; - int status = urb->status; - - if (status < 0) - printk(KERN_DEBUG "%s() failed with %d\n", - __func__, 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!\n"); - return; - } - - req = kmalloc(sizeof *req, GFP_ATOMIC); - if (!req) { - dev_err(&dev->udev->dev, - "Failed to allocate memory for control request\n"); - 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\n", ret); - goto out; - } - return; -out: - kfree(req); - usb_free_urb(urb); -} - -static int mcs7830_hif_get_mac_address(struct usbnet *dev, unsigned char *addr) -{ - int ret = mcs7830_get_reg(dev, HIF_REG_ETHERNET_ADDR, ETH_ALEN, addr); - if (ret < 0) - return ret; - return 0; -} - -static int mcs7830_hif_set_mac_address(struct usbnet *dev, unsigned char *addr) -{ - int ret = mcs7830_set_reg(dev, HIF_REG_ETHERNET_ADDR, ETH_ALEN, addr); - - if (ret < 0) - return ret; - return 0; -} - -static int mcs7830_set_mac_address(struct net_device *netdev, void *p) -{ - int ret; - struct usbnet *dev = netdev_priv(netdev); - struct sockaddr *addr = p; - - if (netif_running(netdev)) - return -EBUSY; - - if (!is_valid_ether_addr(addr->sa_data)) - return -EADDRNOTAVAIL; - - ret = mcs7830_hif_set_mac_address(dev, addr->sa_data); - - if (ret < 0) - return ret; - - /* it worked --> adopt it on netdev side */ - memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); - - 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; -} - - -/* - * 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_FRAME_DROP_COUNTER, 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_mdio_read(struct net_device *netdev, int phy_id, - int location) -{ - struct usbnet *dev = netdev_priv(netdev); - 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(netdev); - 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); -} - -static inline struct mcs7830_data *mcs7830_get_data(struct usbnet *dev) -{ - return (struct mcs7830_data *)&dev->data; -} - -static void mcs7830_hif_update_multicast_hash(struct usbnet *dev) -{ - struct mcs7830_data *data = mcs7830_get_data(dev); - mcs7830_set_reg_async(dev, HIF_REG_MULTICAST_HASH, - sizeof data->multi_filter, - data->multi_filter); -} - -static void mcs7830_hif_update_config(struct usbnet *dev) -{ - /* implementation specific to data->config - (argument needs to be heap-based anyway - USB DMA!) */ - struct mcs7830_data *data = mcs7830_get_data(dev); - mcs7830_set_reg_async(dev, HIF_REG_CONFIG, 1, &data->config); -} - -static void mcs7830_data_set_multicast(struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - struct mcs7830_data *data = mcs7830_get_data(dev); - - memset(data->multi_filter, 0, sizeof data->multi_filter); - - 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_PROMISCUOUS; - } else if (net->flags & IFF_ALLMULTI || - netdev_mc_count(net) > MCS7830_MAX_MCAST) { - data->config |= HIF_REG_CONFIG_ALLMULTICAST; - } else if (netdev_mc_empty(net)) { - /* 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 netdev_hw_addr *ha; - u32 crc_bits; - - /* Build the multicast hash filter. */ - netdev_for_each_mc_addr(ha, net) { - crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; - data->multi_filter[crc_bits >> 3] |= 1 << (crc_bits & 7); - } - } -} - -static int mcs7830_apply_base_config(struct usbnet *dev) -{ - int ret; - - /* re-configure known MAC (suspend case etc.) */ - ret = mcs7830_hif_set_mac_address(dev, dev->net->dev_addr); - if (ret) { - dev_info(&dev->udev->dev, "Cannot set 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_hif_update_multicast_hash(dev); - mcs7830_hif_update_config(dev); - - mcs7830_rev_C_fixup(dev); - ret = 0; -out: - return ret; -} - -/* credits go to asix_set_multicast */ -static void mcs7830_set_multicast(struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - - mcs7830_data_set_multicast(net); - - mcs7830_hif_update_multicast_hash(dev); - mcs7830_hif_update_config(dev); -} - -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 const 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 const struct net_device_ops mcs7830_netdev_ops = { - .ndo_open = usbnet_open, - .ndo_stop = usbnet_stop, - .ndo_start_xmit = usbnet_start_xmit, - .ndo_tx_timeout = usbnet_tx_timeout, - .ndo_change_mtu = usbnet_change_mtu, - .ndo_validate_addr = eth_validate_addr, - .ndo_do_ioctl = mcs7830_ioctl, - .ndo_set_rx_mode = mcs7830_set_multicast, - .ndo_set_mac_address = mcs7830_set_mac_address, -}; - -static int mcs7830_bind(struct usbnet *dev, struct usb_interface *udev) -{ - struct net_device *net = dev->net; - int ret; - int retry; - - /* Initial startup: Gather MAC address setting from EEPROM */ - ret = -EINVAL; - for (retry = 0; retry < 5 && ret; retry++) - ret = mcs7830_hif_get_mac_address(dev, net->dev_addr); - if (ret) { - dev_warn(&dev->udev->dev, "Cannot read MAC address\n"); - goto out; - } - - mcs7830_data_set_multicast(net); - - ret = mcs7830_apply_base_config(dev); - if (ret) - goto out; - - net->ethtool_ops = &mcs7830_ethtool_ops; - net->netdev_ops = &mcs7830_netdev_ops; - - /* 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 byte 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 != MCS7830_RX_FRAME_CORRECT) { - dev_dbg(&dev->udev->dev, "rx fixup status %x\n", status); - - /* hmm, perhaps usbnet.c already sees a globally visible - frame error and increments rx_errors on its own already? */ - dev->net->stats.rx_errors++; - - if (status & (MCS7830_RX_SHORT_FRAME - |MCS7830_RX_LENGTH_ERROR - |MCS7830_RX_LARGE_FRAME)) - dev->net->stats.rx_length_errors++; - if (status & MCS7830_RX_ALIGNMENT_ERROR) - dev->net->stats.rx_frame_errors++; - if (status & MCS7830_RX_CRC_ERROR) - dev->net->stats.rx_crc_errors++; - } - - return skb->len > 0; -} - -static const struct driver_info moschip_info = { - .description = "MOSCHIP 7830/7832/7730 usb-NET adapter", - .bind = mcs7830_bind, - .rx_fixup = mcs7830_rx_fixup, - .flags = FLAG_ETHER, - .in = 1, - .out = 2, -}; - -static const struct driver_info sitecom_info = { - .description = "Sitecom LN-30 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, MCS7832_PRODUCT_ID), - .driver_info = (unsigned long) &moschip_info, - }, - { - USB_DEVICE(MCS7830_VENDOR_ID, MCS7830_PRODUCT_ID), - .driver_info = (unsigned long) &moschip_info, - }, - { - USB_DEVICE(MCS7830_VENDOR_ID, MCS7730_PRODUCT_ID), - .driver_info = (unsigned long) &moschip_info, - }, - { - USB_DEVICE(SITECOM_VENDOR_ID, LN_030_PRODUCT_ID), - .driver_info = (unsigned long) &sitecom_info, - }, - {}, -}; -MODULE_DEVICE_TABLE(usb, products); - -static int mcs7830_reset_resume (struct usb_interface *intf) -{ - /* YES, this function is successful enough that ethtool -d - does show same output pre-/post-suspend */ - - struct usbnet *dev = usb_get_intfdata(intf); - - mcs7830_apply_base_config(dev); - - usbnet_resume(intf); - - return 0; -} - -static struct usb_driver mcs7830_driver = { - .name = driver_name, - .id_table = products, - .probe = usbnet_probe, - .disconnect = usbnet_disconnect, - .suspend = usbnet_suspend, - .resume = usbnet_resume, - .reset_resume = mcs7830_reset_resume, -}; - -module_usb_driver(mcs7830_driver); - -MODULE_DESCRIPTION("USB to network adapter MCS7830)"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/net/usb/net1080.c b/ANDROID_3.4.5/drivers/net/usb/net1080.c deleted file mode 100644 index 83f965cb..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/net1080.c +++ /dev/null @@ -1,596 +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 <linux/usb/usbnet.h> -#include <linux/slab.h> - -#include <asm/unaligned.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; -} __packed; - -#define PAD_BYTE ((unsigned char)0xAC) - -struct nc_trailer { - __le16 packet_id; -} __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) -{ - netif_dbg(dev, link, dev->net, - "net1080 %s-%s usbctl 0x%x:%s%s%s%s%s; this%s%s; other%s%s; r/o 0x%x\n", - 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_THIS) ? " FLUSH" : "", - (usbctl & USBCTL_DISCONN_THIS) ? " DIS" : "", - - (usbctl & USBCTL_FLUSH_OTHER) ? " FLUSH" : "", - (usbctl & USBCTL_DISCONN_OTHER) ? " 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) -{ - netif_dbg(dev, link, dev->net, - "net1080 %s-%s status 0x%x: this (%c) PKT=%d%s%s%s; other PKT=%d%s%s%s; unspec 0x%x\n", - 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) -{ - netif_dbg(dev, link, dev->net, "net1080 %s-%s ttl 0x%x this = %d, other = %d\n", - 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); - - netif_info(dev, link, dev->net, "port %c, peer %sconnected\n", - (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; - } - - netif_dbg(dev, rx_err, dev->net, - "flush net1080; too many framing errors\n"); - 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->net->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->net->stats.rx_frame_errors++; - dbg("packet too big, %d", packet_len); - nc_ensure_sync(dev); - return 0; - } else if (hdr_len < MIN_HEADER) { - dev->net->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->net->stats.rx_frame_errors++; - dbg("bad pad"); - return 0; - } - skb_trim(skb, skb->len - 1); - } - if (skb->len != packet_len) { - dev->net->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->net->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 - netdev_dbg(dev->net, "frame <rx h %d p %d id %d\n", 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 - netdev_dbg(dev->net, "frame >tx h %d p %d id %d\n", - 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_POINTTOPOINT | 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, -}; - -module_usb_driver(net1080_driver); - -MODULE_AUTHOR("David Brownell"); -MODULE_DESCRIPTION("NetChip 1080 based USB Host-to-Host Links"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/net/usb/pegasus.c b/ANDROID_3.4.5/drivers/net/usb/pegasus.c deleted file mode 100644 index 75239309..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/pegasus.c +++ /dev/null @@ -1,1539 +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 bool loopback; -static bool mii_mode; -static char *devid; - -static struct usb_eth_dev usb_dev_id[] = { -#define PEGASUS_DEV(pn, vid, pid, flags) \ - {.name = pn, .vendor = vid, .device = pid, .private = flags}, -#define PEGASUS_DEV_CLASS(pn, vid, pid, dclass, flags) \ - PEGASUS_DEV(pn, vid, pid, flags) -#include "pegasus.h" -#undef PEGASUS_DEV -#undef PEGASUS_DEV_CLASS - {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}, -/* - * The Belkin F8T012xx1 bluetooth adaptor has the same vendor and product - * IDs as the Belkin F5D5050, so we need to teach the pegasus driver to - * ignore adaptors belonging to the "Wireless" class 0xE0. For this one - * case anyway, seeing as the pegasus is for "Wired" adaptors. - */ -#define PEGASUS_DEV_CLASS(pn, vid, pid, dclass, flags) \ - {.match_flags = (USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_DEV_CLASS), \ - .idVendor = vid, .idProduct = pid, .bDeviceClass = dclass}, -#include "pegasus.h" -#undef PEGASUS_DEV -#undef PEGASUS_DEV_CLASS - {}, - {} -}; - -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 const struct net_device_ops pegasus_netdev_ops; - -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; - int status = urb->status; - - if (!pegasus) - return; - - switch (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 (net_ratelimit()) - netif_dbg(pegasus, drv, pegasus->net, - "%s, status %d\n", __func__, status); - break; - } - 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) { - netif_warn(pegasus, drv, pegasus->net, - "out of memory in %s\n", __func__); - 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_le16(indx); - pegasus->dr.wLength = cpu_to_le16(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 (net_ratelimit()) - netif_err(pegasus, drv, pegasus->net, - "%s, status %d\n", __func__, 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 = kmemdup(data, size, GFP_KERNEL); - if (!buffer) { - netif_warn(pegasus, drv, pegasus->net, - "out of memory in %s\n", __func__); - 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_WRITE; - pegasus->dr.bRequest = PEGASUS_REQ_SET_REGS; - pegasus->dr.wValue = cpu_to_le16(0); - pegasus->dr.wIndex = cpu_to_le16(indx); - pegasus->dr.wLength = cpu_to_le16(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); - netif_err(pegasus, drv, pegasus->net, - "%s, status %d\n", __func__, 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 = kmemdup(&data, 1, GFP_KERNEL); - if (!tmp) { - netif_warn(pegasus, drv, pegasus->net, - "out of memory in %s\n", __func__); - 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_WRITE; - pegasus->dr.bRequest = PEGASUS_REQ_SET_REG; - pegasus->dr.wValue = cpu_to_le16(data); - pegasus->dr.wIndex = cpu_to_le16(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 (net_ratelimit()) - netif_err(pegasus, drv, pegasus->net, - "%s, status %d\n", __func__, 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 = cpu_to_le16(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); - netif_err(pegasus, drv, pegasus->net, - "%s, status %d\n", __func__, 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) - goto fail; - - ret = get_registers(pegasus, PhyData, 2, ®di); - *regd = le16_to_cpu(regdi); - return ret; - -fail: - netif_warn(pegasus, drv, pegasus->net, "%s failed\n", __func__); - - return ret; -} - -static int mdio_read(struct net_device *dev, int phy_id, int loc) -{ - pegasus_t *pegasus = 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) - goto fail; - - return ret; - -fail: - netif_warn(pegasus, drv, pegasus->net, "%s failed\n", __func__); - return -ETIMEDOUT; -} - -static void mdio_write(struct net_device *dev, int phy_id, int loc, int val) -{ - pegasus_t *pegasus = 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) - goto fail; - - ret = get_registers(pegasus, EpromData, 2, &retdatai); - *retdata = le16_to_cpu(retdatai); - return ret; - -fail: - netif_warn(pegasus, drv, pegasus->net, "%s failed\n", __func__); - 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; - __le16 le_data = cpu_to_le16(data); - - set_registers(pegasus, EpromOffset, 4, d); - enable_eprom_write(pegasus); - set_register(pegasus, EpromOffset, index); - set_registers(pegasus, EpromData, 2, &le_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) - goto fail; - - return ret; - -fail: - netif_warn(pegasus, drv, pegasus->net, "%s failed\n", __func__); - 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_le16(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) - 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 ? 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; - int status = urb->status; - u8 *buf = urb->transfer_buffer; - __u16 pkt_len; - - if (!pegasus) - return; - - net = pegasus->net; - if (!netif_device_present(net) || !netif_running(net)) - return; - - switch (status) { - case 0: - break; - case -ETIME: - netif_dbg(pegasus, rx_err, net, "reset MAC\n"); - pegasus->flags &= ~PEGASUS_RX_BUSY; - break; - case -EPIPE: /* stall, or disconnect from TT */ - /* FIXME schedule work to clear the halt */ - netif_warn(pegasus, rx_err, net, "no rx stall recovery\n"); - return; - case -ENOENT: - case -ECONNRESET: - case -ESHUTDOWN: - netif_dbg(pegasus, ifdown, net, "rx unlink, %d\n", status); - return; - default: - netif_dbg(pegasus, rx_err, net, "RX status %d\n", status); - goto goon; - } - - if (!count || count < 4) - goto goon; - - rx_status = buf[count - 2]; - if (rx_status & 0x1e) { - netif_dbg(pegasus, rx_err, net, - "RX packet error %x\n", 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) { - netif_warn(pegasus, rx_err, pegasus->net, "low on memory\n"); - 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; - int status = urb->status; - - if (!pegasus) - return; - - net = pegasus->net; - - if (!netif_device_present(net) || !netif_running(net)) - return; - - switch (status) { - case -EPIPE: - /* FIXME schedule_work() to clear the tx halt */ - netif_stop_queue(net); - netif_warn(pegasus, tx_err, net, "no tx stall recovery\n"); - return; - case -ENOENT: - case -ECONNRESET: - case -ESHUTDOWN: - netif_dbg(pegasus, ifdown, net, "tx unlink, %d\n", status); - return; - default: - netif_info(pegasus, tx_err, net, "TX status %d\n", status); - /* FALL THROUGH */ - case 0: - break; - } - - net->trans_start = jiffies; /* prevent tx timeout */ - netif_wake_queue(net); -} - -static void intr_callback(struct urb *urb) -{ - pegasus_t *pegasus = urb->context; - struct net_device *net; - int res, status = urb->status; - - if (!pegasus) - return; - net = pegasus->net; - - switch (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 - */ - netif_dbg(pegasus, timer, net, "intr status %d\n", 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]; - } - - res = usb_submit_urb(urb, GFP_ATOMIC); - if (res == -ENODEV) - netif_device_detach(pegasus->net); - if (res) - netif_err(pegasus, timer, net, - "can't resubmit interrupt urb, %d\n", res); -} - -static void pegasus_tx_timeout(struct net_device *net) -{ - pegasus_t *pegasus = netdev_priv(net); - netif_warn(pegasus, timer, net, "tx timeout\n"); - usb_unlink_urb(pegasus->tx_urb); - pegasus->stats.tx_errors++; -} - -static netdev_tx_t 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))) { - netif_warn(pegasus, tx_err, net, "fail tx, %d\n", res); - switch (res) { - case -EPIPE: /* stall, or disconnect from TT */ - /* cleanup should already have been scheduled */ - break; - case -ENODEV: /* disconnect() upcoming */ - case -EPERM: - 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; - } - dev_kfree_skb(skb); - - return NETDEV_TX_OK; -} - -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) -{ - __le16 tmp = cpu_to_le16(0); - - set_registers(pegasus, EthCtrl0, sizeof(tmp), &tmp); -} - -static inline void get_interrupt_interval(pegasus_t *pegasus) -{ - u16 data; - u8 interval; - - read_eprom_word(pegasus, 4, &data); - interval = data >> 8; - if (pegasus->usb->speed != USB_SPEED_HIGH) { - if (interval < 0x80) { - netif_info(pegasus, timer, pegasus->net, - "intr interval changed from %ums to %ums\n", - interval, 0x80); - interval = 0x80; - data = (data & 0x00FF) | ((u16)interval << 8); -#ifdef PEGASUS_WRITE_EEPROM - write_eprom_word(pegasus, 4, data); -#endif - } - } - pegasus->intr_interval = interval; -} - -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); - netif_dbg(pegasus, ifup, net, "failed rx_urb, %d\n", 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); - netif_dbg(pegasus, ifup, net, "failed intr_urb, %d\n", res); - usb_kill_urb(pegasus->rx_urb); - goto exit; - } - if ((res = enable_net_traffic(net, pegasus->usb))) { - netif_dbg(pegasus, ifup, net, - "can't enable_net_traffic() - %d\n", 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); - netif_dbg(pegasus, ifup, net, "open\n"); - 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; - - 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 const 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; - netif_info(pegasus, link, net, "Promiscuous mode enabled\n"); - } else if (!netdev_mc_empty(net) || (net->flags & IFF_ALLMULTI)) { - pegasus->eth_regs[EthCtrl0] |= RX_MULTICAST; - pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS; - netif_dbg(pegasus, link, net, "set allmulti\n"); - } else { - pegasus->eth_regs[EthCtrl0] &= ~RX_MULTICAST; - pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS; - } - - pegasus->ctrl_urb->status = 0; - - 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 int pegasus_count; -static struct workqueue_struct *pegasus_workqueue; -#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_blacklisted(struct usb_device *udev) -{ - struct usb_device_descriptor *udd = &udev->descriptor; - - /* Special quirk to keep the driver from handling the Belkin Bluetooth - * dongle which happens to have the same ID. - */ - if ((udd->idVendor == cpu_to_le16(VENDOR_BELKIN)) && - (udd->idProduct == cpu_to_le16(0x0121)) && - (udd->bDeviceClass == USB_CLASS_WIRELESS_CONTROLLER) && - (udd->bDeviceProtocol == 1)) - return 1; - - return 0; -} - -/* we rely on probe() and remove() being serialized so we - * don't need extra locking on pegasus_count. - */ -static void pegasus_dec_workqueue(void) -{ - pegasus_count--; - if (pegasus_count == 0) { - destroy_workqueue(pegasus_workqueue); - pegasus_workqueue = NULL; - } -} - -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; - - if (pegasus_blacklisted(dev)) - return -ENODEV; - - if (pegasus_count == 0) { - pegasus_workqueue = create_singlethread_workqueue("pegasus"); - if (!pegasus_workqueue) - return -ENOMEM; - } - pegasus_count++; - - usb_get_dev(dev); - - net = alloc_etherdev(sizeof(struct pegasus)); - if (!net) - goto out; - - pegasus = netdev_priv(net); - 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; - - - net->watchdog_timeo = PEGASUS_TX_TIMEOUT; - net->netdev_ops = &pegasus_netdev_ops; - 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, %pM\n", - net->name, - usb_dev_id[dev_index].name, - net->dev_addr); - 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); - pegasus_dec_workqueue(); - 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); - pegasus_dec_workqueue(); -} - -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 const struct net_device_ops pegasus_netdev_ops = { - .ndo_open = pegasus_open, - .ndo_stop = pegasus_close, - .ndo_do_ioctl = pegasus_ioctl, - .ndo_start_xmit = pegasus_start_xmit, - .ndo_set_rx_mode = pegasus_set_multicast, - .ndo_get_stats = pegasus_netdev_stats, - .ndo_tx_timeout = pegasus_tx_timeout, - .ndo_change_mtu = eth_change_mtu, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -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 __init 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); - return usb_register(&pegasus_driver); -} - -static void __exit pegasus_exit(void) -{ - usb_deregister(&pegasus_driver); -} - -module_init(pegasus_init); -module_exit(pegasus_exit); diff --git a/ANDROID_3.4.5/drivers/net/usb/pegasus.h b/ANDROID_3.4.5/drivers/net/usb/pegasus.h deleted file mode 100644 index 65b78b35..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/pegasus.h +++ /dev/null @@ -1,315 +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) -/* - * Distinguish between this Belkin adaptor and the Belkin bluetooth adaptors - * with the same product IDs by checking the device class too. - */ -PEGASUS_DEV_CLASS("Belkin F5D5050 USB Ethernet", VENDOR_BELKIN, 0x0121, 0x00, - DEFAULT_GPIO_RESET | PEGASUS_II) -PEGASUS_DEV("Belkin F5U122 10/100 USB Ethernet", VENDOR_BELKIN, 0x0122, - 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("IO DATA USB ETX-US2", VENDOR_IODATA, 0x093a, - 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/ANDROID_3.4.5/drivers/net/usb/plusb.c b/ANDROID_3.4.5/drivers/net/usb/plusb.c deleted file mode 100644 index b2b035e2..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/plusb.c +++ /dev/null @@ -1,161 +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 <linux/usb/usbnet.h> - - -/* - * Prolific PL-2301/PL-2302 driver ... http://www.prolific.com.tw/ - * - * 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. - * - * NOTE: pl2501 has several modes, including pl2301 and pl2302 - * compatibility. Some docs suggest the difference between 2301 - * and 2302 is only to make MS-Windows use a different driver... - * - * pl25a1 glue based on patch from Tony Gibbs. Prolific "docs" on - * this chip are as usual incomplete about what control messages - * are supported. - */ - -/* - * 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) -{ - int status; - - /* some units seem to need this reset, others reject it utterly. - * FIXME be more like "naplink" or windows drivers. - */ - status = pl_set_QuickLink_features(dev, - PL_S_EN|PL_RESET_OUT|PL_RESET_IN|PL_PEER_E); - if (status != 0 && netif_msg_probe(dev)) - netif_dbg(dev, link, dev->net, "pl_reset --> %d\n", status); - return 0; -} - -static const struct driver_info prolific_info = { - .description = "Prolific PL-2301/PL-2302/PL-25A1", - .flags = FLAG_POINTTOPOINT | 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 [] = { - -/* full speed cables */ -{ - USB_DEVICE(0x067b, 0x0000), // PL-2301 - .driver_info = (unsigned long) &prolific_info, -}, { - USB_DEVICE(0x067b, 0x0001), // PL-2302 - .driver_info = (unsigned long) &prolific_info, -}, - -/* high speed cables */ -{ - USB_DEVICE(0x067b, 0x25a1), /* PL-25A1, no eeprom */ - .driver_info = (unsigned long) &prolific_info, -}, { - USB_DEVICE(0x050d, 0x258a), /* Belkin F5U258/F5U279 (PL-25A1) */ - .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, -}; - -module_usb_driver(plusb_driver); - -MODULE_AUTHOR("David Brownell"); -MODULE_DESCRIPTION("Prolific PL-2301/2302/25A1 USB Host to Host Link Driver"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/net/usb/qmi_wwan.c b/ANDROID_3.4.5/drivers/net/usb/qmi_wwan.c deleted file mode 100644 index c2ae4266..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/qmi_wwan.c +++ /dev/null @@ -1,563 +0,0 @@ -/* - * Copyright (c) 2012 Bjørn Mork <bjorn@mork.no> - * - * 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/module.h> -#include <linux/netdevice.h> -#include <linux/ethtool.h> -#include <linux/mii.h> -#include <linux/usb.h> -#include <linux/usb/cdc.h> -#include <linux/usb/usbnet.h> -#include <linux/usb/cdc-wdm.h> - -/* The name of the CDC Device Management driver */ -#define DM_DRIVER "cdc_wdm" - -/* - * This driver supports wwan (3G/LTE/?) devices using a vendor - * specific management protocol called Qualcomm MSM Interface (QMI) - - * in addition to the more common AT commands over serial interface - * management - * - * QMI is wrapped in CDC, using CDC encapsulated commands on the - * control ("master") interface of a two-interface CDC Union - * resembling standard CDC ECM. The devices do not use the control - * interface for any other CDC messages. Most likely because the - * management protocol is used in place of the standard CDC - * notifications NOTIFY_NETWORK_CONNECTION and NOTIFY_SPEED_CHANGE - * - * Handling a protocol like QMI is out of the scope for any driver. - * It can be exported as a character device using the cdc-wdm driver, - * which will enable userspace applications ("modem managers") to - * handle it. This may be required to use the network interface - * provided by the driver. - * - * These devices may alternatively/additionally be configured using AT - * commands on any of the serial interfaces driven by the option driver - * - * This driver binds only to the data ("slave") interface to enable - * the cdc-wdm driver to bind to the control interface. It still - * parses the CDC functional descriptors on the control interface to - * a) verify that this is indeed a handled interface (CDC Union - * header lists it as slave) - * b) get MAC address and other ethernet config from the CDC Ethernet - * header - * c) enable user bind requests against the control interface, which - * is the common way to bind to CDC Ethernet Control Model type - * interfaces - * d) provide a hint to the user about which interface is the - * corresponding management interface - */ - -static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf) -{ - int status = -1; - struct usb_interface *control = NULL; - u8 *buf = intf->cur_altsetting->extra; - int len = intf->cur_altsetting->extralen; - struct usb_interface_descriptor *desc = &intf->cur_altsetting->desc; - struct usb_cdc_union_desc *cdc_union = NULL; - struct usb_cdc_ether_desc *cdc_ether = NULL; - u32 required = 1 << USB_CDC_HEADER_TYPE | 1 << USB_CDC_UNION_TYPE; - u32 found = 0; - atomic_t *pmcount = (void *)&dev->data[1]; - - atomic_set(pmcount, 0); - - /* - * assume a data interface has no additional descriptors and - * that the control and data interface are numbered - * consecutively - this holds for the Huawei device at least - */ - if (len == 0 && desc->bInterfaceNumber > 0) { - control = usb_ifnum_to_if(dev->udev, desc->bInterfaceNumber - 1); - if (!control) - goto err; - - buf = control->cur_altsetting->extra; - len = control->cur_altsetting->extralen; - dev_dbg(&intf->dev, "guessing \"control\" => %s, \"data\" => this\n", - dev_name(&control->dev)); - } - - while (len > 3) { - struct usb_descriptor_header *h = (void *)buf; - - /* ignore any misplaced descriptors */ - if (h->bDescriptorType != USB_DT_CS_INTERFACE) - goto next_desc; - - /* buf[2] is CDC descriptor subtype */ - switch (buf[2]) { - case USB_CDC_HEADER_TYPE: - if (found & 1 << USB_CDC_HEADER_TYPE) { - dev_dbg(&intf->dev, "extra CDC header\n"); - goto err; - } - if (h->bLength != sizeof(struct usb_cdc_header_desc)) { - dev_dbg(&intf->dev, "CDC header len %u\n", h->bLength); - goto err; - } - break; - case USB_CDC_UNION_TYPE: - if (found & 1 << USB_CDC_UNION_TYPE) { - dev_dbg(&intf->dev, "extra CDC union\n"); - goto err; - } - if (h->bLength != sizeof(struct usb_cdc_union_desc)) { - dev_dbg(&intf->dev, "CDC union len %u\n", h->bLength); - goto err; - } - cdc_union = (struct usb_cdc_union_desc *)buf; - break; - case USB_CDC_ETHERNET_TYPE: - if (found & 1 << USB_CDC_ETHERNET_TYPE) { - dev_dbg(&intf->dev, "extra CDC ether\n"); - goto err; - } - if (h->bLength != sizeof(struct usb_cdc_ether_desc)) { - dev_dbg(&intf->dev, "CDC ether len %u\n", h->bLength); - goto err; - } - cdc_ether = (struct usb_cdc_ether_desc *)buf; - break; - } - - /* - * Remember which CDC functional descriptors we've seen. Works - * for all types we care about, of which USB_CDC_ETHERNET_TYPE - * (0x0f) is the highest numbered - */ - if (buf[2] < 32) - found |= 1 << buf[2]; - -next_desc: - len -= h->bLength; - buf += h->bLength; - } - - /* did we find all the required ones? */ - if ((found & required) != required) { - dev_err(&intf->dev, "CDC functional descriptors missing\n"); - goto err; - } - - /* give the user a helpful hint if trying to bind to the wrong interface */ - if (cdc_union && desc->bInterfaceNumber == cdc_union->bMasterInterface0) { - dev_err(&intf->dev, "leaving \"control\" interface for " DM_DRIVER " - try binding to %s instead!\n", - dev_name(&usb_ifnum_to_if(dev->udev, cdc_union->bSlaveInterface0)->dev)); - goto err; - } - - /* errors aren't fatal - we can live with the dynamic address */ - if (cdc_ether) { - dev->hard_mtu = le16_to_cpu(cdc_ether->wMaxSegmentSize); - usbnet_get_ethernet_addr(dev, cdc_ether->iMACAddress); - } - - /* success! point the user to the management interface */ - if (control) - dev_info(&intf->dev, "Use \"" DM_DRIVER "\" for QMI interface %s\n", - dev_name(&control->dev)); - - /* XXX: add a sysfs symlink somewhere to help management applications find it? */ - - /* collect bulk endpoints now that we know intf == "data" interface */ - status = usbnet_get_endpoints(dev, intf); - -err: - return status; -} - -/* using a counter to merge subdriver requests with our own into a combined state */ -static int qmi_wwan_manage_power(struct usbnet *dev, int on) -{ - atomic_t *pmcount = (void *)&dev->data[1]; - int rv = 0; - - dev_dbg(&dev->intf->dev, "%s() pmcount=%d, on=%d\n", __func__, atomic_read(pmcount), on); - - if ((on && atomic_add_return(1, pmcount) == 1) || (!on && atomic_dec_and_test(pmcount))) { - /* need autopm_get/put here to ensure the usbcore sees the new value */ - rv = usb_autopm_get_interface(dev->intf); - if (rv < 0) - goto err; - dev->intf->needs_remote_wakeup = on; - usb_autopm_put_interface(dev->intf); - } -err: - return rv; -} - -static int qmi_wwan_cdc_wdm_manage_power(struct usb_interface *intf, int on) -{ - struct usbnet *dev = usb_get_intfdata(intf); - - /* can be called while disconnecting */ - if (!dev) - return 0; - return qmi_wwan_manage_power(dev, on); -} - -/* Some devices combine the "control" and "data" functions into a - * single interface with all three endpoints: interrupt + bulk in and - * out - * - * Setting up cdc-wdm as a subdriver owning the interrupt endpoint - * will let it provide userspace access to the encapsulated QMI - * protocol without interfering with the usbnet operations. - */ -static int qmi_wwan_bind_shared(struct usbnet *dev, struct usb_interface *intf) -{ - int rv; - struct usb_driver *subdriver = NULL; - atomic_t *pmcount = (void *)&dev->data[1]; - - /* ZTE makes devices where the interface descriptors and endpoint - * configurations of two or more interfaces are identical, even - * though the functions are completely different. If set, then - * driver_info->data is a bitmap of acceptable interface numbers - * allowing us to bind to one such interface without binding to - * all of them - */ - if (dev->driver_info->data && - !test_bit(intf->cur_altsetting->desc.bInterfaceNumber, &dev->driver_info->data)) { - dev_info(&intf->dev, "not on our whitelist - ignored"); - rv = -ENODEV; - goto err; - } - - atomic_set(pmcount, 0); - - /* collect all three endpoints */ - rv = usbnet_get_endpoints(dev, intf); - if (rv < 0) - goto err; - - /* require interrupt endpoint for subdriver */ - if (!dev->status) { - rv = -EINVAL; - goto err; - } - - subdriver = usb_cdc_wdm_register(intf, &dev->status->desc, 512, &qmi_wwan_cdc_wdm_manage_power); - if (IS_ERR(subdriver)) { - rv = PTR_ERR(subdriver); - goto err; - } - - /* can't let usbnet use the interrupt endpoint */ - dev->status = NULL; - - /* save subdriver struct for suspend/resume wrappers */ - dev->data[0] = (unsigned long)subdriver; - -err: - return rv; -} - -static void qmi_wwan_unbind_shared(struct usbnet *dev, struct usb_interface *intf) -{ - struct usb_driver *subdriver = (void *)dev->data[0]; - - if (subdriver && subdriver->disconnect) - subdriver->disconnect(intf); - - dev->data[0] = (unsigned long)NULL; -} - -/* suspend/resume wrappers calling both usbnet and the cdc-wdm - * subdriver if present. - * - * NOTE: cdc-wdm also supports pre/post_reset, but we cannot provide - * wrappers for those without adding usbnet reset support first. - */ -static int qmi_wwan_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct usbnet *dev = usb_get_intfdata(intf); - struct usb_driver *subdriver = (void *)dev->data[0]; - int ret; - - ret = usbnet_suspend(intf, message); - if (ret < 0) - goto err; - - if (subdriver && subdriver->suspend) - ret = subdriver->suspend(intf, message); - if (ret < 0) - usbnet_resume(intf); -err: - return ret; -} - -static int qmi_wwan_resume(struct usb_interface *intf) -{ - struct usbnet *dev = usb_get_intfdata(intf); - struct usb_driver *subdriver = (void *)dev->data[0]; - int ret = 0; - - if (subdriver && subdriver->resume) - ret = subdriver->resume(intf); - if (ret < 0) - goto err; - ret = usbnet_resume(intf); - if (ret < 0 && subdriver && subdriver->resume && subdriver->suspend) - subdriver->suspend(intf, PMSG_SUSPEND); -err: - return ret; -} - - -static const struct driver_info qmi_wwan_info = { - .description = "QMI speaking wwan device", - .flags = FLAG_WWAN, - .bind = qmi_wwan_bind, - .manage_power = qmi_wwan_manage_power, -}; - -static const struct driver_info qmi_wwan_shared = { - .description = "QMI speaking wwan device with combined interface", - .flags = FLAG_WWAN, - .bind = qmi_wwan_bind_shared, - .unbind = qmi_wwan_unbind_shared, - .manage_power = qmi_wwan_manage_power, -}; - -static const struct driver_info qmi_wwan_force_int0 = { - .description = "Qualcomm WWAN/QMI device", - .flags = FLAG_WWAN, - .bind = qmi_wwan_bind_shared, - .unbind = qmi_wwan_unbind_shared, - .manage_power = qmi_wwan_manage_power, - .data = BIT(0), /* interface whitelist bitmap */ -}; - -static const struct driver_info qmi_wwan_force_int1 = { - .description = "Qualcomm WWAN/QMI device", - .flags = FLAG_WWAN, - .bind = qmi_wwan_bind_shared, - .unbind = qmi_wwan_unbind_shared, - .manage_power = qmi_wwan_manage_power, - .data = BIT(1), /* interface whitelist bitmap */ -}; - -static const struct driver_info qmi_wwan_force_int3 = { - .description = "Qualcomm WWAN/QMI device", - .flags = FLAG_WWAN, - .bind = qmi_wwan_bind_shared, - .unbind = qmi_wwan_unbind_shared, - .manage_power = qmi_wwan_manage_power, - .data = BIT(3), /* interface whitelist bitmap */ -}; - -static const struct driver_info qmi_wwan_force_int4 = { - .description = "Qualcomm WWAN/QMI device", - .flags = FLAG_WWAN, - .bind = qmi_wwan_bind_shared, - .unbind = qmi_wwan_unbind_shared, - .manage_power = qmi_wwan_manage_power, - .data = BIT(4), /* interface whitelist bitmap */ -}; - -/* Sierra Wireless provide equally useless interface descriptors - * Devices in QMI mode can be switched between two different - * configurations: - * a) USB interface #8 is QMI/wwan - * b) USB interfaces #8, #19 and #20 are QMI/wwan - * - * Both configurations provide a number of other interfaces (serial++), - * some of which have the same endpoint configuration as we expect, so - * a whitelist or blacklist is necessary. - * - * FIXME: The below whitelist should include BIT(20). It does not - * because I cannot get it to work... - */ -static const struct driver_info qmi_wwan_sierra = { - .description = "Sierra Wireless wwan/QMI device", - .flags = FLAG_WWAN, - .bind = qmi_wwan_bind_shared, - .unbind = qmi_wwan_unbind_shared, - .manage_power = qmi_wwan_manage_power, - .data = BIT(8) | BIT(19), /* interface whitelist bitmap */ -}; - -#define HUAWEI_VENDOR_ID 0x12D1 - -/* Gobi 1000 QMI/wwan interface number is 3 according to qcserial */ -#define QMI_GOBI1K_DEVICE(vend, prod) \ - USB_DEVICE(vend, prod), \ - .driver_info = (unsigned long)&qmi_wwan_force_int3 - -/* Gobi 2000 and Gobi 3000 QMI/wwan interface number is 0 according to qcserial */ -#define QMI_GOBI_DEVICE(vend, prod) \ - USB_DEVICE(vend, prod), \ - .driver_info = (unsigned long)&qmi_wwan_force_int0 - -static const struct usb_device_id products[] = { - { /* Huawei E392, E398 and possibly others sharing both device id and more... */ - .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = HUAWEI_VENDOR_ID, - .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 8, /* NOTE: This is the *slave* interface of the CDC Union! */ - .driver_info = (unsigned long)&qmi_wwan_info, - }, - { /* Huawei E392, E398 and possibly others in "Windows mode" - * using a combined control and data interface without any CDC - * functional descriptors - */ - .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = HUAWEI_VENDOR_ID, - .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 17, - .driver_info = (unsigned long)&qmi_wwan_shared, - }, - { /* Pantech UML290 */ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x106c, - .idProduct = 0x3718, - .bInterfaceClass = 0xff, - .bInterfaceSubClass = 0xf0, - .bInterfaceProtocol = 0xff, - .driver_info = (unsigned long)&qmi_wwan_shared, - }, - { /* ZTE MF820D */ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x19d2, - .idProduct = 0x0167, - .bInterfaceClass = 0xff, - .bInterfaceSubClass = 0xff, - .bInterfaceProtocol = 0xff, - .driver_info = (unsigned long)&qmi_wwan_force_int4, - }, - { /* ZTE (Vodafone) K3520-Z */ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x19d2, - .idProduct = 0x0055, - .bInterfaceClass = 0xff, - .bInterfaceSubClass = 0xff, - .bInterfaceProtocol = 0xff, - .driver_info = (unsigned long)&qmi_wwan_force_int1, - }, - { /* ZTE (Vodafone) K3565-Z */ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x19d2, - .idProduct = 0x0063, - .bInterfaceClass = 0xff, - .bInterfaceSubClass = 0xff, - .bInterfaceProtocol = 0xff, - .driver_info = (unsigned long)&qmi_wwan_force_int4, - }, - { /* ZTE (Vodafone) K3570-Z */ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x19d2, - .idProduct = 0x1008, - .bInterfaceClass = 0xff, - .bInterfaceSubClass = 0xff, - .bInterfaceProtocol = 0xff, - .driver_info = (unsigned long)&qmi_wwan_force_int4, - }, - { /* ZTE (Vodafone) K3571-Z */ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x19d2, - .idProduct = 0x1010, - .bInterfaceClass = 0xff, - .bInterfaceSubClass = 0xff, - .bInterfaceProtocol = 0xff, - .driver_info = (unsigned long)&qmi_wwan_force_int4, - }, - { /* ZTE (Vodafone) K4505-Z */ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x19d2, - .idProduct = 0x0104, - .bInterfaceClass = 0xff, - .bInterfaceSubClass = 0xff, - .bInterfaceProtocol = 0xff, - .driver_info = (unsigned long)&qmi_wwan_force_int4, - }, - { /* Sierra Wireless MC77xx in QMI mode */ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x1199, - .idProduct = 0x68a2, - .bInterfaceClass = 0xff, - .bInterfaceSubClass = 0xff, - .bInterfaceProtocol = 0xff, - .driver_info = (unsigned long)&qmi_wwan_sierra, - }, - - /* Gobi 1000 devices */ - {QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ - {QMI_GOBI1K_DEVICE(0x03f0, 0x1f1d)}, /* HP un2400 Gobi Modem Device */ - {QMI_GOBI1K_DEVICE(0x03f0, 0x371d)}, /* HP un2430 Mobile Broadband Module */ - {QMI_GOBI1K_DEVICE(0x04da, 0x250d)}, /* Panasonic Gobi Modem device */ - {QMI_GOBI1K_DEVICE(0x413c, 0x8172)}, /* Dell Gobi Modem device */ - {QMI_GOBI1K_DEVICE(0x1410, 0xa001)}, /* Novatel Gobi Modem device */ - {QMI_GOBI1K_DEVICE(0x0b05, 0x1776)}, /* Asus Gobi Modem device */ - {QMI_GOBI1K_DEVICE(0x19d2, 0xfff3)}, /* ONDA Gobi Modem device */ - {QMI_GOBI1K_DEVICE(0x05c6, 0x9001)}, /* Generic Gobi Modem device */ - {QMI_GOBI1K_DEVICE(0x05c6, 0x9002)}, /* Generic Gobi Modem device */ - {QMI_GOBI1K_DEVICE(0x05c6, 0x9202)}, /* Generic Gobi Modem device */ - {QMI_GOBI1K_DEVICE(0x05c6, 0x9203)}, /* Generic Gobi Modem device */ - {QMI_GOBI1K_DEVICE(0x05c6, 0x9222)}, /* Generic Gobi Modem device */ - {QMI_GOBI1K_DEVICE(0x05c6, 0x9009)}, /* Generic Gobi Modem device */ - - /* Gobi 2000 and 3000 devices */ - {QMI_GOBI_DEVICE(0x413c, 0x8186)}, /* Dell Gobi 2000 Modem device (N0218, VU936) */ - {QMI_GOBI_DEVICE(0x05c6, 0x920b)}, /* Generic Gobi 2000 Modem device */ - {QMI_GOBI_DEVICE(0x05c6, 0x9225)}, /* Sony Gobi 2000 Modem device (N0279, VU730) */ - {QMI_GOBI_DEVICE(0x05c6, 0x9245)}, /* Samsung Gobi 2000 Modem device (VL176) */ - {QMI_GOBI_DEVICE(0x03f0, 0x251d)}, /* HP Gobi 2000 Modem device (VP412) */ - {QMI_GOBI_DEVICE(0x05c6, 0x9215)}, /* Acer Gobi 2000 Modem device (VP413) */ - {QMI_GOBI_DEVICE(0x05c6, 0x9265)}, /* Asus Gobi 2000 Modem device (VR305) */ - {QMI_GOBI_DEVICE(0x05c6, 0x9235)}, /* Top Global Gobi 2000 Modem device (VR306) */ - {QMI_GOBI_DEVICE(0x05c6, 0x9275)}, /* iRex Technologies Gobi 2000 Modem device (VR307) */ - {QMI_GOBI_DEVICE(0x1199, 0x9001)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ - {QMI_GOBI_DEVICE(0x1199, 0x9002)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ - {QMI_GOBI_DEVICE(0x1199, 0x9003)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ - {QMI_GOBI_DEVICE(0x1199, 0x9004)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ - {QMI_GOBI_DEVICE(0x1199, 0x9005)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ - {QMI_GOBI_DEVICE(0x1199, 0x9006)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ - {QMI_GOBI_DEVICE(0x1199, 0x9007)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ - {QMI_GOBI_DEVICE(0x1199, 0x9008)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ - {QMI_GOBI_DEVICE(0x1199, 0x9009)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ - {QMI_GOBI_DEVICE(0x1199, 0x900a)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ - {QMI_GOBI_DEVICE(0x1199, 0x9011)}, /* Sierra Wireless Gobi 2000 Modem device (MC8305) */ - {QMI_GOBI_DEVICE(0x16d8, 0x8002)}, /* CMDTech Gobi 2000 Modem device (VU922) */ - {QMI_GOBI_DEVICE(0x05c6, 0x9205)}, /* Gobi 2000 Modem device */ - {QMI_GOBI_DEVICE(0x1199, 0x9013)}, /* Sierra Wireless Gobi 3000 Modem device (MC8355) */ - { } /* END */ -}; -MODULE_DEVICE_TABLE(usb, products); - -static struct usb_driver qmi_wwan_driver = { - .name = "qmi_wwan", - .id_table = products, - .probe = usbnet_probe, - .disconnect = usbnet_disconnect, - .suspend = qmi_wwan_suspend, - .resume = qmi_wwan_resume, - .reset_resume = qmi_wwan_resume, - .supports_autosuspend = 1, -}; - -static int __init qmi_wwan_init(void) -{ - return usb_register(&qmi_wwan_driver); -} -module_init(qmi_wwan_init); - -static void __exit qmi_wwan_exit(void) -{ - usb_deregister(&qmi_wwan_driver); -} -module_exit(qmi_wwan_exit); - -MODULE_AUTHOR("Bjørn Mork <bjorn@mork.no>"); -MODULE_DESCRIPTION("Qualcomm MSM Interface (QMI) WWAN driver"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/net/usb/r8152.c b/ANDROID_3.4.5/drivers/net/usb/r8152.c deleted file mode 100755 index a1021d0c..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/r8152.c +++ /dev/null @@ -1,5481 +0,0 @@ -/* - * Copyright (c) 2014 Realtek Semiconductor Corp. All rights reserved. - * - * 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. - * - * This product is covered by one or more of the following patents: - * US6,570,884, US6,115,776, and US6,327,625. - */ - -#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 <linux/crc32.h> -#include <linux/if_vlan.h> -#include <linux/uaccess.h> -#include <linux/list.h> -#include <linux/ip.h> -#include <linux/ipv6.h> -#include <net/ip6_checksum.h> -#include "compatibility.h" - -/* Version Information */ -#define DRIVER_VERSION "v2.02.0 (2014/08/21)" -#define DRIVER_AUTHOR "Realtek nic sw <nic_swsd@realtek.com>" -#define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters" -#define MODULENAME "r8152" - -#define PATENTS "This product is covered by one or more of the " \ - "following patents:\n" \ - "\t\tUS6,570,884, US6,115,776, and US6,327,625.\n" - -#define R8152_PHY_ID 32 - -#define PLA_IDR 0xc000 -#define PLA_RCR 0xc010 -#define PLA_RMS 0xc016 -#define PLA_RXFIFO_CTRL0 0xc0a0 -#define PLA_RXFIFO_CTRL1 0xc0a4 -#define PLA_RXFIFO_CTRL2 0xc0a8 -#define PLA_FMC 0xc0b4 -#define PLA_CFG_WOL 0xc0b6 -#define PLA_TEREDO_CFG 0xc0bc -#define PLA_MAR 0xcd00 -#define PLA_BACKUP 0xd000 -#define PAL_BDC_CR 0xd1a0 -#define PLA_TEREDO_TIMER 0xd2cc -#define PLA_REALWOW_TIMER 0xd2e8 -#define PLA_LEDSEL 0xdd90 -#define PLA_LED_FEATURE 0xdd92 -#define PLA_PHYAR 0xde00 -#define PLA_BOOT_CTRL 0xe004 -#define PLA_GPHY_INTR_IMR 0xe022 -#define PLA_EEE_CR 0xe040 -#define PLA_EEEP_CR 0xe080 -#define PLA_MAC_PWR_CTRL 0xe0c0 -#define PLA_MAC_PWR_CTRL2 0xe0ca -#define PLA_MAC_PWR_CTRL3 0xe0cc -#define PLA_MAC_PWR_CTRL4 0xe0ce -#define PLA_WDT6_CTRL 0xe428 -#define PLA_TCR0 0xe610 -#define PLA_TCR1 0xe612 -#define PLA_MTPS 0xe615 -#define PLA_TXFIFO_CTRL 0xe618 -#define PLA_RSTTALLY 0xe800 -#define PLA_CR 0xe813 -#define PLA_CRWECR 0xe81c -#define PLA_CONFIG12 0xe81e /* CONFIG1, CONFIG2 */ -#define PLA_CONFIG34 0xe820 /* CONFIG3, CONFIG4 */ -#define PLA_CONFIG5 0xe822 -#define PLA_PHY_PWR 0xe84c -#define PLA_OOB_CTRL 0xe84f -#define PLA_CPCR 0xe854 -#define PLA_MISC_0 0xe858 -#define PLA_MISC_1 0xe85a -#define PLA_OCP_GPHY_BASE 0xe86c -#define PLA_TALLYCNT 0xe890 -#define PLA_SFF_STS_7 0xe8de -#define PLA_PHYSTATUS 0xe908 -#define PLA_BP_BA 0xfc26 -#define PLA_BP_0 0xfc28 -#define PLA_BP_1 0xfc2a -#define PLA_BP_2 0xfc2c -#define PLA_BP_3 0xfc2e -#define PLA_BP_4 0xfc30 -#define PLA_BP_5 0xfc32 -#define PLA_BP_6 0xfc34 -#define PLA_BP_7 0xfc36 -#define PLA_BP_EN 0xfc38 - -#define USB_U2P3_CTRL 0xb460 -#define USB_DEV_STAT 0xb808 -#define USB_USB_CTRL 0xd406 -#define USB_PHY_CTRL 0xd408 -#define USB_TX_AGG 0xd40a -#define USB_RX_BUF_TH 0xd40c -#define USB_USB_TIMER 0xd428 -#define USB_RX_EARLY_AGG 0xd42c -#define USB_PM_CTRL_STATUS 0xd432 -#define USB_TX_DMA 0xd434 -#define USB_TOLERANCE 0xd490 -#define USB_LPM_CTRL 0xd41a -#define USB_UPS_CTRL 0xd800 -#define USB_MISC_0 0xd81a -#define USB_POWER_CUT 0xd80a -#define USB_AFE_CTRL2 0xd824 -#define USB_WDT11_CTRL 0xe43c -#define USB_BP_BA 0xfc26 -#define USB_BP_0 0xfc28 -#define USB_BP_1 0xfc2a -#define USB_BP_2 0xfc2c -#define USB_BP_3 0xfc2e -#define USB_BP_4 0xfc30 -#define USB_BP_5 0xfc32 -#define USB_BP_6 0xfc34 -#define USB_BP_7 0xfc36 -#define USB_BP_EN 0xfc38 - -/* OCP Registers */ -#define OCP_ALDPS_CONFIG 0x2010 -#define OCP_EEE_CONFIG1 0x2080 -#define OCP_EEE_CONFIG2 0x2092 -#define OCP_EEE_CONFIG3 0x2094 -#define OCP_BASE_MII 0xa400 -#define OCP_EEE_AR 0xa41a -#define OCP_EEE_DATA 0xa41c -#define OCP_PHY_STATUS 0xa420 -#define OCP_POWER_CFG 0xa430 -#define OCP_EEE_CFG 0xa432 -#define OCP_SRAM_ADDR 0xa436 -#define OCP_SRAM_DATA 0xa438 -#define OCP_DOWN_SPEED 0xa442 -#define OCP_EEE_CFG2 0xa5d0 -#define OCP_ADC_CFG 0xbc06 - -/* SRAM Register */ -#define SRAM_LPF_CFG 0x8012 -#define SRAM_10M_AMP1 0x8080 -#define SRAM_10M_AMP2 0x8082 -#define SRAM_IMPEDANCE 0x8084 - -/* PLA_RCR */ -#define RCR_AAP 0x00000001 -#define RCR_APM 0x00000002 -#define RCR_AM 0x00000004 -#define RCR_AB 0x00000008 -#define RCR_ACPT_ALL (RCR_AAP | RCR_APM | RCR_AM | RCR_AB) - -/* PLA_RXFIFO_CTRL0 */ -#define RXFIFO_THR1_NORMAL 0x00080002 -#define RXFIFO_THR1_OOB 0x01800003 - -/* PLA_RXFIFO_CTRL1 */ -#define RXFIFO_THR2_FULL 0x00000060 -#define RXFIFO_THR2_HIGH 0x00000038 -#define RXFIFO_THR2_OOB 0x0000004a -#define RXFIFO_THR2_NORMAL 0x00a0 - -/* PLA_RXFIFO_CTRL2 */ -#define RXFIFO_THR3_FULL 0x00000078 -#define RXFIFO_THR3_HIGH 0x00000048 -#define RXFIFO_THR3_OOB 0x0000005a -#define RXFIFO_THR3_NORMAL 0x0110 - -/* PLA_TXFIFO_CTRL */ -#define TXFIFO_THR_NORMAL 0x00400008 -#define TXFIFO_THR_NORMAL2 0x01000008 - -/* PLA_FMC */ -#define FMC_FCR_MCU_EN 0x0001 - -/* PLA_EEEP_CR */ -#define EEEP_CR_EEEP_TX 0x0002 - -/* PLA_WDT6_CTRL */ -#define WDT6_SET_MODE 0x0010 - -/* PLA_TCR0 */ -#define TCR0_TX_EMPTY 0x0800 -#define TCR0_AUTO_FIFO 0x0080 - -/* PLA_TCR1 */ -#define VERSION_MASK 0x7cf0 - -/* PLA_MTPS */ -#define MTPS_JUMBO (12 * 1024 / 64) -#define MTPS_DEFAULT (6 * 1024 / 64) - -/* PLA_RSTTALLY */ -#define TALLY_RESET 0x0001 - -/* PLA_CR */ -#define CR_RST 0x10 -#define CR_RE 0x08 -#define CR_TE 0x04 - -/* PLA_CRWECR */ -#define CRWECR_NORAML 0x00 -#define CRWECR_CONFIG 0xc0 - -/* PLA_OOB_CTRL */ -#define NOW_IS_OOB 0x80 -#define TXFIFO_EMPTY 0x20 -#define RXFIFO_EMPTY 0x10 -#define LINK_LIST_READY 0x02 -#define DIS_MCU_CLROOB 0x01 -#define FIFO_EMPTY (TXFIFO_EMPTY | RXFIFO_EMPTY) - -/* PLA_MISC_1 */ -#define RXDY_GATED_EN 0x0008 - -/* PLA_SFF_STS_7 */ -#define RE_INIT_LL 0x8000 -#define MCU_BORW_EN 0x4000 - -/* PLA_CPCR */ -#define CPCR_RX_VLAN 0x0040 - -/* PLA_CFG_WOL */ -#define MAGIC_EN 0x0001 - -/* PLA_TEREDO_CFG */ -#define TEREDO_SEL 0x8000 -#define TEREDO_WAKE_MASK 0x7f00 -#define TEREDO_RS_EVENT_MASK 0x00fe -#define OOB_TEREDO_EN 0x0001 - -/* PAL_BDC_CR */ -#define ALDPS_PROXY_MODE 0x0001 - -/* PLA_CONFIG34 */ -#define LINK_ON_WAKE_EN 0x0010 -#define LINK_OFF_WAKE_EN 0x0008 - -/* PLA_CONFIG5 */ -#define BWF_EN 0x0040 -#define MWF_EN 0x0020 -#define UWF_EN 0x0010 -#define LAN_WAKE_EN 0x0002 - -/* PLA_LED_FEATURE */ -#define LED_MODE_MASK 0x0700 - -/* PLA_PHY_PWR */ -#define TX_10M_IDLE_EN 0x0080 -#define PFM_PWM_SWITCH 0x0040 - -/* PLA_MAC_PWR_CTRL */ -#define D3_CLK_GATED_EN 0x00004000 -#define MCU_CLK_RATIO 0x07010f07 -#define MCU_CLK_RATIO_MASK 0x0f0f0f0f -#define ALDPS_SPDWN_RATIO 0x0f87 - -/* PLA_MAC_PWR_CTRL2 */ -#define EEE_SPDWN_RATIO 0x8007 - -/* PLA_MAC_PWR_CTRL3 */ -#define PKT_AVAIL_SPDWN_EN 0x0100 -#define SUSPEND_SPDWN_EN 0x0004 -#define U1U2_SPDWN_EN 0x0002 -#define L1_SPDWN_EN 0x0001 - -/* PLA_MAC_PWR_CTRL4 */ -#define PWRSAVE_SPDWN_EN 0x1000 -#define RXDV_SPDWN_EN 0x0800 -#define TX10MIDLE_EN 0x0100 -#define TP100_SPDWN_EN 0x0020 -#define TP500_SPDWN_EN 0x0010 -#define TP1000_SPDWN_EN 0x0008 -#define EEE_SPDWN_EN 0x0001 - -/* PLA_GPHY_INTR_IMR */ -#define GPHY_STS_MSK 0x0001 -#define SPEED_DOWN_MSK 0x0002 -#define SPDWN_RXDV_MSK 0x0004 -#define SPDWN_LINKCHG_MSK 0x0008 - -/* PLA_PHYAR */ -#define PHYAR_FLAG 0x80000000 - -/* PLA_EEE_CR */ -#define EEE_RX_EN 0x0001 -#define EEE_TX_EN 0x0002 - -/* PLA_BOOT_CTRL */ -#define AUTOLOAD_DONE 0x0002 - -/* USB_DEV_STAT */ -#define STAT_SPEED_MASK 0x0006 -#define STAT_SPEED_HIGH 0x0000 -#define STAT_SPEED_FULL 0x0002 - -/* USB_TX_AGG */ -#define TX_AGG_MAX_THRESHOLD 0x03 - -/* USB_RX_BUF_TH */ -#define RX_THR_SUPPER 0x0c350180 -#define RX_THR_HIGH 0x7a120180 -#define RX_THR_SLOW 0xffff0180 - -/* USB_TX_DMA */ -#define TEST_MODE_DISABLE 0x00000001 -#define TX_SIZE_ADJUST1 0x00000100 - -/* USB_UPS_CTRL */ -#define POWER_CUT 0x0100 - -/* USB_PM_CTRL_STATUS */ -#define RESUME_INDICATE 0x0001 - -/* USB_USB_CTRL */ -#define RX_AGG_DISABLE 0x0010 - -/* USB_U2P3_CTRL */ -#define U2P3_ENABLE 0x0001 - -/* USB_POWER_CUT */ -#define PWR_EN 0x0001 -#define PHASE2_EN 0x0008 - -/* USB_MISC_0 */ -#define PCUT_STATUS 0x0001 - -/* USB_RX_EARLY_AGG */ -#if defined(__i386__) || defined(__x86_64__) - #define EARLY_AGG_SUPER 0x0e832981 -#else - #define EARLY_AGG_SUPER 0x0e835000 -#endif -#define EARLY_AGG_HIGH 0x0e837a12 -#define EARLY_AGG_SLOW 0x0e83ffff - -/* USB_WDT11_CTRL */ -#define TIMER11_EN 0x0001 - -/* USB_LPM_CTRL */ -#define LPM_TIMER_MASK 0x0c -#define LPM_TIMER_500MS 0x04 /* 500 ms */ -#define LPM_TIMER_500US 0x0c /* 500 us */ - -/* USB_AFE_CTRL2 */ -#define SEN_VAL_MASK 0xf800 -#define SEN_VAL_NORMAL 0xa000 -#define SEL_RXIDLE 0x0100 - -/* OCP_ALDPS_CONFIG */ -#define ENPWRSAVE 0x8000 -#define ENPDNPS 0x0200 -#define LINKENA 0x0100 -#define DIS_SDSAVE 0x0010 - -/* OCP_PHY_STATUS */ -#define PHY_STAT_MASK 0x0007 -#define PHY_STAT_LAN_ON 3 -#define PHY_STAT_PWRDN 5 - -/* OCP_POWER_CFG */ -#define EEE_CLKDIV_EN 0x8000 -#define EN_ALDPS 0x0004 -#define EN_10M_PLLOFF 0x0001 - -/* OCP_EEE_CONFIG1 */ -#define RG_TXLPI_MSK_HFDUP 0x8000 -#define RG_MATCLR_EN 0x4000 -#define EEE_10_CAP 0x2000 -#define EEE_NWAY_EN 0x1000 -#define TX_QUIET_EN 0x0200 -#define RX_QUIET_EN 0x0100 -#define SDRISETIME 0x0010 /* bit 4 ~ 6 */ -#define RG_RXLPI_MSK_HFDUP 0x0008 -#define SDFALLTIME 0x0007 /* bit 0 ~ 2 */ - -/* OCP_EEE_CONFIG2 */ -#define RG_LPIHYS_NUM 0x7000 /* bit 12 ~ 15 */ -#define RG_DACQUIET_EN 0x0400 -#define RG_LDVQUIET_EN 0x0200 -#define RG_CKRSEL 0x0020 -#define RG_EEEPRG_EN 0x0010 - -/* OCP_EEE_CONFIG3 */ -#define FST_SNR_EYE_R 0x1500 /* bit 7 ~ 15 */ -#define RG_LFS_SEL 0x0060 /* bit 6 ~ 5 */ -#define MSK_PH 0x0006 /* bit 0 ~ 3 */ - -/* OCP_EEE_AR */ -/* bit[15:14] function */ -#define FUN_ADDR 0x0000 -#define FUN_DATA 0x4000 -/* bit[4:0] device addr */ -#define DEVICE_ADDR 0x0007 - -/* OCP_EEE_DATA */ -#define EEE_ADDR 0x003C -#define EEE_DATA 0x0002 - -/* OCP_EEE_CFG */ -#define CTAP_SHORT_EN 0x0040 -#define EEE10_EN 0x0010 - -/* OCP_DOWN_SPEED */ -#define EN_10M_BGOFF 0x0080 - -/* OCP_EEE_CFG2 */ -#define MY1000_EEE 0x0004 -#define MY100_EEE 0x0002 - -/* OCP_ADC_CFG */ -#define CKADSEL_L 0x0100 -#define ADC_EN 0x0080 -#define EN_EMI_L 0x0040 - -/* SRAM_LPF_CFG */ -#define LPF_AUTO_TUNE 0x8000 - -/* SRAM_10M_AMP1 */ -#define GDAC_IB_UPALL 0x0008 - -/* SRAM_10M_AMP2 */ -#define AMP_DN 0x0200 - -/* SRAM_IMPEDANCE */ -#define RX_DRIVING_MASK 0x6000 - -enum rtl_register_content { - _1000bps = 0x10, - _100bps = 0x08, - _10bps = 0x04, - LINK_STATUS = 0x02, - FULL_DUP = 0x01, -}; - -#define RTL8152_MAX_TX 4 -#define RTL8152_MAX_RX 10 -#define INTBUFSIZE 2 -#define CRC_SIZE 4 -#define TX_ALIGN 4 -#define RX_ALIGN 8 - -#define INTR_LINK 0x0004 - -#define RTL8152_REQT_READ 0xc0 -#define RTL8152_REQT_WRITE 0x40 -#define RTL8152_REQ_GET_REGS 0x05 -#define RTL8152_REQ_SET_REGS 0x05 - -#define BYTE_EN_DWORD 0xff -#define BYTE_EN_WORD 0x33 -#define BYTE_EN_BYTE 0x11 -#define BYTE_EN_SIX_BYTES 0x3f -#define BYTE_EN_START_MASK 0x0f -#define BYTE_EN_END_MASK 0xf0 - -#define RTL8153_MAX_PACKET 9216 /* 9K */ -#define RTL8153_MAX_MTU (RTL8153_MAX_PACKET - VLAN_ETH_HLEN - VLAN_HLEN) -#define RTL8152_RMS (VLAN_ETH_FRAME_LEN + VLAN_HLEN) -#define RTL8153_RMS RTL8153_MAX_PACKET -#define RTL8152_TX_TIMEOUT (5 * HZ) - -/* rtl8152 flags */ -enum rtl8152_flags { - RTL8152_UNPLUG = 0, - RTL8152_SET_RX_MODE, - WORK_ENABLE, - RTL8152_LINK_CHG, - SELECTIVE_SUSPEND, - PHY_RESET, - SCHEDULE_TASKLET, -}; - -/* Define these values to match your device */ -#define VENDOR_ID_REALTEK 0x0bda -#define PRODUCT_ID_RTL8152 0x8152 -#define PRODUCT_ID_RTL8153 0x8153 - -#define VENDOR_ID_SAMSUNG 0x04e8 -#define PRODUCT_ID_SAMSUNG 0xa101 - -#define VENDOR_ID_LENOVO 0x17ef - -#define MCU_TYPE_PLA 0x0100 -#define MCU_TYPE_USB 0x0000 - -struct tally_counter { - __le64 tx_packets; - __le64 rx_packets; - __le64 tx_errors; - __le32 rx_errors; - __le16 rx_missed; - __le16 align_errors; - __le32 tx_one_collision; - __le32 tx_multi_collision; - __le64 rx_unicast; - __le64 rx_broadcast; - __le32 rx_multicast; - __le16 tx_aborted; - __le16 tx_underun; -}; - -struct rx_desc { - __le32 opts1; -#define RD_CRC (1 << 15) -#define RX_LEN_MASK 0x7fff - - __le32 opts2; -#define RD_UDP_CS (1 << 23) -#define RD_TCP_CS (1 << 22) -#define RD_IPV6_CS (1 << 20) -#define RD_IPV4_CS (1 << 19) - - __le32 opts3; -#define IPF (1 << 23) /* IP checksum fail */ -#define UDPF (1 << 22) /* UDP checksum fail */ -#define TCPF (1 << 21) /* TCP checksum fail */ - - __le32 opts4; - __le32 opts5; - __le32 opts6; -}; - -struct tx_desc { - __le32 opts1; -#define TX_FS (1 << 31) /* First segment of a packet */ -#define TX_LS (1 << 30) /* Final segment of a packet */ -#define LGSEND (1 << 29) -#define GTSENDV4 (1 << 28) -#define GTSENDV6 (1 << 27) -#define GTTCPHO_SHIFT 18 -#define GTTCPHO_MAX 0x7fU -#define TX_LEN_MAX 0x3ffffU - - __le32 opts2; -#define UDP_CS (1 << 31) /* Calculate UDP/IP checksum */ -#define TCP_CS (1 << 30) /* Calculate TCP/IP checksum */ -#define IPV4_CS (1 << 29) /* Calculate IPv4 checksum */ -#define IPV6_CS (1 << 28) /* Calculate IPv6 checksum */ -#define MSS_SHIFT 17 -#define MSS_MAX 0x7ffU -#define TCPHO_SHIFT 17 -#define TCPHO_MAX 0x7ffU -}; - -struct r8152; - -struct rx_agg { - struct list_head list; - struct urb *urb; - struct r8152 *context; - void *buffer; - void *head; -}; - -struct tx_agg { - struct list_head list; - struct urb *urb; - struct r8152 *context; - void *buffer; - void *head; - u32 skb_num; - u32 skb_len; -}; - -struct r8152 { - unsigned long flags; - struct usb_device *udev; - struct tasklet_struct tl; - struct usb_interface *intf; - struct net_device *netdev; - struct urb *intr_urb; - struct tx_agg tx_info[RTL8152_MAX_TX]; - struct rx_agg rx_info[RTL8152_MAX_RX]; - struct list_head rx_done, tx_free; - struct sk_buff_head tx_queue; - spinlock_t rx_lock, tx_lock; - struct delayed_work schedule; - struct mii_if_info mii; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) - struct net_device_stats stats; -#endif - - struct rtl_ops { - void (*init)(struct r8152 *); - int (*enable)(struct r8152 *); - void (*disable)(struct r8152 *); - void (*up)(struct r8152 *); - void (*down)(struct r8152 *); - void (*unload)(struct r8152 *); - } rtl_ops; - - int intr_interval; - u32 saved_wolopts; - u32 msg_enable; - u32 tx_qlen; - u16 ocp_base; - u8 *intr_buff; - u8 version; - u8 speed; - u8 rtk_enable_diag; -}; - -enum rtl_version { - RTL_VER_UNKNOWN = 0, - RTL_VER_01, - RTL_VER_02, - RTL_VER_03, - RTL_VER_04, - RTL_VER_05, - RTL_VER_MAX -}; - -enum tx_csum_stat { - TX_CSUM_SUCCESS = 0, - TX_CSUM_TSO, - TX_CSUM_NONE -}; - -/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). - * The RTL chips use a 64 element hash table based on the Ethernet CRC. - */ -static const int multicast_filter_limit = 32; -static unsigned int rx_buf_sz = 16384; - -#define RTL_LIMITED_TSO_SIZE (rx_buf_sz - sizeof(struct tx_desc) - \ - VLAN_ETH_HLEN - VLAN_HLEN) - -static -int get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data) -{ - int ret; - void *tmp; - - tmp = kmalloc(size, GFP_KERNEL); - if (!tmp) - return -ENOMEM; - - ret = usb_control_msg(tp->udev, usb_rcvctrlpipe(tp->udev, 0), - RTL8152_REQ_GET_REGS, RTL8152_REQT_READ, - value, index, tmp, size, 500); - - memcpy(data, tmp, size); - kfree(tmp); - - return ret; -} - -static -int set_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data) -{ - int ret; - void *tmp; - - tmp = kmemdup(data, size, GFP_KERNEL); - if (!tmp) - return -ENOMEM; - - ret = usb_control_msg(tp->udev, usb_sndctrlpipe(tp->udev, 0), - RTL8152_REQ_SET_REGS, RTL8152_REQT_WRITE, - value, index, tmp, size, 500); - - kfree(tmp); - - return ret; -} - -static int generic_ocp_read(struct r8152 *tp, u16 index, u16 size, - void *data, u16 type) -{ - u16 limit = 64; - int ret = 0; - - if (test_bit(RTL8152_UNPLUG, &tp->flags)) - return -ENODEV; - - /* both size and indix must be 4 bytes align */ - if ((size & 3) || !size || (index & 3) || !data) - return -EPERM; - - if ((u32)index + (u32)size > 0xffff) - return -EPERM; - - while (size) { - if (size > limit) { - ret = get_registers(tp, index, type, limit, data); - if (ret < 0) - break; - - index += limit; - data += limit; - size -= limit; - } else { - ret = get_registers(tp, index, type, size, data); - if (ret < 0) - break; - - index += size; - data += size; - size = 0; - break; - } - } - - return ret; -} - -static int generic_ocp_write(struct r8152 *tp, u16 index, u16 byteen, - u16 size, void *data, u16 type) -{ - int ret; - u16 byteen_start, byteen_end, byen; - u16 limit = 512; - - if (test_bit(RTL8152_UNPLUG, &tp->flags)) - return -ENODEV; - - /* both size and indix must be 4 bytes align */ - if ((size & 3) || !size || (index & 3) || !data) - return -EPERM; - - if ((u32)index + (u32)size > 0xffff) - return -EPERM; - - byteen_start = byteen & BYTE_EN_START_MASK; - byteen_end = byteen & BYTE_EN_END_MASK; - - byen = byteen_start | (byteen_start << 4); - ret = set_registers(tp, index, type | byen, 4, data); - if (ret < 0) - goto error1; - - index += 4; - data += 4; - size -= 4; - - if (size) { - size -= 4; - - while (size) { - if (size > limit) { - ret = set_registers(tp, index, - type | BYTE_EN_DWORD, - limit, data); - if (ret < 0) - goto error1; - - index += limit; - data += limit; - size -= limit; - } else { - ret = set_registers(tp, index, - type | BYTE_EN_DWORD, - size, data); - if (ret < 0) - goto error1; - - index += size; - data += size; - size = 0; - break; - } - } - - byen = byteen_end | (byteen_end >> 4); - ret = set_registers(tp, index, type | byen, 4, data); - if (ret < 0) - goto error1; - } - -error1: - return ret; -} - -static inline -int pla_ocp_read(struct r8152 *tp, u16 index, u16 size, void *data) -{ - return generic_ocp_read(tp, index, size, data, MCU_TYPE_PLA); -} - -static inline int pla_ocp_real_write(struct r8152 *tp, u16 index, - u16 byteen, u16 size, void *data) -{ - return generic_ocp_write(tp, index, byteen, size, data, MCU_TYPE_PLA); -} - -static -int pla_ocp_write(struct r8152 *tp, u16 index, u16 byteen, u16 size, void *data) -{ - if (tp->rtk_enable_diag == 1) - return 0; - - return pla_ocp_real_write(tp, index, byteen, size, data); -} - -static inline -int usb_ocp_read(struct r8152 *tp, u16 index, u16 size, void *data) -{ - return generic_ocp_read(tp, index, size, data, MCU_TYPE_USB); -} - -static inline int usb_ocp_real_write(struct r8152 *tp, u16 index, - u16 byteen, u16 size, void *data) -{ - return generic_ocp_write(tp, index, byteen, size, data, MCU_TYPE_USB); -} - -static -int usb_ocp_write(struct r8152 *tp, u16 index, u16 byteen, u16 size, void *data) -{ - if (tp->rtk_enable_diag == 1) - return 0; - - return usb_ocp_real_write(tp, index, byteen, size, data); -} - -static u32 ocp_read_dword(struct r8152 *tp, u16 type, u16 index) -{ - __le32 data; - - generic_ocp_read(tp, index, sizeof(data), &data, type); - - return __le32_to_cpu(data); -} - -static -void ocp_write_real_dword(struct r8152 *tp, u16 type, u16 index, u32 data) -{ - __le32 tmp = __cpu_to_le32(data); - - generic_ocp_write(tp, index, BYTE_EN_DWORD, sizeof(tmp), &tmp, type); -} - -static void ocp_write_dword(struct r8152 *tp, u16 type, u16 index, u32 data) -{ - if (tp->rtk_enable_diag == 1) - return; - - ocp_write_real_dword(tp, type, index, data); -} - -static u16 ocp_read_word(struct r8152 *tp, u16 type, u16 index) -{ - u32 data; - __le32 tmp; - u8 shift = index & 2; - - index &= ~3; - - generic_ocp_read(tp, index, sizeof(tmp), &tmp, type); - - data = __le32_to_cpu(tmp); - data >>= (shift * 8); - data &= 0xffff; - - return (u16)data; -} - -static void ocp_write_real_word(struct r8152 *tp, u16 type, u16 index, u32 data) -{ - u32 mask = 0xffff; - __le32 tmp; - u16 byen = BYTE_EN_WORD; - u8 shift = index & 2; - - data &= mask; - - if (index & 2) { - byen <<= shift; - mask <<= (shift * 8); - data <<= (shift * 8); - index &= ~3; - } - - generic_ocp_read(tp, index, sizeof(tmp), &tmp, type); - - data |= __le32_to_cpu(tmp) & ~mask; - tmp = __cpu_to_le32(data); - - generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type); -} - -static void ocp_write_word(struct r8152 *tp, u16 type, u16 index, u32 data) -{ - if (tp->rtk_enable_diag == 1) - return; - - ocp_write_real_word(tp, type, index, data); -} - -static u8 ocp_read_byte(struct r8152 *tp, u16 type, u16 index) -{ - u32 data; - __le32 tmp; - u8 shift = index & 3; - - index &= ~3; - - generic_ocp_read(tp, index, sizeof(tmp), &tmp, type); - - data = __le32_to_cpu(tmp); - data >>= (shift * 8); - data &= 0xff; - - return (u8)data; -} - -static void ocp_write_real_byte(struct r8152 *tp, u16 type, u16 index, u32 data) -{ - u32 mask = 0xff; - __le32 tmp; - u16 byen = BYTE_EN_BYTE; - u8 shift = index & 3; - - data &= mask; - - if (index & 3) { - byen <<= shift; - mask <<= (shift * 8); - data <<= (shift * 8); - index &= ~3; - } - - generic_ocp_read(tp, index, sizeof(tmp), &tmp, type); - - data |= __le32_to_cpu(tmp) & ~mask; - tmp = __cpu_to_le32(data); - - generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type); -} - -static void ocp_write_byte(struct r8152 *tp, u16 type, u16 index, u32 data) -{ - if (tp->rtk_enable_diag == 1) - return; - - ocp_write_real_byte(tp, type, index, data); -} - -static u16 ocp_reg_read(struct r8152 *tp, u16 addr) -{ - u16 ocp_base, ocp_index; - - if (tp->rtk_enable_diag == 1) - return -1; - - ocp_base = addr & 0xf000; - if (ocp_base != tp->ocp_base) { - ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, ocp_base); - tp->ocp_base = ocp_base; - } - - ocp_index = (addr & 0x0fff) | 0xb000; - return ocp_read_word(tp, MCU_TYPE_PLA, ocp_index); -} - -static void ocp_reg_write(struct r8152 *tp, u16 addr, u16 data) -{ - u16 ocp_base, ocp_index; - - if (tp->rtk_enable_diag == 1) - return; - - ocp_base = addr & 0xf000; - if (ocp_base != tp->ocp_base) { - ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, ocp_base); - tp->ocp_base = ocp_base; - } - - ocp_index = (addr & 0x0fff) | 0xb000; - ocp_write_word(tp, MCU_TYPE_PLA, ocp_index, data); -} - -static inline void r8152_mdio_write(struct r8152 *tp, u32 reg_addr, u32 value) -{ - ocp_reg_write(tp, OCP_BASE_MII + reg_addr * 2, value); -} - -static inline int r8152_mdio_read(struct r8152 *tp, u32 reg_addr) -{ - return ocp_reg_read(tp, OCP_BASE_MII + reg_addr * 2); -} - -static void sram_write(struct r8152 *tp, u16 addr, u16 data) -{ - ocp_reg_write(tp, OCP_SRAM_ADDR, addr); - ocp_reg_write(tp, OCP_SRAM_DATA, data); -} - -static u16 sram_read(struct r8152 *tp, u16 addr) -{ - ocp_reg_write(tp, OCP_SRAM_ADDR, addr); - return ocp_reg_read(tp, OCP_SRAM_DATA); -} - -static int read_mii_word(struct net_device *netdev, int phy_id, int reg) -{ - struct r8152 *tp = netdev_priv(netdev); - int ret; - - if (test_bit(RTL8152_UNPLUG, &tp->flags)) - return -ENODEV; - - if (phy_id != R8152_PHY_ID) - return -EINVAL; - - ret = usb_autopm_get_interface(tp->intf); - if (ret < 0) - goto out; - - ret = r8152_mdio_read(tp, reg); - - usb_autopm_put_interface(tp->intf); - -out: - return ret; -} - -static -void write_mii_word(struct net_device *netdev, int phy_id, int reg, int val) -{ - struct r8152 *tp = netdev_priv(netdev); - - if (test_bit(RTL8152_UNPLUG, &tp->flags)) - return; - - if (phy_id != R8152_PHY_ID) - return; - - if (usb_autopm_get_interface(tp->intf) < 0) - return; - - r8152_mdio_write(tp, reg, val); - - usb_autopm_put_interface(tp->intf); -} - -static int -r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags); - -static int rtl8152_set_mac_address(struct net_device *netdev, void *p) -{ - struct r8152 *tp = netdev_priv(netdev); - struct sockaddr *addr = p; - - if (!is_valid_ether_addr(addr->sa_data)) - return -EADDRNOTAVAIL; - - memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); - - ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG); - pla_ocp_write(tp, PLA_IDR, BYTE_EN_SIX_BYTES, 8, addr->sa_data); - ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML); - - return 0; -} - -static int set_ethernet_addr(struct r8152 *tp) -{ - struct net_device *dev = tp->netdev; - struct sockaddr sa; - int ret; - - if (tp->version == RTL_VER_01) - ret = pla_ocp_read(tp, PLA_IDR, 8, sa.sa_data); - else - ret = pla_ocp_read(tp, PLA_BACKUP, 8, sa.sa_data); - - if (ret < 0) { - netif_err(tp, probe, dev, "ether addr fail\n"); - } else if (!is_valid_ether_addr(sa.sa_data)) { - netif_warn(tp, probe, dev, "Invalid ether addr\n"); - eth_hw_addr_random(dev); - memcpy(sa.sa_data, dev->dev_addr, ETH_ALEN); - rtl8152_set_mac_address(dev, &sa); - } else { - if (tp->version == RTL_VER_01) - memcpy(dev->dev_addr, sa.sa_data, ETH_ALEN); - else - ret = rtl8152_set_mac_address(dev, &sa); - -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13) - memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); -#endif - } - - return ret; -} - -static inline struct net_device_stats *rtl8152_get_stats(struct net_device *dev) -{ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) - struct rtl8152 *tp = netdev_priv(dev); - - return (struct net_device_stats *)&tp->stats; -#else - return &dev->stats; -#endif -} - -static void read_bulk_callback(struct urb *urb) -{ - struct net_device *netdev; - int status = urb->status; - struct rx_agg *agg; - struct r8152 *tp; - int result; - - agg = urb->context; - if (!agg) - return; - - tp = agg->context; - if (!tp) - return; - - if (test_bit(RTL8152_UNPLUG, &tp->flags)) - return; - - if (!test_bit(WORK_ENABLE, &tp->flags)) - return; - - netdev = tp->netdev; - - /* When link down, the driver would cancel all bulks. */ - /* This avoid the re-submitting bulk */ - if (!netif_carrier_ok(netdev)) - return; - - usb_mark_last_busy(tp->udev); - - switch (status) { - case 0: - if (urb->actual_length < ETH_ZLEN) - break; - - spin_lock(&tp->rx_lock); - list_add_tail(&agg->list, &tp->rx_done); - spin_unlock(&tp->rx_lock); - tasklet_schedule(&tp->tl); - return; - case -ESHUTDOWN: - set_bit(RTL8152_UNPLUG, &tp->flags); - netif_device_detach(tp->netdev); - return; - case -ENOENT: - return; /* the urb is in unlink state */ - case -ETIME: - if (net_ratelimit()) - netif_warn(tp, rx_err, netdev, - "maybe reset is needed?\n"); - break; - default: - if (net_ratelimit()) - netif_warn(tp, rx_err, netdev, - "Rx status %d\n", status); - break; - } - - result = r8152_submit_rx(tp, agg, GFP_ATOMIC); - if (result == -ENODEV) { - netif_device_detach(tp->netdev); - } else if (result) { - spin_lock(&tp->rx_lock); - list_add_tail(&agg->list, &tp->rx_done); - spin_unlock(&tp->rx_lock); - tasklet_schedule(&tp->tl); - } -} - -static void write_bulk_callback(struct urb *urb) -{ - struct net_device_stats *stats; - struct net_device *netdev; - struct tx_agg *agg; - struct r8152 *tp; - int status = urb->status; - - agg = urb->context; - if (!agg) - return; - - tp = agg->context; - if (!tp) - return; - - netdev = tp->netdev; - stats = rtl8152_get_stats(netdev); - if (status) { - if (net_ratelimit()) - netif_warn(tp, tx_err, netdev, - "Tx status %d\n", status); - stats->tx_errors += agg->skb_num; - } else { - stats->tx_packets += agg->skb_num; - stats->tx_bytes += agg->skb_len; - } - - spin_lock(&tp->tx_lock); - list_add_tail(&agg->list, &tp->tx_free); - spin_unlock(&tp->tx_lock); - - usb_autopm_put_interface_async(tp->intf); - - if (!netif_carrier_ok(netdev)) - return; - - if (!test_bit(WORK_ENABLE, &tp->flags)) - return; - - if (test_bit(RTL8152_UNPLUG, &tp->flags)) - return; - - if (!skb_queue_empty(&tp->tx_queue)) - tasklet_schedule(&tp->tl); -} - -static void intr_callback(struct urb *urb) -{ - struct r8152 *tp; - __le16 *d; - int status = urb->status; - int res; - - tp = urb->context; - if (!tp) - return; - - if (!test_bit(WORK_ENABLE, &tp->flags)) - return; - - if (test_bit(RTL8152_UNPLUG, &tp->flags)) - return; - - switch (status) { - case 0: /* success */ - break; - case -ECONNRESET: /* unlink */ - case -ESHUTDOWN: - netif_device_detach(tp->netdev); - case -ENOENT: - return; - case -EOVERFLOW: - netif_info(tp, intr, tp->netdev, "intr status -EOVERFLOW\n"); - goto resubmit; - /* -EPIPE: should clear the halt */ - default: - netif_info(tp, intr, tp->netdev, "intr status %d\n", status); - goto resubmit; - } - - d = urb->transfer_buffer; - if (INTR_LINK & __le16_to_cpu(d[0])) { - if (!(tp->speed & LINK_STATUS)) { - set_bit(RTL8152_LINK_CHG, &tp->flags); - schedule_delayed_work(&tp->schedule, 0); - } - } else { - if (tp->speed & LINK_STATUS) { - set_bit(RTL8152_LINK_CHG, &tp->flags); - schedule_delayed_work(&tp->schedule, 0); - } - } - -resubmit: - res = usb_submit_urb(urb, GFP_ATOMIC); - if (res == -ENODEV) - netif_device_detach(tp->netdev); - else if (res) - netif_err(tp, intr, tp->netdev, - "can't resubmit intr, status %d\n", res); -} - -static inline void *rx_agg_align(void *data) -{ - return (void *)ALIGN((uintptr_t)data, RX_ALIGN); -} - -static inline void *tx_agg_align(void *data) -{ - return (void *)ALIGN((uintptr_t)data, TX_ALIGN); -} - -static void free_all_mem(struct r8152 *tp) -{ - int i; - - for (i = 0; i < RTL8152_MAX_RX; i++) { - usb_free_urb(tp->rx_info[i].urb); - tp->rx_info[i].urb = NULL; - - kfree(tp->rx_info[i].buffer); - tp->rx_info[i].buffer = NULL; - tp->rx_info[i].head = NULL; - } - - for (i = 0; i < RTL8152_MAX_TX; i++) { - usb_free_urb(tp->tx_info[i].urb); - tp->tx_info[i].urb = NULL; - - kfree(tp->tx_info[i].buffer); - tp->tx_info[i].buffer = NULL; - tp->tx_info[i].head = NULL; - } - - usb_free_urb(tp->intr_urb); - tp->intr_urb = NULL; - - kfree(tp->intr_buff); - tp->intr_buff = NULL; -} - -static int alloc_all_mem(struct r8152 *tp) -{ - struct net_device *netdev = tp->netdev; - struct usb_interface *intf = tp->intf; - struct usb_host_interface *alt = intf->cur_altsetting; - struct usb_host_endpoint *ep_intr = alt->endpoint + 2; - struct urb *urb; - int node, i; - u8 *buf; - - node = netdev->dev.parent ? dev_to_node(netdev->dev.parent) : -1; - - spin_lock_init(&tp->rx_lock); - spin_lock_init(&tp->tx_lock); - INIT_LIST_HEAD(&tp->rx_done); - INIT_LIST_HEAD(&tp->tx_free); - skb_queue_head_init(&tp->tx_queue); - - for (i = 0; i < RTL8152_MAX_RX; i++) { - buf = kmalloc_node(rx_buf_sz, GFP_KERNEL, node); - if (!buf) - goto err1; - - if (buf != rx_agg_align(buf)) { - kfree(buf); - buf = kmalloc_node(rx_buf_sz + RX_ALIGN, GFP_KERNEL, - node); - if (!buf) - goto err1; - } - - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - kfree(buf); - goto err1; - } - - INIT_LIST_HEAD(&tp->rx_info[i].list); - tp->rx_info[i].context = tp; - tp->rx_info[i].urb = urb; - tp->rx_info[i].buffer = buf; - tp->rx_info[i].head = rx_agg_align(buf); - } - - for (i = 0; i < RTL8152_MAX_TX; i++) { - buf = kmalloc_node(rx_buf_sz, GFP_KERNEL, node); - if (!buf) - goto err1; - - if (buf != tx_agg_align(buf)) { - kfree(buf); - buf = kmalloc_node(rx_buf_sz + TX_ALIGN, GFP_KERNEL, - node); - if (!buf) - goto err1; - } - - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - kfree(buf); - goto err1; - } - - INIT_LIST_HEAD(&tp->tx_info[i].list); - tp->tx_info[i].context = tp; - tp->tx_info[i].urb = urb; - tp->tx_info[i].buffer = buf; - tp->tx_info[i].head = tx_agg_align(buf); - - list_add_tail(&tp->tx_info[i].list, &tp->tx_free); - } - - tp->intr_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!tp->intr_urb) - goto err1; - - tp->intr_buff = kmalloc(INTBUFSIZE, GFP_KERNEL); - if (!tp->intr_buff) - goto err1; - - tp->intr_interval = (int)ep_intr->desc.bInterval; - usb_fill_int_urb(tp->intr_urb, tp->udev, usb_rcvintpipe(tp->udev, 3), - tp->intr_buff, INTBUFSIZE, intr_callback, - tp, tp->intr_interval); - - return 0; - -err1: - free_all_mem(tp); - return -ENOMEM; -} - -static struct tx_agg *r8152_get_tx_agg(struct r8152 *tp) -{ - struct tx_agg *agg = NULL; - unsigned long flags; - - if (list_empty(&tp->tx_free)) - return NULL; - - spin_lock_irqsave(&tp->tx_lock, flags); - if (!list_empty(&tp->tx_free)) { - struct list_head *cursor; - - cursor = tp->tx_free.next; - list_del_init(cursor); - agg = list_entry(cursor, struct tx_agg, list); - } - spin_unlock_irqrestore(&tp->tx_lock, flags); - - return agg; -} - -static inline __be16 get_protocol(struct sk_buff *skb) -{ - __be16 protocol; - - if (skb->protocol == htons(ETH_P_8021Q)) - protocol = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto; - else - protocol = skb->protocol; - - return protocol; -} - -/* r8152_csum_workaround() - * The hw limites the value the transport offset. When the offset is out of the - * range, calculate the checksum by sw. - */ -static void r8152_csum_workaround(struct r8152 *tp, struct sk_buff *skb, - struct sk_buff_head *list) -{ - if (skb_shinfo(skb)->gso_size) { - netdev_features_t features = tp->netdev->features; - struct sk_buff_head seg_list; - struct sk_buff *segs, *nskb; - - features &= ~(NETIF_F_SG | NETIF_F_IPV6_CSUM | NETIF_F_TSO6); - segs = skb_gso_segment(skb, features); - if (IS_ERR(segs) || !segs) - goto drop; - - __skb_queue_head_init(&seg_list); - - do { - nskb = segs; - segs = segs->next; - nskb->next = NULL; - __skb_queue_tail(&seg_list, nskb); - } while (segs); - - skb_queue_splice(&seg_list, list); - dev_kfree_skb(skb); - } else if (skb->ip_summed == CHECKSUM_PARTIAL) { - if (skb_checksum_help(skb) < 0) - goto drop; - - __skb_queue_head(list, skb); - } else { - struct net_device_stats *stats; - -drop: - stats = rtl8152_get_stats(tp->netdev); - stats->tx_dropped++; - dev_kfree_skb(skb); - } -} - -/* msdn_giant_send_check() - * According to the document of microsoft, the TCP Pseudo Header excludes the - * packet length for IPv6 TCP large packets. - */ -static int msdn_giant_send_check(struct sk_buff *skb) -{ - const struct ipv6hdr *ipv6h; - struct tcphdr *th; - int ret; - - ret = skb_cow_head(skb, 0); - if (ret) - return ret; - - ipv6h = ipv6_hdr(skb); - th = tcp_hdr(skb); - - th->check = 0; - //th->check = ~tcp_v6_check(0, &ipv6h->saddr, &ipv6h->daddr, 0); - { - int i; - for(i=0;i<100;i++) - printk("msdn_giant_send_check ,this should not happen!!"); - } - - return ret; -} - -static int r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, - struct sk_buff *skb, u32 len, u32 transport_offset) -{ - u32 mss = skb_shinfo(skb)->gso_size; - u32 opts1, opts2 = 0; - int ret = TX_CSUM_SUCCESS; - - WARN_ON_ONCE(len > TX_LEN_MAX); - - opts1 = len | TX_FS | TX_LS; - - if (mss) { - if (transport_offset > GTTCPHO_MAX) { - netif_warn(tp, tx_err, tp->netdev, - "Invalid transport offset 0x%x for TSO\n", - transport_offset); - ret = TX_CSUM_TSO; - goto unavailable; - } - - switch (get_protocol(skb)) { - case htons(ETH_P_IP): - opts1 |= GTSENDV4; - break; - - case htons(ETH_P_IPV6): - if (msdn_giant_send_check(skb)) { - ret = TX_CSUM_TSO; - goto unavailable; - } - opts1 |= GTSENDV6; - break; - - default: - WARN_ON_ONCE(1); - break; - } - - opts1 |= transport_offset << GTTCPHO_SHIFT; - opts2 |= min(mss, MSS_MAX) << MSS_SHIFT; - } else if (skb->ip_summed == CHECKSUM_PARTIAL) { - u8 ip_protocol; - - if (transport_offset > TCPHO_MAX) { - netif_warn(tp, tx_err, tp->netdev, - "Invalid transport offset 0x%x\n", - transport_offset); - ret = TX_CSUM_NONE; - goto unavailable; - } - - switch (get_protocol(skb)) { - case htons(ETH_P_IP): - opts2 |= IPV4_CS; - ip_protocol = ip_hdr(skb)->protocol; - break; - - case htons(ETH_P_IPV6): - opts2 |= IPV6_CS; - ip_protocol = ipv6_hdr(skb)->nexthdr; - break; - - default: - ip_protocol = IPPROTO_RAW; - break; - } - - if (ip_protocol == IPPROTO_TCP) - opts2 |= TCP_CS; - else if (ip_protocol == IPPROTO_UDP) - opts2 |= UDP_CS; - else - WARN_ON_ONCE(1); - - opts2 |= transport_offset << TCPHO_SHIFT; - } - - desc->opts2 = cpu_to_le32(opts2); - desc->opts1 = cpu_to_le32(opts1); - -unavailable: - return ret; -} - -static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) -{ - struct sk_buff_head skb_head, *tx_queue = &tp->tx_queue; - int remain, ret; - u8 *tx_data; - - __skb_queue_head_init(&skb_head); - spin_lock(&tx_queue->lock); - skb_queue_splice_init(tx_queue, &skb_head); - spin_unlock(&tx_queue->lock); - - tx_data = agg->head; - agg->skb_num = 0; - agg->skb_len = 0; - remain = rx_buf_sz; - - while (remain >= ETH_ZLEN + sizeof(struct tx_desc)) { - struct tx_desc *tx_desc; - struct sk_buff *skb; - unsigned int len; - u32 offset; - - skb = __skb_dequeue(&skb_head); - if (!skb) - break; - - len = skb->len + sizeof(*tx_desc); - - if (len > remain) { - __skb_queue_head(&skb_head, skb); - break; - } - - tx_data = tx_agg_align(tx_data); - tx_desc = (struct tx_desc *)tx_data; - - offset = (u32)skb_transport_offset(skb); - - if (r8152_tx_csum(tp, tx_desc, skb, skb->len, offset)) { - r8152_csum_workaround(tp, skb, &skb_head); - continue; - } - - tx_data += sizeof(*tx_desc); - - len = skb->len; - if (skb_copy_bits(skb, 0, tx_data, len) < 0) { - struct net_device_stats *stats = &tp->netdev->stats; - - stats->tx_dropped++; - dev_kfree_skb_any(skb); - tx_data -= sizeof(*tx_desc); - continue; - } - - tx_data += len; - agg->skb_len += len; - agg->skb_num++; - - dev_kfree_skb_any(skb); - - remain = rx_buf_sz - (int)(tx_agg_align(tx_data) - agg->head); - } - - if (!skb_queue_empty(&skb_head)) { - spin_lock(&tx_queue->lock); - skb_queue_splice(&skb_head, tx_queue); - spin_unlock(&tx_queue->lock); - } - - netif_tx_lock(tp->netdev); - - if (netif_queue_stopped(tp->netdev) && - skb_queue_len(&tp->tx_queue) < tp->tx_qlen) - netif_wake_queue(tp->netdev); - - netif_tx_unlock(tp->netdev); - - ret = usb_autopm_get_interface_async(tp->intf); - if (ret < 0) - goto out_tx_fill; - - usb_fill_bulk_urb(agg->urb, tp->udev, usb_sndbulkpipe(tp->udev, 2), - agg->head, (int)(tx_data - (u8 *)agg->head), - (usb_complete_t)write_bulk_callback, agg); - - ret = usb_submit_urb(agg->urb, GFP_ATOMIC); - if (ret < 0) - usb_autopm_put_interface_async(tp->intf); - -out_tx_fill: - return ret; -} - -static u8 r8152_rx_csum(struct r8152 *tp, struct rx_desc *rx_desc) -{ - u8 checksum = CHECKSUM_NONE; - u32 opts2, opts3; - - if (tp->version == RTL_VER_01) - goto return_result; - - opts2 = le32_to_cpu(rx_desc->opts2); - opts3 = le32_to_cpu(rx_desc->opts3); - - if (opts2 & RD_IPV4_CS) { - if (opts3 & IPF) - checksum = CHECKSUM_NONE; - else if ((opts2 & RD_UDP_CS) && (opts3 & UDPF)) - checksum = CHECKSUM_NONE; - else if ((opts2 & RD_TCP_CS) && (opts3 & TCPF)) - checksum = CHECKSUM_NONE; - else - checksum = CHECKSUM_UNNECESSARY; - } else if (RD_IPV6_CS) { - if ((opts2 & RD_UDP_CS) && !(opts3 & UDPF)) - checksum = CHECKSUM_UNNECESSARY; - else if ((opts2 & RD_TCP_CS) && !(opts3 & TCPF)) - checksum = CHECKSUM_UNNECESSARY; - } - -return_result: - return checksum; -} - -static void rx_bottom(struct r8152 *tp) -{ - unsigned long flags; - struct list_head *cursor, *next, rx_queue; - - if (list_empty(&tp->rx_done)) - return; - - INIT_LIST_HEAD(&rx_queue); - spin_lock_irqsave(&tp->rx_lock, flags); - list_splice_init(&tp->rx_done, &rx_queue); - spin_unlock_irqrestore(&tp->rx_lock, flags); - - list_for_each_safe(cursor, next, &rx_queue) { - struct rx_desc *rx_desc; - struct rx_agg *agg; - int len_used = 0; - struct urb *urb; - u8 *rx_data; - int ret; - - list_del_init(cursor); - - agg = list_entry(cursor, struct rx_agg, list); - urb = agg->urb; - if (urb->actual_length < ETH_ZLEN) - goto submit; - - rx_desc = agg->head; - rx_data = agg->head; - len_used += sizeof(struct rx_desc); - - while (urb->actual_length > len_used) { - struct net_device *netdev = tp->netdev; - struct net_device_stats *stats; - unsigned int pkt_len; - struct sk_buff *skb; - - pkt_len = le32_to_cpu(rx_desc->opts1) & RX_LEN_MASK; - if (pkt_len < ETH_ZLEN) - break; - - len_used += pkt_len; - if (urb->actual_length < len_used) - break; - - stats = rtl8152_get_stats(netdev); - - pkt_len -= CRC_SIZE; - rx_data += sizeof(struct rx_desc); - - skb = netdev_alloc_skb_ip_align(netdev, pkt_len); - if (!skb) { - stats->rx_dropped++; - goto find_next_rx; - } - - skb->ip_summed = r8152_rx_csum(tp, rx_desc); - memcpy(skb->data, rx_data, pkt_len); - skb_put(skb, pkt_len); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) - skb->dev = netdev; -#endif - skb->protocol = eth_type_trans(skb, netdev); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) - netdev->last_rx = jiffies; -#endif - netif_receive_skb(skb); - stats->rx_packets++; - stats->rx_bytes += pkt_len; - -find_next_rx: - rx_data = rx_agg_align(rx_data + pkt_len + CRC_SIZE); - rx_desc = (struct rx_desc *)rx_data; - len_used = (int)(rx_data - (u8 *)agg->head); - len_used += sizeof(struct rx_desc); - } - -submit: - ret = r8152_submit_rx(tp, agg, GFP_ATOMIC); - if (ret && ret != -ENODEV) { - spin_lock_irqsave(&tp->rx_lock, flags); - list_add_tail(&agg->list, &tp->rx_done); - spin_unlock_irqrestore(&tp->rx_lock, flags); - tasklet_schedule(&tp->tl); - } - } -} - -static void tx_bottom(struct r8152 *tp) -{ - int res; - - do { - struct tx_agg *agg; - - if (skb_queue_empty(&tp->tx_queue)) - break; - - agg = r8152_get_tx_agg(tp); - if (!agg) - break; - - res = r8152_tx_agg_fill(tp, agg); - if (res) { - struct net_device *netdev = tp->netdev; - - if (res == -ENODEV) { - netif_device_detach(netdev); - } else { - struct net_device_stats *stats; - unsigned long flags; - - stats = rtl8152_get_stats(netdev); - netif_warn(tp, tx_err, netdev, - "failed tx_urb %d\n", res); - stats->tx_dropped += agg->skb_num; - - spin_lock_irqsave(&tp->tx_lock, flags); - list_add_tail(&agg->list, &tp->tx_free); - spin_unlock_irqrestore(&tp->tx_lock, flags); - } - } - } while (res == 0); -} - -static void bottom_half(unsigned long data) -{ - struct r8152 *tp; - - tp = (struct r8152 *)data; - - if (test_bit(RTL8152_UNPLUG, &tp->flags)) - return; - - if (!test_bit(WORK_ENABLE, &tp->flags)) - return; - - /* When link down, the driver would cancel all bulks. */ - /* This avoid the re-submitting bulk */ - if (!netif_carrier_ok(tp->netdev)) - return; - - rx_bottom(tp); - tx_bottom(tp); -} - -static -int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags) -{ - usb_fill_bulk_urb(agg->urb, tp->udev, usb_rcvbulkpipe(tp->udev, 1), - agg->head, rx_buf_sz, - (usb_complete_t)read_bulk_callback, agg); - - return usb_submit_urb(agg->urb, mem_flags); -} - -static void rtl_drop_queued_tx(struct r8152 *tp) -{ - struct net_device_stats *stats = rtl8152_get_stats(tp->netdev); - struct sk_buff_head skb_head, *tx_queue = &tp->tx_queue; - struct sk_buff *skb; - - if (skb_queue_empty(tx_queue)) - return; - - __skb_queue_head_init(&skb_head); - spin_lock_bh(&tx_queue->lock); - skb_queue_splice_init(tx_queue, &skb_head); - spin_unlock_bh(&tx_queue->lock); - - while ((skb = __skb_dequeue(&skb_head))) { - dev_kfree_skb(skb); - stats->tx_dropped++; - } -} - -static void rtl8152_tx_timeout(struct net_device *netdev) -{ - struct r8152 *tp = netdev_priv(netdev); - int i; - - netif_warn(tp, tx_err, netdev, "Tx timeout\n"); - for (i = 0; i < RTL8152_MAX_TX; i++) - usb_unlink_urb(tp->tx_info[i].urb); -} - -static void rtl8152_set_rx_mode(struct net_device *netdev) -{ - struct r8152 *tp = netdev_priv(netdev); - u32 mc_filter[2]; /* Multicast hash filter */ - __le32 tmp[2]; - u32 ocp_data; - - if (in_atomic()) { - if (tp->speed & LINK_STATUS) { - set_bit(RTL8152_SET_RX_MODE, &tp->flags); - schedule_delayed_work(&tp->schedule, 0); - } - return; - } - - clear_bit(RTL8152_SET_RX_MODE, &tp->flags); - netif_stop_queue(netdev); - ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); - ocp_data &= ~RCR_ACPT_ALL; - ocp_data |= RCR_AB | RCR_APM; - - if (netdev->flags & IFF_PROMISC) { - /* Unconditionally log net taps. */ - netif_notice(tp, link, netdev, "Promiscuous mode enabled\n"); - ocp_data |= RCR_AM | RCR_AAP; - mc_filter[1] = 0xffffffff; - mc_filter[0] = 0xffffffff; - } else if ((netdev_mc_count(netdev) > multicast_filter_limit) || - (netdev->flags & IFF_ALLMULTI)) { - /* Too many to filter perfectly -- accept all multicasts. */ - ocp_data |= RCR_AM; - mc_filter[1] = 0xffffffff; - mc_filter[0] = 0xffffffff; - } else { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) - struct dev_mc_list *mclist; - unsigned int i; - - mc_filter[1] = mc_filter[0] = 0; - for (i = 0, mclist = netdev->mc_list; mclist && i < netdev->mc_count; - i++, mclist = mclist->next) { - int bit_nr; - bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; - mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); - ocp_data |= RCR_AM; - } -#else - struct netdev_hw_addr *ha; - - mc_filter[1] = 0; - mc_filter[0] = 0; - netdev_for_each_mc_addr(ha, netdev) { - int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26; - - mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); - ocp_data |= RCR_AM; - } -#endif - } - - tmp[0] = __cpu_to_le32(swab32(mc_filter[1])); - tmp[1] = __cpu_to_le32(swab32(mc_filter[0])); - - pla_ocp_write(tp, PLA_MAR, BYTE_EN_DWORD, sizeof(tmp), tmp); - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); - netif_wake_queue(netdev); -} - -static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb, - struct net_device *netdev) -{ - struct r8152 *tp = netdev_priv(netdev); - - skb_tx_timestamp(skb); - - skb_queue_tail(&tp->tx_queue, skb); - - if (!list_empty(&tp->tx_free)) { - if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { - set_bit(SCHEDULE_TASKLET, &tp->flags); - schedule_delayed_work(&tp->schedule, 0); - } else { - usb_mark_last_busy(tp->udev); - tasklet_schedule(&tp->tl); - } - } else if (skb_queue_len(&tp->tx_queue) > tp->tx_qlen) { - netif_stop_queue(netdev); - } - - return NETDEV_TX_OK; -} - -static void r8152b_reset_packet_filter(struct r8152 *tp) -{ - u32 ocp_data; - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_FMC); - ocp_data &= ~FMC_FCR_MCU_EN; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_FMC, ocp_data); - ocp_data |= FMC_FCR_MCU_EN; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_FMC, ocp_data); -} - -static void rtl8152_nic_reset(struct r8152 *tp) -{ - int i; - - ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, CR_RST); - - for (i = 0; i < 1000; i++) { - if (!(ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CR) & CR_RST)) - break; - usleep_range(100, 400); - } -} - -static void set_tx_qlen(struct r8152 *tp) -{ - struct net_device *netdev = tp->netdev; - - tp->tx_qlen = rx_buf_sz / (netdev->mtu + VLAN_ETH_HLEN + VLAN_HLEN + - sizeof(struct tx_desc)); -} - -static inline u8 rtl8152_get_speed(struct r8152 *tp) -{ - return ocp_read_byte(tp, MCU_TYPE_PLA, PLA_PHYSTATUS); -} - -static void rtl_set_eee_plus(struct r8152 *tp) -{ - u32 ocp_data; - u8 speed; - - speed = rtl8152_get_speed(tp); - if (speed & _10bps) { - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR); - ocp_data |= EEEP_CR_EEEP_TX; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR, ocp_data); - } else { - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR); - ocp_data &= ~EEEP_CR_EEEP_TX; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR, ocp_data); - } -} - -static void rxdy_gated_en(struct r8152 *tp, bool enable) -{ - u32 ocp_data; - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1); - if (enable) - ocp_data |= RXDY_GATED_EN; - else - ocp_data &= ~RXDY_GATED_EN; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data); -} - -static int rtl_enable(struct r8152 *tp) -{ - u32 ocp_data; - int i, ret; - - r8152b_reset_packet_filter(tp); - - ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CR); - ocp_data |= CR_RE | CR_TE; - ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, ocp_data); - - rxdy_gated_en(tp, false); - - INIT_LIST_HEAD(&tp->rx_done); - ret = 0; - for (i = 0; i < RTL8152_MAX_RX; i++) { - INIT_LIST_HEAD(&tp->rx_info[i].list); - ret |= r8152_submit_rx(tp, &tp->rx_info[i], GFP_KERNEL); - } - - return ret; -} - -static int rtl8152_enable(struct r8152 *tp) -{ - if (test_bit(RTL8152_UNPLUG, &tp->flags)) - return -ENODEV; - - set_tx_qlen(tp); - rtl_set_eee_plus(tp); - - return rtl_enable(tp); -} - -static void r8153_set_rx_agg(struct r8152 *tp) -{ - u8 speed; - - speed = rtl8152_get_speed(tp); - if (speed & _1000bps) { - if (tp->udev->speed == USB_SPEED_SUPER) { - ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, - RX_THR_SUPPER); - ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_EARLY_AGG, - EARLY_AGG_SUPER); - } else { - ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, - RX_THR_HIGH); - ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_EARLY_AGG, - EARLY_AGG_HIGH); - } - } else { - ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, RX_THR_SLOW); - ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_EARLY_AGG, - EARLY_AGG_SLOW); - } -} - -static int rtl8153_enable(struct r8152 *tp) -{ - if (test_bit(RTL8152_UNPLUG, &tp->flags)) - return -ENODEV; - - set_tx_qlen(tp); - rtl_set_eee_plus(tp); - r8153_set_rx_agg(tp); - - return rtl_enable(tp); -} - -static void rtl_disable(struct r8152 *tp) -{ - u32 ocp_data; - int i; - - if (test_bit(RTL8152_UNPLUG, &tp->flags)) { - rtl_drop_queued_tx(tp); - return; - } - - ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); - ocp_data &= ~RCR_ACPT_ALL; - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); - - rtl_drop_queued_tx(tp); - - for (i = 0; i < RTL8152_MAX_TX; i++) - usb_kill_urb(tp->tx_info[i].urb); - - rxdy_gated_en(tp, true); - - for (i = 0; i < 1000; i++) { - ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); - if ((ocp_data & FIFO_EMPTY) == FIFO_EMPTY) - break; - usleep_range(1000, 2000); - } - - for (i = 0; i < 1000; i++) { - if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR0) & TCR0_TX_EMPTY) - break; - usleep_range(1000, 2000); - } - - for (i = 0; i < RTL8152_MAX_RX; i++) - usb_kill_urb(tp->rx_info[i].urb); - - rtl8152_nic_reset(tp); -} - -static void r8152_power_cut_en(struct r8152 *tp, bool enable) -{ - u32 ocp_data; - - ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CTRL); - if (enable) - ocp_data |= POWER_CUT; - else - ocp_data &= ~POWER_CUT; - ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CTRL, ocp_data); - - ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS); - ocp_data &= ~RESUME_INDICATE; - ocp_write_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS, ocp_data); -} - -#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST) - -static u32 __rtl_get_wol(struct r8152 *tp) -{ - u32 ocp_data; - u32 wolopts = 0; - - ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CONFIG5); - if (!(ocp_data & LAN_WAKE_EN)) - return 0; - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG34); - if (ocp_data & LINK_ON_WAKE_EN) - wolopts |= WAKE_PHY; - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG5); - if (ocp_data & UWF_EN) - wolopts |= WAKE_UCAST; - if (ocp_data & BWF_EN) - wolopts |= WAKE_BCAST; - if (ocp_data & MWF_EN) - wolopts |= WAKE_MCAST; - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL); - if (ocp_data & MAGIC_EN) - wolopts |= WAKE_MAGIC; - - return wolopts; -} - -static void __rtl_set_wol(struct r8152 *tp, u32 wolopts) -{ - u32 ocp_data; - - ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG); - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG34); - ocp_data &= ~LINK_ON_WAKE_EN; - if (wolopts & WAKE_PHY) - ocp_data |= LINK_ON_WAKE_EN; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG34, ocp_data); - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG5); - ocp_data &= ~(UWF_EN | BWF_EN | MWF_EN | LAN_WAKE_EN); - if (wolopts & WAKE_UCAST) - ocp_data |= UWF_EN; - if (wolopts & WAKE_BCAST) - ocp_data |= BWF_EN; - if (wolopts & WAKE_MCAST) - ocp_data |= MWF_EN; - if (wolopts & WAKE_ANY) - ocp_data |= LAN_WAKE_EN; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG5, ocp_data); - - ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML); - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL); - ocp_data &= ~MAGIC_EN; - if (wolopts & WAKE_MAGIC) - ocp_data |= MAGIC_EN; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL, ocp_data); - - if (wolopts & WAKE_ANY) - device_set_wakeup_enable(&tp->udev->dev, true); - else - device_set_wakeup_enable(&tp->udev->dev, false); -} - -static void rtl_runtime_suspend_enable(struct r8152 *tp, bool enable) -{ - if (enable) { - u32 ocp_data; - - __rtl_set_wol(tp, WAKE_ANY); - - ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG); - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG34); - ocp_data |= LINK_OFF_WAKE_EN; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG34, ocp_data); - - ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML); - } else { - __rtl_set_wol(tp, tp->saved_wolopts); - } -} - -static void rtl_phy_reset(struct r8152 *tp) -{ - u16 data; - int i; - - clear_bit(PHY_RESET, &tp->flags); - - data = r8152_mdio_read(tp, MII_BMCR); - - /* don't reset again before the previous one complete */ - if (data & BMCR_RESET) - return; - - data |= BMCR_RESET; - r8152_mdio_write(tp, MII_BMCR, data); - - for (i = 0; i < 50; i++) { - msleep(20); - if ((r8152_mdio_read(tp, MII_BMCR) & BMCR_RESET) == 0) - break; - } -} - -static void rtl_clear_bp(struct r8152 *tp) -{ - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_0, 0); - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_2, 0); - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_4, 0); - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_6, 0); - ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_0, 0); - ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_2, 0); - ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_4, 0); - ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_6, 0); - usleep_range(3000, 6000); - ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_BA, 0); - ocp_write_word(tp, MCU_TYPE_USB, USB_BP_BA, 0); -} - -static void r8153_clear_bp(struct r8152 *tp) -{ - if (tp->version == RTL_VER_05) { - u32 ocp_data; - - ocp_data = ocp_read_word(tp, MCU_TYPE_USB, 0xcfca); - ocp_data &= ~0x4000; - ocp_write_word(tp, MCU_TYPE_USB, 0xcfca, ocp_data); - } - - if (tp->version == RTL_VER_04 || tp->version == RTL_VER_05) { - int i; - - for (i = 0; i < 104; i++) { - usleep_range(1000, 2000); - if (!(ocp_read_byte(tp, MCU_TYPE_USB, 0xe404) & 1)) - break; - } - } - - ocp_write_byte(tp, MCU_TYPE_PLA, PLA_BP_EN, 0); - ocp_write_byte(tp, MCU_TYPE_USB, USB_BP_EN, 0); - rtl_clear_bp(tp); -} - -static void r8153_teredo_off(struct r8152 *tp) -{ - u32 ocp_data; - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG); - ocp_data &= ~(TEREDO_SEL | TEREDO_RS_EVENT_MASK | OOB_TEREDO_EN); - ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data); - - ocp_write_word(tp, MCU_TYPE_PLA, PLA_WDT6_CTRL, WDT6_SET_MODE); - ocp_write_word(tp, MCU_TYPE_PLA, PLA_REALWOW_TIMER, 0); - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TEREDO_TIMER, 0); -} - -static void r8152b_firmware(struct r8152 *tp) -{ - rtl_clear_bp(tp); - - if (tp->version == RTL_VER_01) { - int i; - static u8 pla_patch_a[] = { - 0x08, 0xe0, 0x40, 0xe0, - 0x78, 0xe0, 0x85, 0xe0, - 0x5d, 0xe1, 0xa1, 0xe1, - 0xa3, 0xe1, 0xab, 0xe1, - 0x31, 0xc3, 0x60, 0x72, - 0xa0, 0x49, 0x10, 0xf0, - 0xa4, 0x49, 0x0e, 0xf0, - 0x2c, 0xc3, 0x62, 0x72, - 0x26, 0x70, 0x80, 0x49, - 0x05, 0xf0, 0x2f, 0x48, - 0x62, 0x9a, 0x24, 0x70, - 0x60, 0x98, 0x24, 0xc3, - 0x60, 0x99, 0x23, 0xc3, - 0x00, 0xbb, 0x2c, 0x75, - 0xdc, 0x21, 0xbc, 0x25, - 0x04, 0x13, 0x0a, 0xf0, - 0x03, 0x13, 0x08, 0xf0, - 0x02, 0x13, 0x06, 0xf0, - 0x01, 0x13, 0x04, 0xf0, - 0x08, 0x13, 0x02, 0xf0, - 0x03, 0xe0, 0xd4, 0x49, - 0x04, 0xf1, 0x14, 0xc2, - 0x12, 0xc3, 0x00, 0xbb, - 0x12, 0xc3, 0x60, 0x75, - 0xd0, 0x49, 0x05, 0xf1, - 0x50, 0x48, 0x60, 0x9d, - 0x09, 0xc6, 0x00, 0xbe, - 0xd0, 0x48, 0x60, 0x9d, - 0xf3, 0xe7, 0xc2, 0xc0, - 0x38, 0xd2, 0xc6, 0xd2, - 0x84, 0x17, 0xa2, 0x13, - 0x0c, 0x17, 0xbc, 0xc0, - 0xa2, 0xd1, 0x33, 0xc5, - 0xa0, 0x74, 0xc0, 0x49, - 0x1f, 0xf0, 0x30, 0xc5, - 0xa0, 0x73, 0x00, 0x13, - 0x04, 0xf1, 0xa2, 0x73, - 0x00, 0x13, 0x14, 0xf0, - 0x28, 0xc5, 0xa0, 0x74, - 0xc8, 0x49, 0x1b, 0xf1, - 0x26, 0xc5, 0xa0, 0x76, - 0xa2, 0x74, 0x01, 0x06, - 0x20, 0x37, 0xa0, 0x9e, - 0xa2, 0x9c, 0x1e, 0xc5, - 0xa2, 0x73, 0x23, 0x40, - 0x10, 0xf8, 0x04, 0xf3, - 0xa0, 0x73, 0x33, 0x40, - 0x0c, 0xf8, 0x15, 0xc5, - 0xa0, 0x74, 0x41, 0x48, - 0xa0, 0x9c, 0x14, 0xc5, - 0xa0, 0x76, 0x62, 0x48, - 0xe0, 0x48, 0xa0, 0x9e, - 0x10, 0xc6, 0x00, 0xbe, - 0x0a, 0xc5, 0xa0, 0x74, - 0x48, 0x48, 0xa0, 0x9c, - 0x0b, 0xc5, 0x20, 0x1e, - 0xa0, 0x9e, 0xe5, 0x48, - 0xa0, 0x9e, 0xf0, 0xe7, - 0xbc, 0xc0, 0xc8, 0xd2, - 0xcc, 0xd2, 0x28, 0xe4, - 0x22, 0x02, 0xf0, 0xc0, - 0x0b, 0xc0, 0x00, 0x71, - 0x0a, 0xc0, 0x00, 0x72, - 0xa0, 0x49, 0x04, 0xf0, - 0xa4, 0x49, 0x02, 0xf0, - 0x93, 0x48, 0x04, 0xc0, - 0x00, 0xb8, 0x00, 0xe4, - 0xc2, 0xc0, 0x8c, 0x09, - 0x14, 0xc2, 0x40, 0x73, - 0xba, 0x48, 0x40, 0x9b, - 0x11, 0xc2, 0x40, 0x73, - 0xb0, 0x49, 0x17, 0xf0, - 0xbf, 0x49, 0x03, 0xf1, - 0x09, 0xc5, 0x00, 0xbd, - 0xb1, 0x49, 0x11, 0xf0, - 0xb1, 0x48, 0x40, 0x9b, - 0x02, 0xc2, 0x00, 0xba, - 0x82, 0x18, 0x00, 0xa0, - 0x1e, 0xfc, 0xbc, 0xc0, - 0xf0, 0xc0, 0xde, 0xe8, - 0x00, 0x80, 0x00, 0x60, - 0x2c, 0x75, 0xd4, 0x49, - 0x12, 0xf1, 0x29, 0xe0, - 0xf8, 0xc2, 0x46, 0x71, - 0xf7, 0xc2, 0x40, 0x73, - 0xbe, 0x49, 0x03, 0xf1, - 0xf5, 0xc7, 0x02, 0xe0, - 0xf2, 0xc7, 0x4f, 0x30, - 0x26, 0x62, 0xa1, 0x49, - 0xf0, 0xf1, 0x22, 0x72, - 0xa0, 0x49, 0xed, 0xf1, - 0x25, 0x25, 0x18, 0x1f, - 0x97, 0x30, 0x91, 0x30, - 0x36, 0x9a, 0x2c, 0x75, - 0x32, 0xc3, 0x60, 0x73, - 0xb1, 0x49, 0x0d, 0xf1, - 0xdc, 0x21, 0xbc, 0x25, - 0x27, 0xc6, 0xc0, 0x77, - 0x04, 0x13, 0x18, 0xf0, - 0x03, 0x13, 0x19, 0xf0, - 0x02, 0x13, 0x1a, 0xf0, - 0x01, 0x13, 0x1b, 0xf0, - 0xd4, 0x49, 0x03, 0xf1, - 0x1c, 0xc5, 0x00, 0xbd, - 0xcd, 0xc6, 0xc6, 0x67, - 0x2e, 0x75, 0xd7, 0x22, - 0xdd, 0x26, 0x05, 0x15, - 0x1a, 0xf0, 0x14, 0xc6, - 0x00, 0xbe, 0x13, 0xc5, - 0x00, 0xbd, 0x12, 0xc5, - 0x00, 0xbd, 0xf1, 0x49, - 0xfb, 0xf1, 0xef, 0xe7, - 0xf4, 0x49, 0xfa, 0xf1, - 0xec, 0xe7, 0xf3, 0x49, - 0xf7, 0xf1, 0xe9, 0xe7, - 0xf2, 0x49, 0xf4, 0xf1, - 0xe6, 0xe7, 0xb6, 0xc0, - 0x6a, 0x14, 0xac, 0x13, - 0xd6, 0x13, 0xfa, 0x14, - 0xa0, 0xd1, 0x00, 0x00, - 0xc0, 0x75, 0xd0, 0x49, - 0x46, 0xf0, 0x26, 0x72, - 0xa7, 0x49, 0x43, 0xf0, - 0x22, 0x72, 0x25, 0x25, - 0x20, 0x1f, 0x97, 0x30, - 0x91, 0x30, 0x40, 0x73, - 0xf3, 0xc4, 0x1c, 0x40, - 0x04, 0xf0, 0xd7, 0x49, - 0x05, 0xf1, 0x37, 0xe0, - 0x53, 0x48, 0xc0, 0x9d, - 0x08, 0x02, 0x40, 0x66, - 0x64, 0x27, 0x06, 0x16, - 0x30, 0xf1, 0x46, 0x63, - 0x3b, 0x13, 0x2d, 0xf1, - 0x34, 0x9b, 0x18, 0x1b, - 0x93, 0x30, 0x2b, 0xc3, - 0x10, 0x1c, 0x2b, 0xe8, - 0x01, 0x14, 0x25, 0xf1, - 0x00, 0x1d, 0x26, 0x1a, - 0x8a, 0x30, 0x22, 0x73, - 0xb5, 0x25, 0x0e, 0x0b, - 0x00, 0x1c, 0x2c, 0xe8, - 0x1f, 0xc7, 0x27, 0x40, - 0x1a, 0xf1, 0x38, 0xe8, - 0x32, 0x1f, 0x8f, 0x30, - 0x08, 0x1b, 0x24, 0xe8, - 0x36, 0x72, 0x46, 0x77, - 0x00, 0x17, 0x0d, 0xf0, - 0x13, 0xc3, 0x1f, 0x40, - 0x03, 0xf1, 0x00, 0x1f, - 0x46, 0x9f, 0x44, 0x77, - 0x9f, 0x44, 0x5f, 0x44, - 0x17, 0xe8, 0x0a, 0xc7, - 0x27, 0x40, 0x05, 0xf1, - 0x02, 0xc3, 0x00, 0xbb, - 0x50, 0x1a, 0x06, 0x1a, - 0xff, 0xc7, 0x00, 0xbf, - 0xb8, 0xcd, 0xff, 0xff, - 0x02, 0x0c, 0x54, 0xa5, - 0xdc, 0xa5, 0x2f, 0x40, - 0x05, 0xf1, 0x00, 0x14, - 0xfa, 0xf1, 0x01, 0x1c, - 0x02, 0xe0, 0x00, 0x1c, - 0x80, 0xff, 0xb0, 0x49, - 0x04, 0xf0, 0x01, 0x0b, - 0xd3, 0xa1, 0x03, 0xe0, - 0x02, 0x0b, 0xd3, 0xa5, - 0x27, 0x31, 0x20, 0x37, - 0x02, 0x0b, 0xd3, 0xa5, - 0x27, 0x31, 0x20, 0x37, - 0x00, 0x13, 0xfb, 0xf1, - 0x80, 0xff, 0x22, 0x73, - 0xb5, 0x25, 0x18, 0x1e, - 0xde, 0x30, 0xd9, 0x30, - 0x64, 0x72, 0x11, 0x1e, - 0x68, 0x23, 0x16, 0x31, - 0x80, 0xff, 0xd4, 0x49, - 0x28, 0xf0, 0x02, 0xb4, - 0x2a, 0xc4, 0x00, 0x1d, - 0x2e, 0xe8, 0xe0, 0x73, - 0xb9, 0x21, 0xbd, 0x25, - 0x04, 0x13, 0x02, 0xf0, - 0x1a, 0xe0, 0x22, 0xc4, - 0x23, 0xc3, 0x2f, 0xe8, - 0x23, 0xc3, 0x2d, 0xe8, - 0x00, 0x1d, 0x21, 0xe8, - 0xe2, 0x73, 0xbb, 0x49, - 0xfc, 0xf0, 0xe0, 0x73, - 0xb7, 0x48, 0x03, 0xb4, - 0x81, 0x1d, 0x19, 0xe8, - 0x40, 0x1a, 0x84, 0x1d, - 0x16, 0xe8, 0x12, 0xc3, - 0x1e, 0xe8, 0x03, 0xb0, - 0x81, 0x1d, 0x11, 0xe8, - 0x0e, 0xc3, 0x19, 0xe8, - 0x02, 0xb0, 0x06, 0xc7, - 0x04, 0x1e, 0xe0, 0x9e, - 0x02, 0xc6, 0x00, 0xbe, - 0x22, 0x02, 0x20, 0xe4, - 0x04, 0xb8, 0x34, 0xb0, - 0x00, 0x02, 0x00, 0x03, - 0x00, 0x0e, 0x00, 0x0c, - 0x09, 0xc7, 0xe0, 0x9b, - 0xe2, 0x9a, 0xe4, 0x9c, - 0xe6, 0x8d, 0xe6, 0x76, - 0xef, 0x49, 0xfe, 0xf1, - 0x80, 0xff, 0x08, 0xea, - 0x82, 0x1d, 0xf5, 0xef, - 0x00, 0x1a, 0x88, 0x1d, - 0xf2, 0xef, 0xed, 0xc2, - 0xf0, 0xef, 0x80, 0xff, - 0x02, 0xc6, 0x00, 0xbe, - 0x46, 0x06, 0x08, 0xc2, - 0x40, 0x73, 0x3a, 0x48, - 0x40, 0x9b, 0x06, 0xff, - 0x02, 0xc6, 0x00, 0xbe, - 0x86, 0x17, 0x1e, 0xfc, - 0x36, 0xf0, 0x08, 0x1c, - 0xea, 0x8c, 0xe3, 0x64, - 0xc7, 0x49, 0x25, 0xf1, - 0xe0, 0x75, 0xff, 0x1b, - 0xeb, 0x47, 0xff, 0x1b, - 0x6b, 0x47, 0xe0, 0x9d, - 0x15, 0xc3, 0x60, 0x75, - 0xd8, 0x49, 0x04, 0xf0, - 0x81, 0x1d, 0xe2, 0x8d, - 0x05, 0xe0, 0xe2, 0x63, - 0x81, 0x1d, 0xdd, 0x47, - 0xe2, 0x8b, 0x0b, 0xc3, - 0x00, 0x1d, 0x61, 0x8d, - 0x3c, 0x03, 0x60, 0x75, - 0xd8, 0x49, 0x06, 0xf1, - 0xdf, 0x48, 0x61, 0x95, - 0x16, 0xe0, 0x4e, 0xe8, - 0x12, 0xe8, 0x21, 0xc5, - 0xa0, 0x73, 0xb0, 0x49, - 0x03, 0xf0, 0x31, 0x48, - 0xa0, 0x9b, 0x0d, 0xe0, - 0xc0, 0x49, 0x0b, 0xf1, - 0xe2, 0x63, 0x7e, 0x1d, - 0xdd, 0x46, 0xe2, 0x8b, - 0xe0, 0x75, 0x83, 0x1b, - 0xeb, 0x46, 0xfe, 0x1b, - 0x6b, 0x46, 0xe0, 0x9d, - 0xe4, 0x49, 0x11, 0xf0, - 0x10, 0x1d, 0xea, 0x8d, - 0xe3, 0x64, 0xc6, 0x49, - 0x09, 0xf1, 0x07, 0xc5, - 0xa0, 0x73, 0xb1, 0x48, - 0xa0, 0x9b, 0x02, 0xc5, - 0x00, 0xbd, 0xe6, 0x04, - 0xa0, 0xd1, 0x02, 0xc5, - 0x00, 0xbd, 0xfe, 0x04, - 0x02, 0xc5, 0x00, 0xbd, - 0x30, 0x05, 0x00, 0x00 }; - static u16 ram_code1[] = { - 0x9700, 0x7fe0, 0x4c00, 0x4007, - 0x4400, 0x4800, 0x7c1f, 0x4c00, - 0x5310, 0x6000, 0x7c07, 0x6800, - 0x673e, 0x0000, 0x0000, 0x571f, - 0x5ffb, 0xaa05, 0x5b58, 0x7d80, - 0x6100, 0x3019, 0x5b64, 0x7d80, - 0x6080, 0xa6f8, 0xdcdb, 0x0015, - 0xb915, 0xb511, 0xd16b, 0x000f, - 0xb40f, 0xd06b, 0x000d, 0xb206, - 0x7c01, 0x5800, 0x7c04, 0x5c00, - 0x3011, 0x7c01, 0x5801, 0x7c04, - 0x5c04, 0x3019, 0x30a5, 0x3127, - 0x31d5, 0x7fe0, 0x4c60, 0x7c07, - 0x6803, 0x7d00, 0x6900, 0x65a0, - 0x0000, 0x0000, 0xaf03, 0x6015, - 0x303e, 0x6017, 0x57e0, 0x580c, - 0x588c, 0x7fdd, 0x5fa2, 0x4827, - 0x7c1f, 0x4c00, 0x7c1f, 0x4c10, - 0x8400, 0x7c30, 0x6020, 0x48bf, - 0x7c1f, 0x4c00, 0x7c1f, 0x4c01, - 0x7c07, 0x6803, 0xb806, 0x7c08, - 0x6800, 0x0000, 0x0000, 0x305c, - 0x7c08, 0x6808, 0x0000, 0x0000, - 0xae06, 0x7c02, 0x5c02, 0x0000, - 0x0000, 0x3067, 0x8e05, 0x7c02, - 0x5c00, 0x0000, 0x0000, 0xad06, - 0x7c20, 0x5c20, 0x0000, 0x0000, - 0x3072, 0x8d05, 0x7c20, 0x5c00, - 0x0000, 0x0000, 0xa008, 0x7c07, - 0x6800, 0xb8db, 0x7c07, 0x6803, - 0xd9b3, 0x00d7, 0x7fe0, 0x4c80, - 0x7c08, 0x6800, 0x0000, 0x0000, - 0x7c23, 0x5c23, 0x481d, 0x7c1f, - 0x4c00, 0x7c1f, 0x4c02, 0x5310, - 0x81ff, 0x30f5, 0x7fe0, 0x4d00, - 0x4832, 0x7c1f, 0x4c00, 0x7c1f, - 0x4c10, 0x7c08, 0x6000, 0xa49e, - 0x7c07, 0x6800, 0xb89b, 0x7c07, - 0x6803, 0xd9b3, 0x00f9, 0x7fe0, - 0x4d20, 0x7e00, 0x6200, 0x3001, - 0x7fe0, 0x4dc0, 0xd09d, 0x0002, - 0xb4fe, 0x7fe0, 0x4d80, 0x7c04, - 0x6004, 0x7c07, 0x6802, 0x6728, - 0x0000, 0x0000, 0x7c08, 0x6000, - 0x486c, 0x7c1f, 0x4c00, 0x7c1f, - 0x4c01, 0x9503, 0x7e00, 0x6200, - 0x571f, 0x5fbb, 0xaa05, 0x5b58, - 0x7d80, 0x6100, 0x30c2, 0x5b64, - 0x7d80, 0x6080, 0xcdab, 0x0063, - 0xcd8d, 0x0061, 0xd96b, 0x005f, - 0xd0a0, 0x00d7, 0xcba0, 0x0003, - 0x80ec, 0x30cf, 0x30dc, 0x7fe0, - 0x4ce0, 0x4832, 0x7c1f, 0x4c00, - 0x7c1f, 0x4c08, 0x7c08, 0x6008, - 0x8300, 0xb902, 0x30a5, 0x308a, - 0x7fe0, 0x4da0, 0x65a8, 0x0000, - 0x0000, 0x56a0, 0x590c, 0x7ffd, - 0x5fa2, 0xae06, 0x7c02, 0x5c02, - 0x0000, 0x0000, 0x30f0, 0x8e05, - 0x7c02, 0x5c00, 0x0000, 0x0000, - 0xcba4, 0x0004, 0xcd8d, 0x0002, - 0x80f1, 0x7fe0, 0x4ca0, 0x7c08, - 0x6408, 0x0000, 0x0000, 0x7d00, - 0x6800, 0xb603, 0x7c10, 0x6010, - 0x7d1f, 0x551f, 0x5fb3, 0xaa07, - 0x7c80, 0x5800, 0x5b58, 0x7d80, - 0x6100, 0x310f, 0x7c80, 0x5800, - 0x5b64, 0x7d80, 0x6080, 0x4827, - 0x7c1f, 0x4c00, 0x7c1f, 0x4c10, - 0x8400, 0x7c10, 0x6000, 0x7fe0, - 0x4cc0, 0x5fbb, 0x4824, 0x7c1f, - 0x4c00, 0x7c1f, 0x4c04, 0x8200, - 0x7ce0, 0x5400, 0x6728, 0x0000, - 0x0000, 0x30cf, 0x3001, 0x7fe0, - 0x4e00, 0x4007, 0x4400, 0x5310, - 0x7c07, 0x6800, 0x673e, 0x0000, - 0x0000, 0x570f, 0x5fff, 0xaa05, - 0x585b, 0x7d80, 0x6100, 0x313b, - 0x5867, 0x7d80, 0x6080, 0x9403, - 0x7e00, 0x6200, 0xcda3, 0x00e7, - 0xcd85, 0x00e5, 0xd96b, 0x00e3, - 0x96e3, 0x7c07, 0x6800, 0x673e, - 0x0000, 0x0000, 0x7fe0, 0x4e20, - 0x96db, 0x8b04, 0x7c08, 0x5008, - 0xab03, 0x7c08, 0x5000, 0x7c07, - 0x6801, 0x677e, 0x0000, 0x0000, - 0xdb7c, 0x00ec, 0x0000, 0x7fe1, - 0x4f40, 0x4837, 0x4418, 0x41c7, - 0x7fe0, 0x4e40, 0x7c40, 0x5400, - 0x7c1f, 0x4c01, 0x7c1f, 0x4c01, - 0x8fbf, 0xd2a0, 0x004b, 0x9204, - 0xa042, 0x3168, 0x3127, 0x7fe1, - 0x4f60, 0x489c, 0x4628, 0x7fe0, - 0x4e60, 0x7e28, 0x4628, 0x7c40, - 0x5400, 0x7c01, 0x5800, 0x7c04, - 0x5c00, 0x41e8, 0x7c1f, 0x4c01, - 0x7c1f, 0x4c01, 0x8fa5, 0xb241, - 0xa02a, 0x3182, 0x7fe0, 0x4ea0, - 0x7c02, 0x4402, 0x4448, 0x4894, - 0x7c1f, 0x4c01, 0x7c1f, 0x4c03, - 0x4824, 0x7c1f, 0x4c07, 0x41ef, - 0x41ff, 0x4891, 0x7c1f, 0x4c07, - 0x7c1f, 0x4c17, 0x8400, 0x8ef8, - 0x41c7, 0x8f8a, 0x92d5, 0xa10f, - 0xd480, 0x0008, 0xd580, 0x00b8, - 0xa202, 0x319d, 0x7c04, 0x4404, - 0x319d, 0xd484, 0x00f3, 0xd484, - 0x00f1, 0x3127, 0x7fe0, 0x4ee0, - 0x7c40, 0x5400, 0x4488, 0x41cf, - 0x3127, 0x7fe0, 0x4ec0, 0x48f3, - 0x7c1f, 0x4c01, 0x7c1f, 0x4c09, - 0x4508, 0x41c7, 0x8fb0, 0xd218, - 0x00ae, 0xd2a4, 0x009e, 0x31be, - 0x7fe0, 0x4e80, 0x4832, 0x7c1f, - 0x4c01, 0x7c1f, 0x4c11, 0x4428, - 0x7c40, 0x5440, 0x7c01, 0x5801, - 0x7c04, 0x5c04, 0x41e8, 0xa4b3, - 0x31d3, 0x7fe0, 0x4f20, 0x7c07, - 0x6800, 0x673e, 0x0000, 0x0000, - 0x570f, 0x5fff, 0xaa04, 0x585b, - 0x6100, 0x31e4, 0x5867, 0x6080, - 0xbcf1, 0x3001 }; - - generic_ocp_write(tp, 0xf800, 0x3f, sizeof(pla_patch_a), - pla_patch_a, MCU_TYPE_PLA); - - ocp_write_word(tp, MCU_TYPE_PLA, 0xfc26, 0x8000); - - ocp_write_word(tp, MCU_TYPE_PLA, 0xfc28, 0x170b); - ocp_write_word(tp, MCU_TYPE_PLA, 0xfc2a, 0x01e1); - ocp_write_word(tp, MCU_TYPE_PLA, 0xfc2c, 0x0989); - ocp_write_word(tp, MCU_TYPE_PLA, 0xfc2e, 0x1349); - ocp_write_word(tp, MCU_TYPE_PLA, 0xfc30, 0x01b7); - ocp_write_word(tp, MCU_TYPE_PLA, 0xfc32, 0x061d); - - ocp_write_word(tp, MCU_TYPE_PLA, 0xe422, 0x0020); - ocp_write_word(tp, MCU_TYPE_PLA, 0xe420, 0x0018); - ocp_write_word(tp, MCU_TYPE_PLA, 0xfc34, 0x1785); - ocp_write_word(tp, MCU_TYPE_PLA, 0xfc36, 0x047b); - - ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, 0x2000); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb092, 0x7070); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb098, 0x0600); - for (i = 0; i < ARRAY_SIZE(ram_code1); i++) { - __le32 ocp_data; - - ocp_data = __cpu_to_le32(ram_code1[i] << 16); - pla_ocp_write(tp, 0xb098, 0xcc, sizeof(ocp_data), - &ocp_data); - } - ocp_write_word(tp, MCU_TYPE_PLA, 0xb098, 0x0200); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb092, 0x7030); - } else if (tp->version == RTL_VER_02) { - static u8 pla_patch_a2[] = { - 0x08, 0xe0, 0x1a, 0xe0, - 0xf2, 0xe0, 0xfa, 0xe0, - 0x32, 0xe1, 0x34, 0xe1, - 0x36, 0xe1, 0x38, 0xe1, - 0x2c, 0x75, 0xdc, 0x21, - 0xbc, 0x25, 0x04, 0x13, - 0x0b, 0xf0, 0x03, 0x13, - 0x09, 0xf0, 0x02, 0x13, - 0x07, 0xf0, 0x01, 0x13, - 0x05, 0xf0, 0x08, 0x13, - 0x03, 0xf0, 0x04, 0xc3, - 0x00, 0xbb, 0x03, 0xc3, - 0x00, 0xbb, 0xd2, 0x17, - 0xbc, 0x17, 0x14, 0xc2, - 0x40, 0x73, 0xba, 0x48, - 0x40, 0x9b, 0x11, 0xc2, - 0x40, 0x73, 0xb0, 0x49, - 0x17, 0xf0, 0xbf, 0x49, - 0x03, 0xf1, 0x09, 0xc5, - 0x00, 0xbd, 0xb1, 0x49, - 0x11, 0xf0, 0xb1, 0x48, - 0x40, 0x9b, 0x02, 0xc2, - 0x00, 0xba, 0x4e, 0x19, - 0x00, 0xa0, 0x1e, 0xfc, - 0xbc, 0xc0, 0xf0, 0xc0, - 0xde, 0xe8, 0x00, 0x80, - 0x00, 0x60, 0x2c, 0x75, - 0xd4, 0x49, 0x12, 0xf1, - 0x29, 0xe0, 0xf8, 0xc2, - 0x46, 0x71, 0xf7, 0xc2, - 0x40, 0x73, 0xbe, 0x49, - 0x03, 0xf1, 0xf5, 0xc7, - 0x02, 0xe0, 0xf2, 0xc7, - 0x4f, 0x30, 0x26, 0x62, - 0xa1, 0x49, 0xf0, 0xf1, - 0x22, 0x72, 0xa0, 0x49, - 0xed, 0xf1, 0x25, 0x25, - 0x18, 0x1f, 0x97, 0x30, - 0x91, 0x30, 0x36, 0x9a, - 0x2c, 0x75, 0x32, 0xc3, - 0x60, 0x73, 0xb1, 0x49, - 0x0d, 0xf1, 0xdc, 0x21, - 0xbc, 0x25, 0x27, 0xc6, - 0xc0, 0x77, 0x04, 0x13, - 0x18, 0xf0, 0x03, 0x13, - 0x19, 0xf0, 0x02, 0x13, - 0x1a, 0xf0, 0x01, 0x13, - 0x1b, 0xf0, 0xd4, 0x49, - 0x03, 0xf1, 0x1c, 0xc5, - 0x00, 0xbd, 0xcd, 0xc6, - 0xc6, 0x67, 0x2e, 0x75, - 0xd7, 0x22, 0xdd, 0x26, - 0x05, 0x15, 0x1a, 0xf0, - 0x14, 0xc6, 0x00, 0xbe, - 0x13, 0xc5, 0x00, 0xbd, - 0x12, 0xc5, 0x00, 0xbd, - 0xf1, 0x49, 0xfb, 0xf1, - 0xef, 0xe7, 0xf4, 0x49, - 0xfa, 0xf1, 0xec, 0xe7, - 0xf3, 0x49, 0xf7, 0xf1, - 0xe9, 0xe7, 0xf2, 0x49, - 0xf4, 0xf1, 0xe6, 0xe7, - 0xb6, 0xc0, 0xf6, 0x14, - 0x36, 0x14, 0x62, 0x14, - 0x86, 0x15, 0xa0, 0xd1, - 0x00, 0x00, 0xc0, 0x75, - 0xd0, 0x49, 0x46, 0xf0, - 0x26, 0x72, 0xa7, 0x49, - 0x43, 0xf0, 0x22, 0x72, - 0x25, 0x25, 0x20, 0x1f, - 0x97, 0x30, 0x91, 0x30, - 0x40, 0x73, 0xf3, 0xc4, - 0x1c, 0x40, 0x04, 0xf0, - 0xd7, 0x49, 0x05, 0xf1, - 0x37, 0xe0, 0x53, 0x48, - 0xc0, 0x9d, 0x08, 0x02, - 0x40, 0x66, 0x64, 0x27, - 0x06, 0x16, 0x30, 0xf1, - 0x46, 0x63, 0x3b, 0x13, - 0x2d, 0xf1, 0x34, 0x9b, - 0x18, 0x1b, 0x93, 0x30, - 0x2b, 0xc3, 0x10, 0x1c, - 0x2b, 0xe8, 0x01, 0x14, - 0x25, 0xf1, 0x00, 0x1d, - 0x26, 0x1a, 0x8a, 0x30, - 0x22, 0x73, 0xb5, 0x25, - 0x0e, 0x0b, 0x00, 0x1c, - 0x2c, 0xe8, 0x1f, 0xc7, - 0x27, 0x40, 0x1a, 0xf1, - 0x38, 0xe8, 0x32, 0x1f, - 0x8f, 0x30, 0x08, 0x1b, - 0x24, 0xe8, 0x36, 0x72, - 0x46, 0x77, 0x00, 0x17, - 0x0d, 0xf0, 0x13, 0xc3, - 0x1f, 0x40, 0x03, 0xf1, - 0x00, 0x1f, 0x46, 0x9f, - 0x44, 0x77, 0x9f, 0x44, - 0x5f, 0x44, 0x17, 0xe8, - 0x0a, 0xc7, 0x27, 0x40, - 0x05, 0xf1, 0x02, 0xc3, - 0x00, 0xbb, 0x1c, 0x1b, - 0xd2, 0x1a, 0xff, 0xc7, - 0x00, 0xbf, 0xb8, 0xcd, - 0xff, 0xff, 0x02, 0x0c, - 0x54, 0xa5, 0xdc, 0xa5, - 0x2f, 0x40, 0x05, 0xf1, - 0x00, 0x14, 0xfa, 0xf1, - 0x01, 0x1c, 0x02, 0xe0, - 0x00, 0x1c, 0x80, 0xff, - 0xb0, 0x49, 0x04, 0xf0, - 0x01, 0x0b, 0xd3, 0xa1, - 0x03, 0xe0, 0x02, 0x0b, - 0xd3, 0xa5, 0x27, 0x31, - 0x20, 0x37, 0x02, 0x0b, - 0xd3, 0xa5, 0x27, 0x31, - 0x20, 0x37, 0x00, 0x13, - 0xfb, 0xf1, 0x80, 0xff, - 0x22, 0x73, 0xb5, 0x25, - 0x18, 0x1e, 0xde, 0x30, - 0xd9, 0x30, 0x64, 0x72, - 0x11, 0x1e, 0x68, 0x23, - 0x16, 0x31, 0x80, 0xff, - 0x08, 0xc2, 0x40, 0x73, - 0x3a, 0x48, 0x40, 0x9b, - 0x06, 0xff, 0x02, 0xc6, - 0x00, 0xbe, 0x4e, 0x18, - 0x1e, 0xfc, 0x33, 0xc5, - 0xa0, 0x74, 0xc0, 0x49, - 0x1f, 0xf0, 0x30, 0xc5, - 0xa0, 0x73, 0x00, 0x13, - 0x04, 0xf1, 0xa2, 0x73, - 0x00, 0x13, 0x14, 0xf0, - 0x28, 0xc5, 0xa0, 0x74, - 0xc8, 0x49, 0x1b, 0xf1, - 0x26, 0xc5, 0xa0, 0x76, - 0xa2, 0x74, 0x01, 0x06, - 0x20, 0x37, 0xa0, 0x9e, - 0xa2, 0x9c, 0x1e, 0xc5, - 0xa2, 0x73, 0x23, 0x40, - 0x10, 0xf8, 0x04, 0xf3, - 0xa0, 0x73, 0x33, 0x40, - 0x0c, 0xf8, 0x15, 0xc5, - 0xa0, 0x74, 0x41, 0x48, - 0xa0, 0x9c, 0x14, 0xc5, - 0xa0, 0x76, 0x62, 0x48, - 0xe0, 0x48, 0xa0, 0x9e, - 0x10, 0xc6, 0x00, 0xbe, - 0x0a, 0xc5, 0xa0, 0x74, - 0x48, 0x48, 0xa0, 0x9c, - 0x0b, 0xc5, 0x20, 0x1e, - 0xa0, 0x9e, 0xe5, 0x48, - 0xa0, 0x9e, 0xf0, 0xe7, - 0xbc, 0xc0, 0xc8, 0xd2, - 0xcc, 0xd2, 0x28, 0xe4, - 0x22, 0x02, 0xf0, 0xc0, - 0x02, 0xc6, 0x00, 0xbe, - 0x00, 0x00, 0x02, 0xc6, - 0x00, 0xbe, 0x00, 0x00, - 0x02, 0xc6, 0x00, 0xbe, - 0x00, 0x00, 0x02, 0xc6, - 0x00, 0xbe, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 }; - - generic_ocp_write(tp, 0xf800, 0xff, sizeof(pla_patch_a2), - pla_patch_a2, MCU_TYPE_PLA); - - ocp_write_word(tp, MCU_TYPE_PLA, 0xfc26, 0x8000); - - ocp_write_word(tp, MCU_TYPE_PLA, 0xfc28, 0x17a5); - ocp_write_word(tp, MCU_TYPE_PLA, 0xfc2a, 0x13ad); - ocp_write_word(tp, MCU_TYPE_PLA, 0xfc2c, 0x1840); - ocp_write_word(tp, MCU_TYPE_PLA, 0xfc2e, 0x01e1); - } -} - -static void r8152b_disable_aldps(struct r8152 *tp) -{ - ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPDNPS | LINKENA | DIS_SDSAVE); - msleep(20); -} - -static inline void r8152b_enable_aldps(struct r8152 *tp) -{ - ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPWRSAVE | ENPDNPS | - LINKENA | DIS_SDSAVE); -} - -static void rtl8152_disable(struct r8152 *tp) -{ - r8152b_disable_aldps(tp); - rtl_disable(tp); - r8152b_enable_aldps(tp); -} - -static void r8152b_hw_phy_cfg(struct r8152 *tp) -{ - u16 data; - - data = r8152_mdio_read(tp, MII_BMCR); - if (data & BMCR_PDOWN) { - data &= ~BMCR_PDOWN; - r8152_mdio_write(tp, MII_BMCR, data); - } - - r8152b_firmware(tp); - - set_bit(PHY_RESET, &tp->flags); -} - -static void r8152b_exit_oob(struct r8152 *tp) -{ - u32 ocp_data; - int i; - - ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); - ocp_data &= ~RCR_ACPT_ALL; - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); - - rxdy_gated_en(tp, true); - r8153_teredo_off(tp); - r8152b_hw_phy_cfg(tp); - - ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML); - ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, 0x00); - - ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); - ocp_data &= ~NOW_IS_OOB; - ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data); - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7); - ocp_data &= ~MCU_BORW_EN; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data); - - for (i = 0; i < 1000; i++) { - ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); - if (ocp_data & LINK_LIST_READY) - break; - usleep_range(1000, 2000); - } - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7); - ocp_data |= RE_INIT_LL; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data); - - for (i = 0; i < 1000; i++) { - ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); - if (ocp_data & LINK_LIST_READY) - break; - usleep_range(1000, 2000); - } - - rtl8152_nic_reset(tp); - - /* rx share fifo credit full threshold */ - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_NORMAL); - - if (tp->udev->speed == USB_SPEED_FULL || - tp->udev->speed == USB_SPEED_LOW) { - /* rx share fifo credit near full threshold */ - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1, - RXFIFO_THR2_FULL); - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2, - RXFIFO_THR3_FULL); - } else { - /* rx share fifo credit near full threshold */ - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1, - RXFIFO_THR2_HIGH); - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2, - RXFIFO_THR3_HIGH); - } - - /* TX share fifo free credit full threshold */ - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, TXFIFO_THR_NORMAL); - - ocp_write_byte(tp, MCU_TYPE_USB, USB_TX_AGG, TX_AGG_MAX_THRESHOLD); - ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, RX_THR_HIGH); - ocp_write_dword(tp, MCU_TYPE_USB, USB_TX_DMA, - TEST_MODE_DISABLE | TX_SIZE_ADJUST1); - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CPCR); - ocp_data &= ~CPCR_RX_VLAN; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data); - - ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS); - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR0); - ocp_data |= TCR0_AUTO_FIFO; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_TCR0, ocp_data); -} - -static void r8152b_enter_oob(struct r8152 *tp) -{ - u32 ocp_data; - int i; - - ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); - ocp_data &= ~NOW_IS_OOB; - ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data); - - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_OOB); - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1, RXFIFO_THR2_OOB); - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2, RXFIFO_THR3_OOB); - - rtl_disable(tp); - - for (i = 0; i < 1000; i++) { - ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); - if (ocp_data & LINK_LIST_READY) - break; - usleep_range(1000, 2000); - } - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7); - ocp_data |= RE_INIT_LL; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data); - - for (i = 0; i < 1000; i++) { - ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); - if (ocp_data & LINK_LIST_READY) - break; - usleep_range(1000, 2000); - } - - ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS); - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CPCR); - ocp_data |= CPCR_RX_VLAN; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data); - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PAL_BDC_CR); - ocp_data |= ALDPS_PROXY_MODE; - ocp_write_word(tp, MCU_TYPE_PLA, PAL_BDC_CR, ocp_data); - - ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); - ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB; - ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data); - - rxdy_gated_en(tp, false); - - ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); - ocp_data |= RCR_APM | RCR_AM | RCR_AB; - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); -} - -static void r8153_firmware(struct r8152 *tp) -{ - u16 data; - - r8153_clear_bp(tp); - - if (tp->version == RTL_VER_03) { - data = ocp_reg_read(tp, 0xb820); - data |= 0x0010; - ocp_reg_write(tp, 0xb820, data); - while ((ocp_reg_read(tp, 0xb800) & 0x0040) == 0); - ocp_reg_write(tp, 0xa436, 0x8146); - ocp_reg_write(tp, 0xa438, 0x7000); - ocp_reg_write(tp, 0xa436, 0xb82e); - ocp_reg_write(tp, 0xa438, 0x0001); - tp->ocp_base = 0xa000; - ocp_write_word(tp, MCU_TYPE_PLA, 0xe86c, 0xa000); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb436, 0xb820); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x0290); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb436, 0xa012); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x0000); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb436, 0xa014); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x2c04); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x2c18); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x2c45); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x2c45); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xd502); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x8301); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x8306); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xd500); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x8208); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xd501); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xe018); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x0308); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x60f2); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x8404); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x607d); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xc117); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x2c16); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xc116); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x2c16); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x607d); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xc117); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xa404); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xd500); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x0800); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xd501); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x62d2); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x615d); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xc115); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xa404); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xc307); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xd502); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x8301); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x8306); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xd500); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x8208); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x2c42); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xc114); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x8404); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xc317); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xd701); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x435d); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xd500); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xa208); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xd502); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xa306); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xa301); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x2c42); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x8404); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x613d); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xc115); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xc307); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xd502); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x8301); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x8306); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xd500); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x8208); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x2c42); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xc114); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xc317); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xd701); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x40dd); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xd500); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xa208); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xd502); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xa306); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xa301); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xd500); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0xd702); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x0800); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb436, 0xa01a); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x0000); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb436, 0xa006); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x0fff); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb436, 0xa004); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x0fff); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb436, 0xa002); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x05a3); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb436, 0xa000); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x3591); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb436, 0xb820); - ocp_write_word(tp, MCU_TYPE_PLA, 0xb438, 0x0210); - ocp_reg_write(tp, 0xa436, 0x0000); - ocp_reg_write(tp, 0xa438, 0x0000); - data = ocp_reg_read(tp, 0xb82e); - data &= ~0x0001; - ocp_reg_write(tp, 0xb82e, data); - ocp_reg_write(tp, 0xa436, 0x8146); - ocp_reg_write(tp, 0xa438, 0x0000); - - data = ocp_reg_read(tp, 0xb820); - data &= ~0x0010; - ocp_reg_write(tp, 0xb820, data); - } else if (tp->version == RTL_VER_04) { - static u8 usb_patch_b[] = { - 0x08, 0xe0, 0x0f, 0xe0, - 0x18, 0xe0, 0x24, 0xe0, - 0x26, 0xe0, 0x3a, 0xe0, - 0x84, 0xe0, 0x9c, 0xe0, - 0xc2, 0x49, 0x04, 0xf0, - 0x02, 0xc0, 0x00, 0xb8, - 0x14, 0x18, 0x02, 0xc0, - 0x00, 0xb8, 0x2e, 0x18, - 0x06, 0x89, 0x08, 0xc0, - 0x0c, 0x61, 0x92, 0x48, - 0x93, 0x48, 0x0c, 0x89, - 0x02, 0xc0, 0x00, 0xb8, - 0x08, 0x05, 0x40, 0xb4, - 0x16, 0x89, 0x6d, 0xc0, - 0x00, 0x61, 0x95, 0x49, - 0x06, 0xf0, 0xfa, 0xc0, - 0x0c, 0x61, 0x92, 0x48, - 0x93, 0x48, 0x0c, 0x89, - 0x02, 0xc0, 0x00, 0xb8, - 0xe2, 0x04, 0x02, 0xc2, - 0x00, 0xba, 0xec, 0x11, - 0x60, 0x60, 0x85, 0x49, - 0x0d, 0xf1, 0x11, 0xc6, - 0xd2, 0x61, 0x91, 0x49, - 0xfd, 0xf0, 0x74, 0x60, - 0x04, 0x48, 0x74, 0x88, - 0x08, 0xc6, 0x08, 0xc0, - 0xc4, 0x98, 0x01, 0x18, - 0xc0, 0x88, 0x02, 0xc0, - 0x00, 0xb8, 0x6e, 0x12, - 0x04, 0xe4, 0x0d, 0x00, - 0x00, 0xd4, 0xd1, 0x49, - 0x3c, 0xf1, 0xd2, 0x49, - 0x16, 0xf1, 0xd3, 0x49, - 0x18, 0xf1, 0xd4, 0x49, - 0x19, 0xf1, 0xd5, 0x49, - 0x1a, 0xf1, 0xd6, 0x49, - 0x1b, 0xf1, 0xd7, 0x49, - 0x1c, 0xf1, 0xd8, 0x49, - 0x1d, 0xf1, 0xd9, 0x49, - 0x20, 0xf1, 0xda, 0x49, - 0x23, 0xf1, 0xdb, 0x49, - 0x24, 0xf1, 0x02, 0xc4, - 0x00, 0xbc, 0x20, 0x04, - 0xe5, 0x8e, 0x02, 0xc4, - 0x00, 0xbc, 0x14, 0x02, - 0x02, 0xc4, 0x00, 0xbc, - 0x16, 0x02, 0x02, 0xc4, - 0x00, 0xbc, 0x18, 0x02, - 0x02, 0xc4, 0x00, 0xbc, - 0x1a, 0x02, 0x02, 0xc4, - 0x00, 0xbc, 0x1c, 0x02, - 0x02, 0xc4, 0x00, 0xbc, - 0x94, 0x02, 0x10, 0xc7, - 0xe0, 0x8e, 0x02, 0xc4, - 0x00, 0xbc, 0x8a, 0x02, - 0x0b, 0xc7, 0xe4, 0x8e, - 0x02, 0xc4, 0x00, 0xbc, - 0x88, 0x02, 0x02, 0xc4, - 0x00, 0xbc, 0x6e, 0x02, - 0x02, 0xc4, 0x00, 0xbc, - 0x5a, 0x02, 0x30, 0xe4, - 0x0c, 0xc3, 0x60, 0x64, - 0xc5, 0x49, 0x04, 0xf1, - 0x74, 0x64, 0xc4, 0x48, - 0x74, 0x8c, 0x06, 0xc3, - 0x64, 0x8e, 0x02, 0xc4, - 0x00, 0xbc, 0x20, 0x04, - 0x00, 0xd8, 0x00, 0xe4, - 0xb2, 0xc0, 0x00, 0x61, - 0x90, 0x49, 0x09, 0xf1, - 0x8b, 0xc6, 0xca, 0x61, - 0x94, 0x49, 0x0e, 0xf1, - 0xf6, 0xc6, 0xda, 0x60, - 0x81, 0x49, 0x0a, 0xf0, - 0x65, 0x60, 0x03, 0x48, - 0x65, 0x88, 0xef, 0xc6, - 0xdc, 0x60, 0x80, 0x48, - 0xdc, 0x88, 0x05, 0xc6, - 0x00, 0xbe, 0x02, 0xc6, - 0x00, 0xbe, 0x36, 0x13, - 0x4c, 0x17, 0x99, 0xc4, - 0x80, 0x65, 0xd0, 0x49, - 0x04, 0xf1, 0xfa, 0x75, - 0x04, 0xc4, 0x00, 0xbc, - 0x03, 0xc4, 0x00, 0xbc, - 0x9a, 0x00, 0xee, 0x01 }; - static u8 pla_patch_b[] = { - 0x08, 0xe0, 0xea, 0xe0, - 0xf2, 0xe0, 0x04, 0xe1, - 0x09, 0xe1, 0x0e, 0xe1, - 0x46, 0xe1, 0xab, 0xe1, - 0x14, 0xc2, 0x40, 0x73, - 0xba, 0x48, 0x40, 0x9b, - 0x11, 0xc2, 0x40, 0x73, - 0xb0, 0x49, 0x17, 0xf0, - 0xbf, 0x49, 0x03, 0xf1, - 0x09, 0xc5, 0x00, 0xbd, - 0xb1, 0x49, 0x11, 0xf0, - 0xb1, 0x48, 0x40, 0x9b, - 0x02, 0xc2, 0x00, 0xba, - 0x1a, 0x17, 0x00, 0xe0, - 0x1e, 0xfc, 0xbc, 0xc0, - 0xf0, 0xc0, 0xde, 0xe8, - 0x00, 0x80, 0x00, 0x20, - 0x2c, 0x75, 0xd4, 0x49, - 0x12, 0xf1, 0x32, 0xe0, - 0xf8, 0xc2, 0x46, 0x71, - 0xf7, 0xc2, 0x40, 0x73, - 0xbe, 0x49, 0x03, 0xf1, - 0xf5, 0xc7, 0x02, 0xe0, - 0xf2, 0xc7, 0x4f, 0x30, - 0x26, 0x62, 0xa1, 0x49, - 0xf0, 0xf1, 0x22, 0x72, - 0xa0, 0x49, 0xed, 0xf1, - 0x25, 0x25, 0x18, 0x1f, - 0x97, 0x30, 0x91, 0x30, - 0x36, 0x9a, 0x2c, 0x75, - 0x3c, 0xc3, 0x60, 0x73, - 0xb1, 0x49, 0x0d, 0xf1, - 0xdc, 0x21, 0xbc, 0x25, - 0x30, 0xc6, 0xc0, 0x77, - 0x04, 0x13, 0x21, 0xf0, - 0x03, 0x13, 0x22, 0xf0, - 0x02, 0x13, 0x23, 0xf0, - 0x01, 0x13, 0x24, 0xf0, - 0x08, 0x13, 0x08, 0xf1, - 0x2e, 0x73, 0xba, 0x21, - 0xbd, 0x25, 0x05, 0x13, - 0x03, 0xf1, 0x24, 0xc5, - 0x00, 0xbd, 0xd4, 0x49, - 0x03, 0xf1, 0x1c, 0xc5, - 0x00, 0xbd, 0xc4, 0xc6, - 0xc6, 0x67, 0x2e, 0x75, - 0xd7, 0x22, 0xdd, 0x26, - 0x05, 0x15, 0x1b, 0xf0, - 0x14, 0xc6, 0x00, 0xbe, - 0x13, 0xc5, 0x00, 0xbd, - 0x12, 0xc5, 0x00, 0xbd, - 0xf1, 0x49, 0xfb, 0xf1, - 0xef, 0xe7, 0xf4, 0x49, - 0xfa, 0xf1, 0xec, 0xe7, - 0xf3, 0x49, 0xf7, 0xf1, - 0xe9, 0xe7, 0xf2, 0x49, - 0xf4, 0xf1, 0xe6, 0xe7, - 0xb6, 0xc0, 0x9e, 0x12, - 0xde, 0x11, 0x0a, 0x12, - 0x3c, 0x13, 0x00, 0xa0, - 0xa0, 0xd1, 0x00, 0x00, - 0xc0, 0x75, 0xd0, 0x49, - 0x46, 0xf0, 0x26, 0x72, - 0xa7, 0x49, 0x43, 0xf0, - 0x22, 0x72, 0x25, 0x25, - 0x20, 0x1f, 0x97, 0x30, - 0x91, 0x30, 0x40, 0x73, - 0xf3, 0xc4, 0x1c, 0x40, - 0x04, 0xf0, 0xd7, 0x49, - 0x05, 0xf1, 0x37, 0xe0, - 0x53, 0x48, 0xc0, 0x9d, - 0x08, 0x02, 0x40, 0x66, - 0x64, 0x27, 0x06, 0x16, - 0x30, 0xf1, 0x46, 0x63, - 0x3b, 0x13, 0x2d, 0xf1, - 0x34, 0x9b, 0x18, 0x1b, - 0x93, 0x30, 0x2b, 0xc3, - 0x10, 0x1c, 0x2b, 0xe8, - 0x01, 0x14, 0x25, 0xf1, - 0x00, 0x1d, 0x26, 0x1a, - 0x8a, 0x30, 0x22, 0x73, - 0xb5, 0x25, 0x0e, 0x0b, - 0x00, 0x1c, 0x2c, 0xe8, - 0x1f, 0xc7, 0x27, 0x40, - 0x1a, 0xf1, 0x38, 0xe8, - 0x32, 0x1f, 0x8f, 0x30, - 0x08, 0x1b, 0x24, 0xe8, - 0x36, 0x72, 0x46, 0x77, - 0x00, 0x17, 0x0d, 0xf0, - 0x13, 0xc3, 0x1f, 0x40, - 0x03, 0xf1, 0x00, 0x1f, - 0x46, 0x9f, 0x44, 0x77, - 0x9f, 0x44, 0x5f, 0x44, - 0x17, 0xe8, 0x0a, 0xc7, - 0x27, 0x40, 0x05, 0xf1, - 0x02, 0xc3, 0x00, 0xbb, - 0xfa, 0x18, 0xb0, 0x18, - 0xff, 0xc7, 0x00, 0xbf, - 0xb8, 0xcd, 0xff, 0xff, - 0x02, 0x0c, 0x54, 0xa5, - 0xdc, 0xa5, 0x2f, 0x40, - 0x05, 0xf1, 0x00, 0x14, - 0xfa, 0xf1, 0x01, 0x1c, - 0x02, 0xe0, 0x00, 0x1c, - 0x80, 0xff, 0xb0, 0x49, - 0x04, 0xf0, 0x01, 0x0b, - 0xd3, 0xa1, 0x03, 0xe0, - 0x02, 0x0b, 0xd3, 0xa5, - 0x27, 0x31, 0x20, 0x37, - 0x02, 0x0b, 0xd3, 0xa5, - 0x27, 0x31, 0x20, 0x37, - 0x00, 0x13, 0xfb, 0xf1, - 0x80, 0xff, 0x22, 0x73, - 0xb5, 0x25, 0x18, 0x1e, - 0xde, 0x30, 0xd9, 0x30, - 0x64, 0x72, 0x11, 0x1e, - 0x68, 0x23, 0x16, 0x31, - 0x80, 0xff, 0x08, 0xc2, - 0x40, 0x73, 0x3a, 0x48, - 0x40, 0x9b, 0x06, 0xff, - 0x02, 0xc6, 0x00, 0xbe, - 0x08, 0x16, 0x1e, 0xfc, - 0x2c, 0x75, 0xdc, 0x21, - 0xbc, 0x25, 0x04, 0x13, - 0x0b, 0xf0, 0x03, 0x13, - 0x09, 0xf0, 0x02, 0x13, - 0x07, 0xf0, 0x01, 0x13, - 0x05, 0xf0, 0x08, 0x13, - 0x03, 0xf0, 0x04, 0xc3, - 0x00, 0xbb, 0x03, 0xc3, - 0x00, 0xbb, 0x8c, 0x15, - 0x76, 0x15, 0xa0, 0x64, - 0x40, 0x48, 0xa0, 0x8c, - 0x02, 0xc4, 0x00, 0xbc, - 0x82, 0x00, 0xa0, 0x62, - 0x21, 0x48, 0xa0, 0x8a, - 0x02, 0xc2, 0x00, 0xba, - 0x40, 0x03, 0x33, 0xc5, - 0xa0, 0x74, 0xc0, 0x49, - 0x1f, 0xf0, 0x30, 0xc5, - 0xa0, 0x73, 0x00, 0x13, - 0x04, 0xf1, 0xa2, 0x73, - 0x00, 0x13, 0x14, 0xf0, - 0x28, 0xc5, 0xa0, 0x74, - 0xc8, 0x49, 0x1b, 0xf1, - 0x26, 0xc5, 0xa0, 0x76, - 0xa2, 0x74, 0x01, 0x06, - 0x20, 0x37, 0xa0, 0x9e, - 0xa2, 0x9c, 0x1e, 0xc5, - 0xa2, 0x73, 0x23, 0x40, - 0x10, 0xf8, 0x04, 0xf3, - 0xa0, 0x73, 0x33, 0x40, - 0x0c, 0xf8, 0x15, 0xc5, - 0xa0, 0x74, 0x41, 0x48, - 0xa0, 0x9c, 0x14, 0xc5, - 0xa0, 0x76, 0x62, 0x48, - 0xe0, 0x48, 0xa0, 0x9e, - 0x10, 0xc6, 0x00, 0xbe, - 0x0a, 0xc5, 0xa0, 0x74, - 0x48, 0x48, 0xa0, 0x9c, - 0x0b, 0xc5, 0x20, 0x1e, - 0xa0, 0x9e, 0xe5, 0x48, - 0xa0, 0x9e, 0xf0, 0xe7, - 0xbc, 0xc0, 0xc8, 0xd2, - 0xcc, 0xd2, 0x28, 0xe4, - 0xe6, 0x01, 0xf0, 0xc0, - 0x18, 0x89, 0x00, 0x1d, - 0x5a, 0xc0, 0x5a, 0xc1, - 0x02, 0x99, 0x00, 0x61, - 0x67, 0x11, 0x35, 0xf1, - 0x69, 0x33, 0x55, 0xc0, - 0x28, 0x40, 0xf7, 0xf1, - 0x54, 0xc0, 0x00, 0x19, - 0x81, 0x1b, 0x44, 0xe8, - 0x53, 0xc0, 0x04, 0x1a, - 0x84, 0x1b, 0x40, 0xe8, - 0x35, 0xe8, 0xa3, 0x49, - 0xfe, 0xf0, 0x4a, 0xc0, - 0x31, 0xe8, 0xa1, 0x48, - 0x47, 0xc0, 0x84, 0x1b, - 0x37, 0xe8, 0x00, 0x1d, - 0x69, 0x33, 0x00, 0x1e, - 0x01, 0x06, 0xff, 0x18, - 0x30, 0x40, 0xfd, 0xf1, - 0x40, 0xc0, 0x00, 0x76, - 0x2e, 0x40, 0xf7, 0xf1, - 0x21, 0x48, 0x38, 0xc0, - 0x84, 0x1b, 0x28, 0xe8, - 0x36, 0xc0, 0x1c, 0xe8, - 0xa1, 0x49, 0xfd, 0xf0, - 0x33, 0xc0, 0x00, 0x1a, - 0x84, 0x1b, 0x20, 0xe8, - 0x15, 0xe8, 0xa5, 0x49, - 0xfe, 0xf0, 0x29, 0xc0, - 0x01, 0x19, 0x81, 0x1b, - 0x19, 0xe8, 0x0b, 0xe0, - 0x9c, 0x20, 0x9c, 0x24, - 0x06, 0x11, 0x07, 0xf1, - 0x25, 0xc0, 0x08, 0xe8, - 0x23, 0xc0, 0x12, 0x48, - 0x81, 0x1b, 0x0e, 0xe8, - 0x02, 0xc0, 0x00, 0xb8, - 0x96, 0x07, 0x16, 0xc4, - 0x84, 0x98, 0x00, 0x1b, - 0x86, 0x8b, 0x86, 0x73, - 0xbf, 0x49, 0xfe, 0xf1, - 0x80, 0x71, 0x82, 0x72, - 0x80, 0xff, 0x0c, 0xc4, - 0x84, 0x98, 0x80, 0x99, - 0x82, 0x9a, 0x86, 0x8b, - 0x86, 0x73, 0xbf, 0x49, - 0xfe, 0xf1, 0x80, 0xff, - 0x50, 0xe8, 0x82, 0x00, - 0xb8, 0x0b, 0x08, 0xea, - 0x20, 0xb4, 0x84, 0xd4, - 0x10, 0xd4, 0x10, 0xd8, - 0x88, 0xd3, 0x30, 0xd4, - 0x02, 0xc6, 0x00, 0xbe, - 0x00, 0x00, 0x00, 0x00 }; - - ocp_write_word(tp, MCU_TYPE_USB, USB_BP_EN, 0x0000); - generic_ocp_write(tp, 0xf800, 0xff, sizeof(usb_patch_b), - usb_patch_b, MCU_TYPE_USB); - ocp_write_word(tp, MCU_TYPE_USB, 0xfc26, 0xa000); - ocp_write_word(tp, MCU_TYPE_USB, 0xfc28, 0x180c); - ocp_write_word(tp, MCU_TYPE_USB, 0xfc2a, 0x0506); - ocp_write_word(tp, MCU_TYPE_USB, 0xfc2c, 0x04E0); - ocp_write_word(tp, MCU_TYPE_USB, 0xfc2e, 0x11E4); - ocp_write_word(tp, MCU_TYPE_USB, 0xfc30, 0x125C); - ocp_write_word(tp, MCU_TYPE_USB, 0xfc32, 0x0232); - ocp_write_word(tp, MCU_TYPE_USB, 0xfc34, 0x131E); - ocp_write_word(tp, MCU_TYPE_USB, 0xfc36, 0x0098); - ocp_write_word(tp, MCU_TYPE_USB, USB_BP_EN, 0x00FF); - - ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_EN, 0x0000); - generic_ocp_write(tp, 0xf800, 0xff, sizeof(pla_patch_b), - pla_patch_b, MCU_TYPE_PLA); - ocp_write_word(tp, MCU_TYPE_PLA, 0xfc26, 0x8000); - ocp_write_word(tp, MCU_TYPE_PLA, 0xfc28, 0x1154); - ocp_write_word(tp, MCU_TYPE_PLA, 0xfc2a, 0x1606); - ocp_write_word(tp, MCU_TYPE_PLA, 0xfc2c, 0x155a); - ocp_write_word(tp, MCU_TYPE_PLA, 0xfc2e, 0x0080); - ocp_write_word(tp, MCU_TYPE_PLA, 0xfc30, 0x033c); - ocp_write_word(tp, MCU_TYPE_PLA, 0xfc32, 0x01a0); - ocp_write_word(tp, MCU_TYPE_PLA, 0xfc34, 0x0794); - ocp_write_word(tp, MCU_TYPE_PLA, 0xfc36, 0x0000); - ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_EN, 0x007f); - - ocp_write_word(tp, MCU_TYPE_PLA, 0xd388, 0x08ca); - } else if (tp->version == RTL_VER_05) { - u32 ocp_data; - static u8 usb_patch_c[] = { - 0x08, 0xe0, 0x0a, 0xe0, - 0x14, 0xe0, 0x26, 0xe0, - 0x2d, 0xe0, 0x34, 0xe0, - 0x36, 0xe0, 0x38, 0xe0, - 0x02, 0xc5, 0x00, 0xbd, - 0x38, 0x3b, 0xdb, 0x49, - 0x04, 0xf1, 0x06, 0xc3, - 0x00, 0xbb, 0x5a, 0x02, - 0x05, 0xc4, 0x03, 0xc3, - 0x00, 0xbb, 0xa4, 0x04, - 0x7e, 0x02, 0x30, 0xd4, - 0x32, 0x48, 0x30, 0x18, - 0x10, 0xc1, 0x04, 0xe8, - 0x02, 0xc2, 0x00, 0xba, - 0x3e, 0x16, 0x02, 0xb4, - 0x09, 0xc2, 0x40, 0x99, - 0x0e, 0x48, 0x42, 0x98, - 0x42, 0x70, 0x8e, 0x49, - 0xfe, 0xf1, 0x02, 0xb0, - 0x80, 0xff, 0xc0, 0xd4, - 0xe4, 0x40, 0xe7, 0x8d, - 0x30, 0x18, 0x05, 0xc1, - 0xf1, 0xef, 0x02, 0xc0, - 0x00, 0xb8, 0xd8, 0x10, - 0xe4, 0x4b, 0x07, 0xc3, - 0x70, 0x61, 0x12, 0x48, - 0x70, 0x89, 0x02, 0xc3, - 0x00, 0xbb, 0x9c, 0x15, - 0x20, 0xd4, 0x02, 0xc6, - 0x00, 0xbe, 0x00, 0x00, - 0x02, 0xc6, 0x00, 0xbe, - 0x00, 0x00, 0x02, 0xc6, - 0x00, 0xbe, 0x00, 0x00 }; - static u8 pla_patch_c[] = { - 0x08, 0xe0, 0xea, 0xe0, - 0xf2, 0xe0, 0x04, 0xe1, - 0x06, 0xe1, 0x08, 0xe1, - 0x40, 0xe1, 0xa5, 0xe1, - 0x14, 0xc2, 0x40, 0x73, - 0xba, 0x48, 0x40, 0x9b, - 0x11, 0xc2, 0x40, 0x73, - 0xb0, 0x49, 0x17, 0xf0, - 0xbf, 0x49, 0x03, 0xf1, - 0x09, 0xc5, 0x00, 0xbd, - 0xb1, 0x49, 0x11, 0xf0, - 0xb1, 0x48, 0x40, 0x9b, - 0x02, 0xc2, 0x00, 0xba, - 0xde, 0x18, 0x00, 0xe0, - 0x1e, 0xfc, 0xbc, 0xc0, - 0xf0, 0xc0, 0xde, 0xe8, - 0x00, 0x80, 0x00, 0x20, - 0x2c, 0x75, 0xd4, 0x49, - 0x12, 0xf1, 0x32, 0xe0, - 0xf8, 0xc2, 0x46, 0x71, - 0xf7, 0xc2, 0x40, 0x73, - 0xbe, 0x49, 0x03, 0xf1, - 0xf5, 0xc7, 0x02, 0xe0, - 0xf2, 0xc7, 0x4f, 0x30, - 0x26, 0x62, 0xa1, 0x49, - 0xf0, 0xf1, 0x22, 0x72, - 0xa0, 0x49, 0xed, 0xf1, - 0x25, 0x25, 0x18, 0x1f, - 0x97, 0x30, 0x91, 0x30, - 0x36, 0x9a, 0x2c, 0x75, - 0x3c, 0xc3, 0x60, 0x73, - 0xb1, 0x49, 0x0d, 0xf1, - 0xdc, 0x21, 0xbc, 0x25, - 0x30, 0xc6, 0xc0, 0x77, - 0x04, 0x13, 0x21, 0xf0, - 0x03, 0x13, 0x22, 0xf0, - 0x02, 0x13, 0x23, 0xf0, - 0x01, 0x13, 0x24, 0xf0, - 0x08, 0x13, 0x08, 0xf1, - 0x2e, 0x73, 0xba, 0x21, - 0xbd, 0x25, 0x05, 0x13, - 0x03, 0xf1, 0x24, 0xc5, - 0x00, 0xbd, 0xd4, 0x49, - 0x03, 0xf1, 0x1c, 0xc5, - 0x00, 0xbd, 0xc4, 0xc6, - 0xc6, 0x67, 0x2e, 0x75, - 0xd7, 0x22, 0xdd, 0x26, - 0x05, 0x15, 0x1b, 0xf0, - 0x14, 0xc6, 0x00, 0xbe, - 0x13, 0xc5, 0x00, 0xbd, - 0x12, 0xc5, 0x00, 0xbd, - 0xf1, 0x49, 0xfb, 0xf1, - 0xef, 0xe7, 0xf4, 0x49, - 0xfa, 0xf1, 0xec, 0xe7, - 0xf3, 0x49, 0xf7, 0xf1, - 0xe9, 0xe7, 0xf2, 0x49, - 0xf4, 0xf1, 0xe6, 0xe7, - 0xb6, 0xc0, 0x50, 0x14, - 0x90, 0x13, 0xbc, 0x13, - 0xf2, 0x14, 0x00, 0xa0, - 0xa0, 0xd1, 0x00, 0x00, - 0xc0, 0x75, 0xd0, 0x49, - 0x46, 0xf0, 0x26, 0x72, - 0xa7, 0x49, 0x43, 0xf0, - 0x22, 0x72, 0x25, 0x25, - 0x20, 0x1f, 0x97, 0x30, - 0x91, 0x30, 0x40, 0x73, - 0xf3, 0xc4, 0x1c, 0x40, - 0x04, 0xf0, 0xd7, 0x49, - 0x05, 0xf1, 0x37, 0xe0, - 0x53, 0x48, 0xc0, 0x9d, - 0x08, 0x02, 0x40, 0x66, - 0x64, 0x27, 0x06, 0x16, - 0x30, 0xf1, 0x46, 0x63, - 0x3b, 0x13, 0x2d, 0xf1, - 0x34, 0x9b, 0x18, 0x1b, - 0x93, 0x30, 0x2b, 0xc3, - 0x10, 0x1c, 0x2b, 0xe8, - 0x01, 0x14, 0x25, 0xf1, - 0x00, 0x1d, 0x26, 0x1a, - 0x8a, 0x30, 0x22, 0x73, - 0xb5, 0x25, 0x0e, 0x0b, - 0x00, 0x1c, 0x2c, 0xe8, - 0x1f, 0xc7, 0x27, 0x40, - 0x1a, 0xf1, 0x38, 0xe8, - 0x32, 0x1f, 0x8f, 0x30, - 0x08, 0x1b, 0x24, 0xe8, - 0x36, 0x72, 0x46, 0x77, - 0x00, 0x17, 0x0d, 0xf0, - 0x13, 0xc3, 0x1f, 0x40, - 0x03, 0xf1, 0x00, 0x1f, - 0x46, 0x9f, 0x44, 0x77, - 0x9f, 0x44, 0x5f, 0x44, - 0x17, 0xe8, 0x0a, 0xc7, - 0x27, 0x40, 0x05, 0xf1, - 0x02, 0xc3, 0x00, 0xbb, - 0xbe, 0x1a, 0x74, 0x14, - 0xff, 0xc7, 0x00, 0xbf, - 0xb8, 0xcd, 0xff, 0xff, - 0x02, 0x0c, 0x54, 0xa5, - 0xdc, 0xa5, 0x2f, 0x40, - 0x05, 0xf1, 0x00, 0x14, - 0xfa, 0xf1, 0x01, 0x1c, - 0x02, 0xe0, 0x00, 0x1c, - 0x80, 0xff, 0xb0, 0x49, - 0x04, 0xf0, 0x01, 0x0b, - 0xd3, 0xa1, 0x03, 0xe0, - 0x02, 0x0b, 0xd3, 0xa5, - 0x27, 0x31, 0x20, 0x37, - 0x02, 0x0b, 0xd3, 0xa5, - 0x27, 0x31, 0x20, 0x37, - 0x00, 0x13, 0xfb, 0xf1, - 0x80, 0xff, 0x22, 0x73, - 0xb5, 0x25, 0x18, 0x1e, - 0xde, 0x30, 0xd9, 0x30, - 0x64, 0x72, 0x11, 0x1e, - 0x68, 0x23, 0x16, 0x31, - 0x80, 0xff, 0x08, 0xc2, - 0x40, 0x73, 0x3a, 0x48, - 0x40, 0x9b, 0x06, 0xff, - 0x02, 0xc6, 0x00, 0xbe, - 0xcc, 0x17, 0x1e, 0xfc, - 0x2c, 0x75, 0xdc, 0x21, - 0xbc, 0x25, 0x04, 0x13, - 0x0b, 0xf0, 0x03, 0x13, - 0x09, 0xf0, 0x02, 0x13, - 0x07, 0xf0, 0x01, 0x13, - 0x05, 0xf0, 0x08, 0x13, - 0x03, 0xf0, 0x04, 0xc3, - 0x00, 0xbb, 0x03, 0xc3, - 0x00, 0xbb, 0x50, 0x17, - 0x3a, 0x17, 0x02, 0xc6, - 0x00, 0xbe, 0x00, 0x00, - 0x02, 0xc6, 0x00, 0xbe, - 0x00, 0x00, 0x33, 0xc5, - 0xa0, 0x74, 0xc0, 0x49, - 0x1f, 0xf0, 0x30, 0xc5, - 0xa0, 0x73, 0x00, 0x13, - 0x04, 0xf1, 0xa2, 0x73, - 0x00, 0x13, 0x14, 0xf0, - 0x28, 0xc5, 0xa0, 0x74, - 0xc8, 0x49, 0x1b, 0xf1, - 0x26, 0xc5, 0xa0, 0x76, - 0xa2, 0x74, 0x01, 0x06, - 0x20, 0x37, 0xa0, 0x9e, - 0xa2, 0x9c, 0x1e, 0xc5, - 0xa2, 0x73, 0x23, 0x40, - 0x10, 0xf8, 0x04, 0xf3, - 0xa0, 0x73, 0x33, 0x40, - 0x0c, 0xf8, 0x15, 0xc5, - 0xa0, 0x74, 0x41, 0x48, - 0xa0, 0x9c, 0x14, 0xc5, - 0xa0, 0x76, 0x62, 0x48, - 0xe0, 0x48, 0xa0, 0x9e, - 0x10, 0xc6, 0x00, 0xbe, - 0x0a, 0xc5, 0xa0, 0x74, - 0x48, 0x48, 0xa0, 0x9c, - 0x0b, 0xc5, 0x20, 0x1e, - 0xa0, 0x9e, 0xe5, 0x48, - 0xa0, 0x9e, 0xf0, 0xe7, - 0xbc, 0xc0, 0xc8, 0xd2, - 0xcc, 0xd2, 0x28, 0xe4, - 0xfa, 0x01, 0xf0, 0xc0, - 0x18, 0x89, 0x00, 0x1d, - 0x5a, 0xc0, 0x5a, 0xc1, - 0x02, 0x99, 0x00, 0x61, - 0x67, 0x11, 0x35, 0xf1, - 0x69, 0x33, 0x55, 0xc0, - 0x28, 0x40, 0xf7, 0xf1, - 0x54, 0xc0, 0x00, 0x19, - 0x81, 0x1b, 0x44, 0xe8, - 0x53, 0xc0, 0x04, 0x1a, - 0x84, 0x1b, 0x40, 0xe8, - 0x35, 0xe8, 0xa3, 0x49, - 0xfe, 0xf0, 0x4a, 0xc0, - 0x31, 0xe8, 0xa1, 0x48, - 0x47, 0xc0, 0x84, 0x1b, - 0x37, 0xe8, 0x00, 0x1d, - 0x69, 0x33, 0x00, 0x1e, - 0x01, 0x06, 0xff, 0x18, - 0x30, 0x40, 0xfd, 0xf1, - 0x40, 0xc0, 0x00, 0x76, - 0x2e, 0x40, 0xf7, 0xf1, - 0x21, 0x48, 0x38, 0xc0, - 0x84, 0x1b, 0x28, 0xe8, - 0x36, 0xc0, 0x1c, 0xe8, - 0xa1, 0x49, 0xfd, 0xf0, - 0x33, 0xc0, 0x00, 0x1a, - 0x84, 0x1b, 0x20, 0xe8, - 0x15, 0xe8, 0xa5, 0x49, - 0xfe, 0xf0, 0x29, 0xc0, - 0x01, 0x19, 0x81, 0x1b, - 0x19, 0xe8, 0x0b, 0xe0, - 0x9c, 0x20, 0x9c, 0x24, - 0x06, 0x11, 0x07, 0xf1, - 0x25, 0xc0, 0x08, 0xe8, - 0x23, 0xc0, 0x12, 0x48, - 0x81, 0x1b, 0x0e, 0xe8, - 0x02, 0xc0, 0x00, 0xb8, - 0xd6, 0x07, 0x16, 0xc4, - 0x84, 0x98, 0x00, 0x1b, - 0x86, 0x8b, 0x86, 0x73, - 0xbf, 0x49, 0xfe, 0xf1, - 0x80, 0x71, 0x82, 0x72, - 0x80, 0xff, 0x0c, 0xc4, - 0x84, 0x98, 0x80, 0x99, - 0x82, 0x9a, 0x86, 0x8b, - 0x86, 0x73, 0xbf, 0x49, - 0xfe, 0xf1, 0x80, 0xff, - 0x50, 0xe8, 0x82, 0x00, - 0xb8, 0x0b, 0x08, 0xea, - 0x20, 0xb4, 0x84, 0xd4, - 0x10, 0xd4, 0x10, 0xd8, - 0x88, 0xd3, 0x30, 0xd4, - 0x02, 0xc0, 0x00, 0xb8, - 0xe0, 0x08, 0x00, 0x00 }; - - ocp_write_word(tp, MCU_TYPE_USB, USB_BP_EN, 0x0000); - generic_ocp_write(tp, 0xf800, 0xff, sizeof(usb_patch_c), - usb_patch_c, MCU_TYPE_USB); - ocp_write_word(tp, MCU_TYPE_USB, 0xfc26, 0xa000); - ocp_write_word(tp, MCU_TYPE_USB, 0xfc28, 0x3b34); - ocp_write_word(tp, MCU_TYPE_USB, 0xfc2a, 0x027c); - ocp_write_word(tp, MCU_TYPE_USB, 0xfc2c, 0x1634); - ocp_write_word(tp, MCU_TYPE_USB, 0xfc2e, 0x10d6); - ocp_write_word(tp, MCU_TYPE_USB, 0xfc30, 0x0000); - ocp_write_word(tp, MCU_TYPE_USB, 0xfc32, 0x0000); - ocp_write_word(tp, MCU_TYPE_USB, 0xfc34, 0x0000); - ocp_write_word(tp, MCU_TYPE_USB, 0xfc36, 0x0000); - if (ocp_read_byte(tp, MCU_TYPE_USB, 0xcfef) & 1) { - ocp_write_word(tp, MCU_TYPE_USB, 0xfc30, 0x1578); - ocp_write_word(tp, MCU_TYPE_USB, USB_BP_EN, 0x001F); - } else { - ocp_write_word(tp, MCU_TYPE_USB, USB_BP_EN, 0x000F); - } - - ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_EN, 0x0000); - generic_ocp_write(tp, 0xf800, 0xff, sizeof(pla_patch_c), - pla_patch_c, MCU_TYPE_PLA); - ocp_write_word(tp, MCU_TYPE_PLA, 0xfc26, 0x8000); - ocp_write_word(tp, MCU_TYPE_PLA, 0xfc28, 0x1306); - ocp_write_word(tp, MCU_TYPE_PLA, 0xfc2a, 0x17ca); - ocp_write_word(tp, MCU_TYPE_PLA, 0xfc2c, 0x171e); - ocp_write_word(tp, MCU_TYPE_PLA, 0xfc2e, 0x0000); - ocp_write_word(tp, MCU_TYPE_PLA, 0xfc30, 0x0000); - ocp_write_word(tp, MCU_TYPE_PLA, 0xfc32, 0x01b4); - ocp_write_word(tp, MCU_TYPE_PLA, 0xfc34, 0x07d4); - ocp_write_word(tp, MCU_TYPE_PLA, 0xfc36, 0x0894); - ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_EN, 0x00e7); - - ocp_write_word(tp, MCU_TYPE_PLA, 0xd388, 0x08ca); - - ocp_data = ocp_read_word(tp, MCU_TYPE_USB, 0xcfca); - ocp_data |= 0x4000; - ocp_write_word(tp, MCU_TYPE_USB, 0xcfca, ocp_data); - } -} - -static void r8153_hw_phy_cfg(struct r8152 *tp) -{ - u32 ocp_data; - u16 data; - - ocp_reg_write(tp, OCP_ADC_CFG, CKADSEL_L | ADC_EN | EN_EMI_L); - data = r8152_mdio_read(tp, MII_BMCR); - if (data & BMCR_PDOWN) { - data &= ~BMCR_PDOWN; - r8152_mdio_write(tp, MII_BMCR, data); - } - - r8153_firmware(tp); - - if (tp->version == RTL_VER_03) { - data = ocp_reg_read(tp, OCP_EEE_CFG); - data &= ~CTAP_SHORT_EN; - ocp_reg_write(tp, OCP_EEE_CFG, data); - } - - data = ocp_reg_read(tp, OCP_POWER_CFG); - data |= EEE_CLKDIV_EN; - ocp_reg_write(tp, OCP_POWER_CFG, data); - - data = ocp_reg_read(tp, OCP_DOWN_SPEED); - data |= EN_10M_BGOFF; - ocp_reg_write(tp, OCP_DOWN_SPEED, data); - data = ocp_reg_read(tp, OCP_POWER_CFG); - data |= EN_10M_PLLOFF; - ocp_reg_write(tp, OCP_POWER_CFG, data); - data = sram_read(tp, SRAM_IMPEDANCE); - data &= ~RX_DRIVING_MASK; - sram_write(tp, SRAM_IMPEDANCE, data); - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR); - ocp_data |= PFM_PWM_SWITCH; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data); - - data = sram_read(tp, SRAM_LPF_CFG); - data |= LPF_AUTO_TUNE; - sram_write(tp, SRAM_LPF_CFG, data); - - data = sram_read(tp, SRAM_10M_AMP1); - data |= GDAC_IB_UPALL; - sram_write(tp, SRAM_10M_AMP1, data); - data = sram_read(tp, SRAM_10M_AMP2); - data |= AMP_DN; - sram_write(tp, SRAM_10M_AMP2, data); - - set_bit(PHY_RESET, &tp->flags); -} - -static void r8153_u1u2en(struct r8152 *tp, bool enable) -{ - u8 u1u2[8]; - - if (enable) - memset(u1u2, 0xff, sizeof(u1u2)); - else - memset(u1u2, 0x00, sizeof(u1u2)); - - usb_ocp_write(tp, USB_TOLERANCE, BYTE_EN_SIX_BYTES, sizeof(u1u2), u1u2); -} - -static void r8153_u2p3en(struct r8152 *tp, bool enable) -{ - u32 ocp_data; - - ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL); - if (enable) - ocp_data |= U2P3_ENABLE; - else - ocp_data &= ~U2P3_ENABLE; - ocp_write_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL, ocp_data); -} - -static void r8153_power_cut_en(struct r8152 *tp, bool enable) -{ - u32 ocp_data; - - ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_POWER_CUT); - if (enable) - ocp_data |= PWR_EN | PHASE2_EN; - else - ocp_data &= ~(PWR_EN | PHASE2_EN); - ocp_write_word(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data); - - ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0); - ocp_data &= ~PCUT_STATUS; - ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data); -} - -static void r8153_first_init(struct r8152 *tp) -{ - u32 ocp_data; - int i; - - rxdy_gated_en(tp, true); - r8153_teredo_off(tp); - - ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); - ocp_data &= ~RCR_ACPT_ALL; - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); - - r8153_hw_phy_cfg(tp); - - rtl8152_nic_reset(tp); - - ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); - ocp_data &= ~NOW_IS_OOB; - ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data); - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7); - ocp_data &= ~MCU_BORW_EN; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data); - - for (i = 0; i < 1000; i++) { - ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); - if (ocp_data & LINK_LIST_READY) - break; - usleep_range(1000, 2000); - } - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7); - ocp_data |= RE_INIT_LL; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data); - - for (i = 0; i < 1000; i++) { - ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); - if (ocp_data & LINK_LIST_READY) - break; - usleep_range(1000, 2000); - } - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CPCR); - ocp_data &= ~CPCR_RX_VLAN; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data); - - ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8153_RMS); - ocp_write_byte(tp, MCU_TYPE_PLA, PLA_MTPS, MTPS_JUMBO); - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR0); - ocp_data |= TCR0_AUTO_FIFO; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_TCR0, ocp_data); - - rtl8152_nic_reset(tp); - - /* rx share fifo credit full threshold */ - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_NORMAL); - ocp_write_word(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1, RXFIFO_THR2_NORMAL); - ocp_write_word(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2, RXFIFO_THR3_NORMAL); - /* TX share fifo free credit full threshold */ - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, TXFIFO_THR_NORMAL2); - - /* rx aggregation */ - ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL); - ocp_data &= ~RX_AGG_DISABLE; - ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data); -} - -static void r8153_enter_oob(struct r8152 *tp) -{ - u32 ocp_data; - int i; - - ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); - ocp_data &= ~NOW_IS_OOB; - ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data); - - rtl_disable(tp); - - for (i = 0; i < 1000; i++) { - ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); - if (ocp_data & LINK_LIST_READY) - break; - usleep_range(1000, 2000); - } - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7); - ocp_data |= RE_INIT_LL; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data); - - for (i = 0; i < 1000; i++) { - ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); - if (ocp_data & LINK_LIST_READY) - break; - usleep_range(1000, 2000); - } - - ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8153_RMS); - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG); - ocp_data &= ~TEREDO_WAKE_MASK; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data); - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CPCR); - ocp_data |= CPCR_RX_VLAN; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data); - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PAL_BDC_CR); - ocp_data |= ALDPS_PROXY_MODE; - ocp_write_word(tp, MCU_TYPE_PLA, PAL_BDC_CR, ocp_data); - - ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); - ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB; - ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data); - - rxdy_gated_en(tp, false); - - ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); - ocp_data |= RCR_APM | RCR_AM | RCR_AB; - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); -} - -static void r8153_disable_aldps(struct r8152 *tp) -{ - u16 data; - - data = ocp_reg_read(tp, OCP_POWER_CFG); - data &= ~EN_ALDPS; - ocp_reg_write(tp, OCP_POWER_CFG, data); - msleep(20); -} - -static void r8153_enable_aldps(struct r8152 *tp) -{ - u16 data; - - data = ocp_reg_read(tp, OCP_POWER_CFG); - data |= EN_ALDPS; - ocp_reg_write(tp, OCP_POWER_CFG, data); -} - -static void rtl8153_disable(struct r8152 *tp) -{ - r8153_disable_aldps(tp); - rtl_disable(tp); - r8153_enable_aldps(tp); -} - -static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex) -{ - u16 bmcr, anar, gbcr; - int ret = 0; - - cancel_delayed_work_sync(&tp->schedule); - anar = r8152_mdio_read(tp, MII_ADVERTISE); - anar &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL | - ADVERTISE_100HALF | ADVERTISE_100FULL); - if (tp->mii.supports_gmii) { - gbcr = r8152_mdio_read(tp, MII_CTRL1000); - gbcr &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); - } else { - gbcr = 0; - } - - if (autoneg == AUTONEG_DISABLE) { - if (speed == SPEED_10) { - bmcr = 0; - anar |= ADVERTISE_10HALF | ADVERTISE_10FULL; - } else if (speed == SPEED_100) { - bmcr = BMCR_SPEED100; - anar |= ADVERTISE_100HALF | ADVERTISE_100FULL; - } else if (speed == SPEED_1000 && tp->mii.supports_gmii) { - bmcr = BMCR_SPEED1000; - gbcr |= ADVERTISE_1000FULL | ADVERTISE_1000HALF; - } else { - ret = -EINVAL; - goto out; - } - - if (duplex == DUPLEX_FULL) - bmcr |= BMCR_FULLDPLX; - } else { - if (speed == SPEED_10) { - if (duplex == DUPLEX_FULL) - anar |= ADVERTISE_10HALF | ADVERTISE_10FULL; - else - anar |= ADVERTISE_10HALF; - } else if (speed == SPEED_100) { - if (duplex == DUPLEX_FULL) { - anar |= ADVERTISE_10HALF | ADVERTISE_10FULL; - anar |= ADVERTISE_100HALF | ADVERTISE_100FULL; - } else { - anar |= ADVERTISE_10HALF; - anar |= ADVERTISE_100HALF; - } - } else if (speed == SPEED_1000 && tp->mii.supports_gmii) { - if (duplex == DUPLEX_FULL) { - anar |= ADVERTISE_10HALF | ADVERTISE_10FULL; - anar |= ADVERTISE_100HALF | ADVERTISE_100FULL; - gbcr |= ADVERTISE_1000FULL | ADVERTISE_1000HALF; - } else { - anar |= ADVERTISE_10HALF; - anar |= ADVERTISE_100HALF; - gbcr |= ADVERTISE_1000HALF; - } - } else { - ret = -EINVAL; - goto out; - } - - bmcr = BMCR_ANENABLE | BMCR_ANRESTART; - } - - if (test_bit(PHY_RESET, &tp->flags)) - bmcr |= BMCR_RESET; - - if (tp->mii.supports_gmii) - r8152_mdio_write(tp, MII_CTRL1000, gbcr); - - r8152_mdio_write(tp, MII_ADVERTISE, anar); - r8152_mdio_write(tp, MII_BMCR, bmcr); - - if (test_bit(PHY_RESET, &tp->flags)) { - int i; - - clear_bit(PHY_RESET, &tp->flags); - for (i = 0; i < 50; i++) { - msleep(20); - if ((r8152_mdio_read(tp, MII_BMCR) & BMCR_RESET) == 0) - break; - } - } - -out: - - return ret; -} - -static void rtl8152_up(struct r8152 *tp) -{ - if (test_bit(RTL8152_UNPLUG, &tp->flags)) - return; - - r8152b_disable_aldps(tp); - r8152b_exit_oob(tp); - r8152b_enable_aldps(tp); -} - -static void rtl8152_down(struct r8152 *tp) -{ - if (test_bit(RTL8152_UNPLUG, &tp->flags)) { - rtl_drop_queued_tx(tp); - return; - } - - r8152_power_cut_en(tp, false); - r8152b_disable_aldps(tp); - r8152b_enter_oob(tp); - r8152b_enable_aldps(tp); - if (tp->version == RTL_VER_01) - rtl8152_set_speed(tp, AUTONEG_ENABLE, SPEED_10, DUPLEX_FULL); -} - -static void rtl8153_up(struct r8152 *tp) -{ - if (test_bit(RTL8152_UNPLUG, &tp->flags)) - return; - - r8153_disable_aldps(tp); - r8153_first_init(tp); - r8153_enable_aldps(tp); -} - -static void rtl8153_down(struct r8152 *tp) -{ - if (test_bit(RTL8152_UNPLUG, &tp->flags)) { - rtl_drop_queued_tx(tp); - return; - } - - r8153_u1u2en(tp, false); - r8153_power_cut_en(tp, false); - r8153_disable_aldps(tp); - r8153_enter_oob(tp); - r8153_enable_aldps(tp); -} - -static void set_carrier(struct r8152 *tp) -{ - struct net_device *netdev = tp->netdev; - u8 speed; - - clear_bit(RTL8152_LINK_CHG, &tp->flags); - speed = rtl8152_get_speed(tp); - - if (speed & LINK_STATUS) { - if (!(tp->speed & LINK_STATUS)) { - tp->rtl_ops.enable(tp); - set_bit(RTL8152_SET_RX_MODE, &tp->flags); - netif_carrier_on(netdev); - } - } else { - if (tp->speed & LINK_STATUS) { - netif_carrier_off(netdev); - tasklet_disable(&tp->tl); - tp->rtl_ops.disable(tp); - tasklet_enable(&tp->tl); - } - } - tp->speed = speed; -} - -static inline void __rtl_work_func(struct r8152 *tp) -{ - if (usb_autopm_get_interface(tp->intf) < 0) - return; - - if (!test_bit(WORK_ENABLE, &tp->flags)) - goto out1; - - if (test_bit(RTL8152_UNPLUG, &tp->flags)) - goto out1; - - if (test_bit(RTL8152_LINK_CHG, &tp->flags)) - set_carrier(tp); - - if (test_bit(RTL8152_SET_RX_MODE, &tp->flags)) - rtl8152_set_rx_mode(tp->netdev); - - /* don't schedule tasklet before linking */ - if (test_bit(SCHEDULE_TASKLET, &tp->flags) && - (tp->speed & LINK_STATUS)) { - clear_bit(SCHEDULE_TASKLET, &tp->flags); - tasklet_schedule(&tp->tl); - } - - if (test_bit(PHY_RESET, &tp->flags)) - rtl_phy_reset(tp); - -out1: - usb_autopm_put_interface(tp->intf); -} - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) - -static void rtl_work_func_t(void *data) -{ - struct r8152 *tp = (struct r8152 *)data; - - __rtl_work_func(tp); -} - -#else - -static void rtl_work_func_t(struct work_struct *work) -{ - struct r8152 *tp = container_of(work, struct r8152, schedule.work); - - __rtl_work_func(tp); -} - -#endif - -static int rtl8152_open(struct net_device *netdev) -{ - struct r8152 *tp = netdev_priv(netdev); - int res = 0; - - res = alloc_all_mem(tp); - if (res) - goto out; - - res = usb_autopm_get_interface(tp->intf); - if (res < 0) { - free_all_mem(tp); - goto out; - } - - /* The WORK_ENABLE may be set when autoresume occurs */ - if (test_bit(WORK_ENABLE, &tp->flags)) { - clear_bit(WORK_ENABLE, &tp->flags); - usb_kill_urb(tp->intr_urb); - cancel_delayed_work_sync(&tp->schedule); - if (tp->speed & LINK_STATUS) - tp->rtl_ops.disable(tp); - } - - tp->rtl_ops.up(tp); - - rtl8152_set_speed(tp, AUTONEG_ENABLE, - tp->mii.supports_gmii ? SPEED_1000 : SPEED_100, - DUPLEX_FULL); - tp->speed = 0; - netif_carrier_off(netdev); - netif_start_queue(netdev); - set_bit(WORK_ENABLE, &tp->flags); - - res = usb_submit_urb(tp->intr_urb, GFP_KERNEL); - if (res) { - if (res == -ENODEV) - netif_device_detach(tp->netdev); - netif_warn(tp, ifup, netdev, "intr_urb submit failed: %d\n", - res); - free_all_mem(tp); - } - - usb_autopm_put_interface(tp->intf); - -out: - return res; -} - -static int rtl8152_close(struct net_device *netdev) -{ - struct r8152 *tp = netdev_priv(netdev); - int res = 0; - - clear_bit(WORK_ENABLE, &tp->flags); - usb_kill_urb(tp->intr_urb); - cancel_delayed_work_sync(&tp->schedule); - netif_stop_queue(netdev); - - res = usb_autopm_get_interface(tp->intf); - if (res < 0) { - rtl_drop_queued_tx(tp); - } else { - /* The autosuspend may have been enabled and wouldn't - * be disable when autoresume occurs, because the - * netif_running() would be false. - */ - if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { - rtl_runtime_suspend_enable(tp, false); - clear_bit(SELECTIVE_SUSPEND, &tp->flags); - } - - tasklet_disable(&tp->tl); - tp->rtl_ops.down(tp); - tasklet_enable(&tp->tl); - usb_autopm_put_interface(tp->intf); - } - - free_all_mem(tp); - - return res; -} - -static void patch4(struct r8152 *tp) -{ - u8 data; - - data = ocp_read_byte(tp, MCU_TYPE_USB, 0xd429); - data |= 0x80; - ocp_write_byte(tp, MCU_TYPE_USB, 0xd429, data); - ocp_write_word(tp, MCU_TYPE_USB, 0xc0ce, 0x0210); - data = ocp_read_byte(tp, MCU_TYPE_USB, 0xd429); - data &= ~0x80; - ocp_write_byte(tp, MCU_TYPE_USB, 0xd429, data); -} - -static void r8152b_enable_eee(struct r8152 *tp) -{ - u32 ocp_data; - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEE_CR); - ocp_data |= EEE_RX_EN | EEE_TX_EN; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEE_CR, ocp_data); - ocp_reg_write(tp, OCP_EEE_CONFIG1, RG_TXLPI_MSK_HFDUP | RG_MATCLR_EN | - EEE_10_CAP | EEE_NWAY_EN | - TX_QUIET_EN | RX_QUIET_EN | - SDRISETIME | RG_RXLPI_MSK_HFDUP | - SDFALLTIME); - ocp_reg_write(tp, OCP_EEE_CONFIG2, RG_LPIHYS_NUM | RG_DACQUIET_EN | - RG_LDVQUIET_EN | RG_CKRSEL | - RG_EEEPRG_EN); - ocp_reg_write(tp, OCP_EEE_CONFIG3, FST_SNR_EYE_R | RG_LFS_SEL | MSK_PH); - ocp_reg_write(tp, OCP_EEE_AR, FUN_ADDR | DEVICE_ADDR); - ocp_reg_write(tp, OCP_EEE_DATA, EEE_ADDR); - ocp_reg_write(tp, OCP_EEE_AR, FUN_DATA | DEVICE_ADDR); - ocp_reg_write(tp, OCP_EEE_DATA, EEE_DATA); - ocp_reg_write(tp, OCP_EEE_AR, 0x0000); -} - -static void r8153_enable_eee(struct r8152 *tp) -{ - u32 ocp_data; - u16 data; - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEE_CR); - ocp_data |= EEE_RX_EN | EEE_TX_EN; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEE_CR, ocp_data); - data = ocp_reg_read(tp, OCP_EEE_CFG); - data |= EEE10_EN; - ocp_reg_write(tp, OCP_EEE_CFG, data); - data = ocp_reg_read(tp, OCP_EEE_CFG2); - data |= MY1000_EEE | MY100_EEE; - ocp_reg_write(tp, OCP_EEE_CFG2, data); -} - -static void r8152b_enable_fc(struct r8152 *tp) -{ - u16 anar; - - anar = r8152_mdio_read(tp, MII_ADVERTISE); - anar |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; - r8152_mdio_write(tp, MII_ADVERTISE, anar); -} - -static void rtl_tally_reset(struct r8152 *tp) -{ - u32 ocp_data; - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY); - ocp_data |= TALLY_RESET; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY, ocp_data); -} - -static void r8152b_init(struct r8152 *tp) -{ - u32 ocp_data; - - if (test_bit(RTL8152_UNPLUG, &tp->flags)) - return; - - r8152b_disable_aldps(tp); -#if 0 - /* Clear EP3 Fifo before using interrupt transfer */ - if (ocp_read_byte(tp, MCU_TYPE_USB, 0xb963) & 0x80) { - ocp_write_byte(tp, MCU_TYPE_USB, 0xb963, 0x08); - ocp_write_byte(tp, MCU_TYPE_USB, 0xb963, 0x40); - ocp_write_byte(tp, MCU_TYPE_USB, 0xb963, 0x00); - ocp_write_byte(tp, MCU_TYPE_USB, 0xb968, 0x00); - ocp_write_word(tp, MCU_TYPE_USB, 0xb010, 0x00e0); - ocp_write_byte(tp, MCU_TYPE_USB, 0xb963, 0x04); - } -#endif - - if (tp->version == RTL_VER_01) { - patch4(tp); - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE); - ocp_data &= ~LED_MODE_MASK; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data); - } - - r8152_power_cut_en(tp, false); - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR); - ocp_data |= TX_10M_IDLE_EN | PFM_PWM_SWITCH; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data); - ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL); - ocp_data &= ~MCU_CLK_RATIO_MASK; - ocp_data |= MCU_CLK_RATIO | D3_CLK_GATED_EN; - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL, ocp_data); - ocp_data = GPHY_STS_MSK | SPEED_DOWN_MSK | - SPDWN_RXDV_MSK | SPDWN_LINKCHG_MSK; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_GPHY_INTR_IMR, ocp_data); - - r8152b_enable_eee(tp); - r8152b_enable_aldps(tp); - r8152b_enable_fc(tp); - rtl_tally_reset(tp); - -#if 0 - /* disable rx aggregation */ - ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL); - ocp_data |= RX_AGG_DISABLE; - ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data); -#else - /* enable rx aggregation */ - ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL); - ocp_data &= ~RX_AGG_DISABLE; - ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data); -#endif -} - -static void r8153_init(struct r8152 *tp) -{ - u32 ocp_data; - int i; - - if (test_bit(RTL8152_UNPLUG, &tp->flags)) - return; - - r8153_disable_aldps(tp); - r8153_u1u2en(tp, false); - - for (i = 0; i < 500; i++) { - if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) & - AUTOLOAD_DONE) - break; - msleep(20); - } - - for (i = 0; i < 500; i++) { - ocp_data = ocp_reg_read(tp, OCP_PHY_STATUS) & PHY_STAT_MASK; - if (ocp_data == PHY_STAT_LAN_ON || ocp_data == PHY_STAT_PWRDN) - break; - msleep(20); - } - - r8153_u2p3en(tp, false); - - if (tp->version == RTL_VER_04) { - ocp_data = ocp_read_word(tp, MCU_TYPE_USB, 0xb428); - ocp_data &= ~0x3fff; - ocp_data |= 0x012c; - ocp_write_word(tp, MCU_TYPE_USB, 0xb428, ocp_data); - - ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, 0xb41e); - ocp_data |= 0x03; - ocp_write_byte(tp, MCU_TYPE_USB, 0xb41e, ocp_data); - - ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, 0xb466); - ocp_data |= 0x01; - ocp_write_byte(tp, MCU_TYPE_USB, 0xb466, ocp_data); - } else if (tp->version == RTL_VER_05) { - ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, 0xc0b0); - ocp_data &= ~0x02; - ocp_write_byte(tp, MCU_TYPE_PLA, 0xc0b0, ocp_data); - - ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, 0xb466); - ocp_data |= 0x01; - ocp_write_byte(tp, MCU_TYPE_USB, 0xb466, ocp_data); - } - - ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL); - ocp_data &= ~TIMER11_EN; - ocp_write_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL, ocp_data); - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE); - ocp_data &= ~LED_MODE_MASK; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data); - - ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_LPM_CTRL); - ocp_data &= ~LPM_TIMER_MASK; - if (tp->version == RTL_VER_04 && tp->udev->speed != USB_SPEED_SUPER) - ocp_data |= LPM_TIMER_500MS; - else - ocp_data |= LPM_TIMER_500US; - ocp_write_byte(tp, MCU_TYPE_USB, USB_LPM_CTRL, ocp_data); - - ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_AFE_CTRL2); - ocp_data &= ~SEN_VAL_MASK; - ocp_data |= SEN_VAL_NORMAL | SEL_RXIDLE; - ocp_write_word(tp, MCU_TYPE_USB, USB_AFE_CTRL2, ocp_data); - - r8153_power_cut_en(tp, false); - ocp_write_word(tp, MCU_TYPE_USB, 0xcbf8, 0x0001); - r8153_u1u2en(tp, true); - - ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL, ALDPS_SPDWN_RATIO); - ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2, EEE_SPDWN_RATIO); - ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, - PKT_AVAIL_SPDWN_EN | SUSPEND_SPDWN_EN | - U1U2_SPDWN_EN | L1_SPDWN_EN); - ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4, - PWRSAVE_SPDWN_EN | RXDV_SPDWN_EN | TX10MIDLE_EN | - TP100_SPDWN_EN | TP500_SPDWN_EN | TP1000_SPDWN_EN | - EEE_SPDWN_EN); - - r8153_enable_eee(tp); - r8153_enable_aldps(tp); - r8152b_enable_fc(tp); - rtl_tally_reset(tp); -} - -static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct r8152 *tp = usb_get_intfdata(intf); - - if (PMSG_IS_AUTO(message)) - set_bit(SELECTIVE_SUSPEND, &tp->flags); - else - netif_device_detach(tp->netdev); - - if (netif_running(tp->netdev)) { - clear_bit(WORK_ENABLE, &tp->flags); - usb_kill_urb(tp->intr_urb); - cancel_delayed_work_sync(&tp->schedule); - if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { - rtl_runtime_suspend_enable(tp, true); - } else { - tasklet_disable(&tp->tl); - tp->rtl_ops.down(tp); - tasklet_enable(&tp->tl); - } - } - - return 0; -} - -static int rtl8152_resume(struct usb_interface *intf) -{ - struct r8152 *tp = usb_get_intfdata(intf); - - if (!test_bit(SELECTIVE_SUSPEND, &tp->flags)) { - tp->rtl_ops.init(tp); - netif_device_attach(tp->netdev); - } - - if (netif_running(tp->netdev)) { - if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { - rtl_runtime_suspend_enable(tp, false); - clear_bit(SELECTIVE_SUSPEND, &tp->flags); - if (tp->speed & LINK_STATUS) - tp->rtl_ops.disable(tp); - } else { - tp->rtl_ops.up(tp); - rtl8152_set_speed(tp, AUTONEG_ENABLE, - tp->mii.supports_gmii ? - SPEED_1000 : SPEED_100, - DUPLEX_FULL); - } - tp->speed = 0; - netif_carrier_off(tp->netdev); - set_bit(WORK_ENABLE, &tp->flags); - usb_submit_urb(tp->intr_urb, GFP_KERNEL); - } - - return 0; -} - -static void rtl8152_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) -{ - struct r8152 *tp = netdev_priv(dev); - - if (usb_autopm_get_interface(tp->intf) < 0) - return; - - wol->supported = WAKE_ANY; - wol->wolopts = __rtl_get_wol(tp); - - usb_autopm_put_interface(tp->intf); -} - -static int rtl8152_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) -{ - struct r8152 *tp = netdev_priv(dev); - int ret; - - ret = usb_autopm_get_interface(tp->intf); - if (ret < 0) - goto out_set_wol; - - __rtl_set_wol(tp, wol->wolopts); - tp->saved_wolopts = wol->wolopts & WAKE_ANY; - - usb_autopm_put_interface(tp->intf); - -out_set_wol: - return ret; -} - -static u32 rtl8152_get_msglevel(struct net_device *dev) -{ - struct r8152 *tp = netdev_priv(dev); - - return tp->msg_enable; -} - -static void rtl8152_set_msglevel(struct net_device *dev, u32 value) -{ - struct r8152 *tp = netdev_priv(dev); - - tp->msg_enable = value; -} - -static void rtl8152_get_drvinfo(struct net_device *netdev, - struct ethtool_drvinfo *info) -{ - struct r8152 *tp = netdev_priv(netdev); - - strlcpy(info->driver, MODULENAME, sizeof(info->driver)); - strlcpy(info->version, DRIVER_VERSION, sizeof(info->version)); - usb_make_path(tp->udev, info->bus_info, sizeof(info->bus_info)); -} - -static -int rtl8152_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd) -{ - struct r8152 *tp = netdev_priv(netdev); - u16 bmcr, bmsr, ctrl1000 = 0, stat1000 = 0; - int ret; - - ret = usb_autopm_get_interface(tp->intf); - if (ret < 0) - goto out; - - cmd->supported = - (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | - SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | - SUPPORTED_Autoneg | SUPPORTED_MII); - if (tp->mii.supports_gmii) - cmd->supported |= SUPPORTED_1000baseT_Half | - SUPPORTED_1000baseT_Full; - - /* only supports twisted-pair */ - cmd->port = PORT_MII; - - /* only supports internal transceiver */ - cmd->transceiver = XCVR_INTERNAL; - cmd->phy_address = 32; -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30) - cmd->mdio_support = ETH_MDIO_SUPPORTS_C22; -#endif - cmd->advertising = ADVERTISED_MII; - - bmcr = r8152_mdio_read(tp, MII_BMCR); - bmsr = r8152_mdio_read(tp, MII_BMSR); - if (tp->mii.supports_gmii) { - ctrl1000 = r8152_mdio_read(tp, MII_CTRL1000); - stat1000 = r8152_mdio_read(tp, MII_STAT1000); - } - - if (bmcr & BMCR_ANENABLE) { - int advert; - - cmd->advertising |= ADVERTISED_Autoneg; - cmd->autoneg = AUTONEG_ENABLE; - - advert = r8152_mdio_read(tp, MII_ADVERTISE); - if (advert & ADVERTISE_10HALF) - cmd->advertising |= ADVERTISED_10baseT_Half; - if (advert & ADVERTISE_10FULL) - cmd->advertising |= ADVERTISED_10baseT_Full; - if (advert & ADVERTISE_100HALF) - cmd->advertising |= ADVERTISED_100baseT_Half; - if (advert & ADVERTISE_100FULL) - cmd->advertising |= ADVERTISED_100baseT_Full; - if (advert & ADVERTISE_PAUSE_CAP) - cmd->advertising |= ADVERTISED_Pause; - if (advert & ADVERTISE_PAUSE_ASYM) - cmd->advertising |= ADVERTISED_Asym_Pause; - if (tp->mii.supports_gmii) { - if (ctrl1000 & ADVERTISE_1000HALF) - cmd->advertising |= ADVERTISED_1000baseT_Half; - if (ctrl1000 & ADVERTISE_1000FULL) - cmd->advertising |= ADVERTISED_1000baseT_Full; - } - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) - if (bmsr & BMSR_ANEGCOMPLETE) { - advert = r8152_mdio_read(tp, MII_LPA); - if (advert & LPA_LPACK) - cmd->lp_advertising |= ADVERTISED_Autoneg; - if (advert & ADVERTISE_10HALF) - cmd->lp_advertising |= - ADVERTISED_10baseT_Half; - if (advert & ADVERTISE_10FULL) - cmd->lp_advertising |= - ADVERTISED_10baseT_Full; - if (advert & ADVERTISE_100HALF) - cmd->lp_advertising |= - ADVERTISED_100baseT_Half; - if (advert & ADVERTISE_100FULL) - cmd->lp_advertising |= - ADVERTISED_100baseT_Full; - - if (tp->mii.supports_gmii) { - if (stat1000 & LPA_1000HALF) - cmd->lp_advertising |= - ADVERTISED_1000baseT_Half; - if (stat1000 & LPA_1000FULL) - cmd->lp_advertising |= - ADVERTISED_1000baseT_Full; - } - } else { - cmd->lp_advertising = 0; - } -#endif - } else { - cmd->autoneg = AUTONEG_DISABLE; - } - - if (tp->speed & _100bps) - cmd->speed = SPEED_100; - else if (tp->speed & _10bps) - cmd->speed = SPEED_10; - else if (tp->mii.supports_gmii && tp->speed & _1000bps) - cmd->speed = SPEED_1000; - - cmd->duplex = (tp->speed & FULL_DUP) ? DUPLEX_FULL : DUPLEX_HALF; - - usb_autopm_put_interface(tp->intf); - -out: - return ret; -} - -static int rtl8152_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct r8152 *tp = netdev_priv(dev); - int ret; - - ret = usb_autopm_get_interface(tp->intf); - if (ret < 0) - goto out; - - ret = rtl8152_set_speed(tp, cmd->autoneg, cmd->speed, cmd->duplex); - - usb_autopm_put_interface(tp->intf); - -out: - return ret; -} - -static const char rtl8152_gstrings[][ETH_GSTRING_LEN] = { - "tx_packets", - "rx_packets", - "tx_errors", - "rx_errors", - "rx_missed", - "align_errors", - "tx_single_collisions", - "tx_multi_collisions", - "rx_unicast", - "rx_broadcast", - "rx_multicast", - "tx_aborted", - "tx_underrun", -}; - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33) -static int rtl8152_get_sset_count(struct net_device *dev) -{ - return ARRAY_SIZE(rtl8152_gstrings); -} -#else -static int rtl8152_get_sset_count(struct net_device *dev, int sset) -{ - switch (sset) { - case ETH_SS_STATS: - return ARRAY_SIZE(rtl8152_gstrings); - default: - return -EOPNOTSUPP; - } -} -#endif - -static void rtl8152_get_ethtool_stats(struct net_device *dev, - struct ethtool_stats *stats, u64 *data) -{ - struct r8152 *tp = netdev_priv(dev); - struct tally_counter tally; - - if (usb_autopm_get_interface(tp->intf) < 0) - return; - - generic_ocp_read(tp, PLA_TALLYCNT, sizeof(tally), &tally, MCU_TYPE_PLA); - - usb_autopm_put_interface(tp->intf); - - data[0] = le64_to_cpu(tally.tx_packets); - data[1] = le64_to_cpu(tally.rx_packets); - data[2] = le64_to_cpu(tally.tx_errors); - data[3] = le32_to_cpu(tally.rx_errors); - data[4] = le16_to_cpu(tally.rx_missed); - data[5] = le16_to_cpu(tally.align_errors); - data[6] = le32_to_cpu(tally.tx_one_collision); - data[7] = le32_to_cpu(tally.tx_multi_collision); - data[8] = le64_to_cpu(tally.rx_unicast); - data[9] = le64_to_cpu(tally.rx_broadcast); - data[10] = le32_to_cpu(tally.rx_multicast); - data[11] = le16_to_cpu(tally.tx_aborted); - data[12] = le16_to_cpu(tally.tx_underun); -} - -static void rtl8152_get_strings(struct net_device *dev, u32 stringset, u8 *data) -{ - switch (stringset) { - case ETH_SS_STATS: - memcpy(data, *rtl8152_gstrings, sizeof(rtl8152_gstrings)); - break; - } -} - -static struct ethtool_ops ops = { - .get_drvinfo = rtl8152_get_drvinfo, - .get_settings = rtl8152_get_settings, - .set_settings = rtl8152_set_settings, - .get_link = ethtool_op_get_link, - .get_msglevel = rtl8152_get_msglevel, - .set_msglevel = rtl8152_set_msglevel, - .get_wol = rtl8152_get_wol, - .set_wol = rtl8152_set_wol, - .get_strings = rtl8152_get_strings, - .get_sset_count = rtl8152_get_sset_count, - .get_ethtool_stats = rtl8152_get_ethtool_stats, -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0) - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, -#ifdef NETIF_F_TSO - .get_tso = ethtool_op_get_tso, - .set_tso = ethtool_op_set_tso, -#endif -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0) */ -}; - -static int rtltool_ioctl(struct r8152 *tp, struct ifreq *ifr) -{ - struct rtltool_cmd my_cmd, *myptr; - struct usb_device_info *uinfo; - struct usb_device *udev; - __le32 ocp_data; - void *buffer; - int ret; - - myptr = (struct rtltool_cmd *)ifr->ifr_data; - if (copy_from_user(&my_cmd, myptr, sizeof(my_cmd))) - return -EFAULT; - - ret = 0; - - switch (my_cmd.cmd) { - case RTLTOOL_PLA_OCP_READ_DWORD: - pla_ocp_read(tp, (u16)my_cmd.offset, sizeof(ocp_data), - &ocp_data); - my_cmd.data = __le32_to_cpu(ocp_data); - - if (copy_to_user(myptr, &my_cmd, sizeof(my_cmd))) { - ret = -EFAULT; - break; - } - break; - - case RTLTOOL_PLA_OCP_WRITE_DWORD: - ocp_data = __cpu_to_le32(my_cmd.data); - pla_ocp_real_write(tp, (u16)my_cmd.offset, (u16)my_cmd.byteen, - sizeof(ocp_data), &ocp_data); - break; - - case RTLTOOL_USB_OCP_READ_DWORD: - usb_ocp_read(tp, (u16)my_cmd.offset, sizeof(ocp_data), - &ocp_data); - my_cmd.data = __le32_to_cpu(ocp_data); - - if (copy_to_user(myptr, &my_cmd, sizeof(my_cmd))) { - ret = -EFAULT; - break; - } - break; - - - case RTLTOOL_USB_OCP_WRITE_DWORD: - ocp_data = __cpu_to_le32(my_cmd.data); - usb_ocp_real_write(tp, (u16)my_cmd.offset, (u16)my_cmd.byteen, - sizeof(ocp_data), &ocp_data); - break; - - case RTLTOOL_PLA_OCP_READ: - buffer = kmalloc(my_cmd.data, GFP_KERNEL); - if (!buffer) { - ret = -ENOMEM; - break; - } - - pla_ocp_read(tp, (u16)my_cmd.offset, my_cmd.data, buffer); - - if (copy_to_user(myptr->buf, buffer, my_cmd.data)) - ret = -EFAULT; - - kfree(buffer); - break; - - case RTLTOOL_PLA_OCP_WRITE: - buffer = kmalloc(my_cmd.data, GFP_KERNEL); - if (!buffer) { - ret = -ENOMEM; - break; - } - - if (copy_from_user(buffer, myptr->buf, my_cmd.data)) { - ret = -EFAULT; - kfree(buffer); - break; - } - - pla_ocp_real_write(tp, (u16)my_cmd.offset, (u16)my_cmd.byteen, - my_cmd.data, buffer); - kfree(buffer); - break; - - case RTLTOOL_USB_OCP_READ: - buffer = kmalloc(my_cmd.data, GFP_KERNEL); - if (!buffer) { - ret = -ENOMEM; - break; - } - - usb_ocp_read(tp, (u16)my_cmd.offset, my_cmd.data, buffer); - - if (copy_to_user(myptr->buf, buffer, my_cmd.data)) - ret = -EFAULT; - - kfree(buffer); - break; - - case RTLTOOL_USB_OCP_WRITE: - buffer = kmalloc(my_cmd.data, GFP_KERNEL); - if (!buffer) { - ret = -ENOMEM; - break; - } - - if (copy_from_user(buffer, myptr->buf, my_cmd.data)) { - ret = -EFAULT; - kfree(buffer); - break; - } - - usb_ocp_real_write(tp, (u16)my_cmd.offset, (u16)my_cmd.byteen, - my_cmd.data, buffer); - kfree(buffer); - break; - - case RTLTOOL_USB_INFO: - uinfo = (struct usb_device_info *)&my_cmd.nic_info; - udev = tp->udev; - uinfo->idVendor = __le16_to_cpu(udev->descriptor.idVendor); - uinfo->idProduct = __le16_to_cpu(udev->descriptor.idProduct); - uinfo->bcdDevice = __le16_to_cpu(udev->descriptor.bcdDevice); - memcpy(uinfo->devpath, udev->devpath, sizeof(udev->devpath)); - pla_ocp_read(tp, PLA_IDR, sizeof(uinfo->dev_addr), - uinfo->dev_addr); - - if (copy_to_user(myptr, &my_cmd, sizeof(my_cmd))) - ret = -EFAULT; - - break; - - case RTL_ENABLE_USB_DIAG: - tp->rtk_enable_diag = 1; - netif_info(tp, drv, tp->netdev,"enable rtk diag\n"); - break; - - case RTL_DISABLE_USB_DIAG: - tp->rtk_enable_diag = 0; - netif_info(tp, drv, tp->netdev,"disable rtk diag\n"); - break; - - default: - ret = -EOPNOTSUPP; - break; - } - - return ret; -} - -static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) -{ - struct r8152 *tp = netdev_priv(netdev); - struct mii_ioctl_data *data = if_mii(rq); - int res; - - if (test_bit(RTL8152_UNPLUG, &tp->flags)) - return -ENODEV; - - res = usb_autopm_get_interface(tp->intf); - if (res < 0) - goto out; - - switch (cmd) { - case SIOCGMIIPHY: - data->phy_id = R8152_PHY_ID; /* Internal PHY */ - break; - - case SIOCGMIIREG: - data->val_out = r8152_mdio_read(tp, data->reg_num); - break; - - case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) { - res = -EPERM; - break; - } - r8152_mdio_write(tp, data->reg_num, data->val_in); - break; - - case SIOCDEVPRIVATE: - res = rtltool_ioctl(tp, rq); - break; - - default: - res = -EOPNOTSUPP; - } - - usb_autopm_put_interface(tp->intf); - -out: - return res; -} - -static int rtl8152_change_mtu(struct net_device *dev, int new_mtu) -{ - struct r8152 *tp = netdev_priv(dev); - - switch (tp->version) { - case RTL_VER_01: - case RTL_VER_02: - return eth_change_mtu(dev, new_mtu); - default: - break; - } - - if (new_mtu < 68 || new_mtu > RTL8153_MAX_MTU) - return -EINVAL; - - dev->mtu = new_mtu; - - return 0; -} - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) -static const struct net_device_ops rtl8152_netdev_ops = { - .ndo_open = rtl8152_open, - .ndo_stop = rtl8152_close, - .ndo_do_ioctl = rtl8152_ioctl, - .ndo_start_xmit = rtl8152_start_xmit, - .ndo_tx_timeout = rtl8152_tx_timeout, - .ndo_set_rx_mode = rtl8152_set_rx_mode, - .ndo_set_mac_address = rtl8152_set_mac_address, - .ndo_change_mtu = rtl8152_change_mtu, - .ndo_validate_addr = eth_validate_addr, -}; -#endif - -static void r8152b_get_version(struct r8152 *tp) -{ - u32 ocp_data; - u16 version; - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR1); - version = (u16)(ocp_data & VERSION_MASK); - - switch (version) { - case 0x4c00: - tp->version = RTL_VER_01; - break; - case 0x4c10: - tp->version = RTL_VER_02; - break; - case 0x5c00: - tp->version = RTL_VER_03; - tp->mii.supports_gmii = 1; - break; - case 0x5c10: - tp->version = RTL_VER_04; - tp->mii.supports_gmii = 1; - break; - case 0x5c20: - tp->version = RTL_VER_05; - tp->mii.supports_gmii = 1; - break; - default: - netif_info(tp, probe, tp->netdev, - "Unknown version 0x%04x\n", version); - break; - } -} - -static void rtl8152_unload(struct r8152 *tp) -{ - if (test_bit(RTL8152_UNPLUG, &tp->flags)) - return; - - if (tp->version != RTL_VER_01) - r8152_power_cut_en(tp, true); -} - -static void rtl8153_unload(struct r8152 *tp) -{ - if (test_bit(RTL8152_UNPLUG, &tp->flags)) - return; - - r8153_power_cut_en(tp, true); -} - -static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id) -{ - struct rtl_ops *ops = &tp->rtl_ops; - int ret = -ENODEV; - - switch (id->idVendor) { - case VENDOR_ID_REALTEK: - switch (id->idProduct) { - case PRODUCT_ID_RTL8152: - ops->init = r8152b_init; - ops->enable = rtl8152_enable; - ops->disable = rtl8152_disable; - ops->up = rtl8152_up; - ops->down = rtl8152_down; - ops->unload = rtl8152_unload; - ret = 0; - break; - case PRODUCT_ID_RTL8153: - ops->init = r8153_init; - ops->enable = rtl8153_enable; - ops->disable = rtl8153_disable; - ops->up = rtl8153_up; - ops->down = rtl8153_down; - ops->unload = rtl8153_unload; - ret = 0; - break; - default: - break; - } - break; - - case VENDOR_ID_SAMSUNG: - switch (id->idProduct) { - case PRODUCT_ID_SAMSUNG: - ops->init = r8153_init; - ops->enable = rtl8153_enable; - ops->disable = rtl8153_disable; - ops->up = rtl8153_up; - ops->down = rtl8153_down; - ops->unload = rtl8153_unload; - ret = 0; - break; - default: - break; - } - break; - - case VENDOR_ID_LENOVO: - switch (id->idProduct) { - case 0x7205: - case 0x3052: - case 0x304f: - ops->init = r8153_init; - ops->enable = rtl8153_enable; - ops->disable = rtl8153_disable; - ops->up = rtl8153_up; - ops->down = rtl8153_down; - ops->unload = rtl8153_unload; - ret = 0; - break; - default: - break; - } - break; - - default: - break; - } - - if (ret) - netif_err(tp, probe, tp->netdev, "Unknown Device\n"); - - return ret; -} -extern struct usb_driver cdc_driver; - -static int rtl8152_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct r8152 *tp; - struct net_device *netdev; - int ret; - - if (udev->actconfig->desc.bConfigurationValue != 1) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) - dev_err(&intf->dev, "The kernel too old to set configuration\n"); -#else - usb_driver_set_configuration(udev, 1); -#endif - return -ENODEV; - } - - usb_reset_device(udev); - netdev = alloc_etherdev(sizeof(struct r8152)); - if (!netdev) { - dev_err(&intf->dev, "Out of memory\n"); - return -ENOMEM; - } - - SET_NETDEV_DEV(netdev, &intf->dev); - tp = netdev_priv(netdev); - tp->msg_enable = 0x7FFF; - - tp->udev = udev; - tp->netdev = netdev; - tp->intf = intf; - - ret = rtl_ops_init(tp, id); - if (ret) - goto out; - - tasklet_init(&tp->tl, bottom_half, (unsigned long)tp); - INIT_DELAYED_WORK(&tp->schedule, rtl_work_func_t); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) - netdev->netdev_ops = &rtl8152_netdev_ops; -#else - netdev->open = rtl8152_open; - netdev->stop = rtl8152_close; - netdev->get_stats = rtl8152_get_stats; - netdev->hard_start_xmit = rtl8152_start_xmit; - netdev->tx_timeout = rtl8152_tx_timeout; - netdev->change_mtu = rtl8152_change_mtu; - netdev->set_mac_address = rtl8152_set_mac_address; - netdev->do_ioctl = rtl8152_ioctl; - netdev->set_multicast_list = rtl8152_set_rx_mode; -#endif /* HAVE_NET_DEVICE_OPS */ - netdev->watchdog_timeo = RTL8152_TX_TIMEOUT; - - netdev->features |= NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG | - NETIF_F_FRAGLIST | NETIF_F_IPV6_CSUM; - -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25) - netdev->features |= NETIF_F_TSO | NETIF_F_TSO6; - netif_set_gso_max_size(netdev, RTL_LIMITED_TSO_SIZE); -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,38) - netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG | - NETIF_F_TSO | NETIF_F_FRAGLIST | - NETIF_F_IPV6_CSUM | NETIF_F_TSO6; -#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2,6,38) */ -#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25) */ - - netdev->ethtool_ops = &ops; - - tp->mii.dev = netdev; - tp->mii.mdio_read = read_mii_word; - tp->mii.mdio_write = write_mii_word; - tp->mii.phy_id_mask = 0x3f; - tp->mii.reg_num_mask = 0x1f; - tp->mii.phy_id = R8152_PHY_ID; - tp->mii.supports_gmii = 0; - - intf->needs_remote_wakeup = 1; - - r8152b_get_version(tp); - tp->rtl_ops.init(tp); - set_ethernet_addr(tp); - - usb_set_intfdata(intf, tp); - - ret = register_netdev(netdev); - if (ret != 0) { - netif_err(tp, probe, netdev, "couldn't register the device\n"); - goto out1; - } - - tp->saved_wolopts = __rtl_get_wol(tp); - if (tp->saved_wolopts) - device_set_wakeup_enable(&udev->dev, true); - else - device_set_wakeup_enable(&udev->dev, false); - - netif_info(tp, probe, netdev, "%s\n", DRIVER_VERSION); - netif_info(tp, probe, netdev, "%s\n", PATENTS); - - return 0; - -out1: - usb_set_intfdata(intf, NULL); -out: - free_netdev(netdev); - return ret; -} - -static void rtl8152_disconnect(struct usb_interface *intf) -{ - struct r8152 *tp = usb_get_intfdata(intf); - - usb_set_intfdata(intf, NULL); - if (tp) { - set_bit(RTL8152_UNPLUG, &tp->flags); - tasklet_kill(&tp->tl); - unregister_netdev(tp->netdev); - tp->rtl_ops.unload(tp); - free_netdev(tp->netdev); - } -} - -/* table of devices that work with this driver */ -static struct usb_device_id rtl8152_table[] = { - {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8152)}, - {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8153)}, - {USB_DEVICE(VENDOR_ID_SAMSUNG, PRODUCT_ID_SAMSUNG)}, - {USB_DEVICE(VENDOR_ID_LENOVO, 0x7205)}, - {USB_DEVICE(VENDOR_ID_LENOVO, 0x3052)}, - {USB_DEVICE(VENDOR_ID_LENOVO, 0x304f)}, - {} -}; - -MODULE_DEVICE_TABLE(usb, rtl8152_table); - -static struct usb_driver rtl8152_driver = { - .name = MODULENAME, - .id_table = rtl8152_table, - .probe = rtl8152_probe, - .disconnect = rtl8152_disconnect, - .suspend = rtl8152_suspend, - .resume = rtl8152_resume, - .reset_resume = rtl8152_resume, - .supports_autosuspend = 1, -#if LINUX_VERSION_CODE > KERNEL_VERSION(3,4,0) -// .disable_hub_initiated_lpm = 1, -#endif -}; - -extern struct usb_driver cdc_driver; -static int __init usb_rtl8152_init(void) -{ - - usb_deregister(&cdc_driver); - - return usb_register(&rtl8152_driver); -} - -static void __exit usb_rtl8152_exit(void) -{ - usb_deregister(&rtl8152_driver); -} - - -module_init(usb_rtl8152_init); -module_exit(usb_rtl8152_exit); -//module_usb_driver(rtl8152_driver); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/net/usb/rndis_host.c b/ANDROID_3.4.5/drivers/net/usb/rndis_host.c deleted file mode 100644 index c8f1b5b3..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/rndis_host.c +++ /dev/null @@ -1,642 +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 - */ -#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/slab.h> -#include <linux/mii.h> -#include <linux/usb.h> -#include <linux/usb/cdc.h> -#include <linux/usb/usbnet.h> -#include <linux/usb/rndis_host.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). - */ - -/* - * RNDIS notifications from device: command completion; "reverse" - * keepalives; etc - */ -void rndis_status(struct usbnet *dev, struct urb *urb) -{ - netdev_dbg(dev->net, "rndis status urb, len %d stat %d\n", - urb->actual_length, urb->status); - // FIXME for keepalives, respond immediately (asynchronously) - // if not an RNDIS status, do like cdc_status(dev,urb) does -} -EXPORT_SYMBOL_GPL(rndis_status); - -/* - * RNDIS indicate messages. - */ -static void rndis_msg_indicate(struct usbnet *dev, struct rndis_indicate *msg, - int buflen) -{ - struct cdc_state *info = (void *)&dev->data; - struct device *udev = &info->control->dev; - - if (dev->driver_info->indication) { - dev->driver_info->indication(dev, msg, buflen); - } else { - switch (msg->status) { - case RNDIS_STATUS_MEDIA_CONNECT: - dev_info(udev, "rndis media connect\n"); - break; - case RNDIS_STATUS_MEDIA_DISCONNECT: - dev_info(udev, "rndis media disconnect\n"); - break; - default: - dev_info(udev, "rndis indication: 0x%08x\n", - le32_to_cpu(msg->status)); - } - } -} - -/* - * 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. - */ -int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen) -{ - struct cdc_state *info = (void *) &dev->data; - struct usb_cdc_notification notification; - int master_ifnum; - int retval; - int partial; - 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; - - /* Some devices don't respond on the control channel until - * polled on the status channel, so do that first. */ - if (dev->driver_info->data & RNDIS_DRIVER_DATA_POLL_STATUS) { - retval = usb_interrupt_msg( - dev->udev, - usb_rcvintpipe(dev->udev, - dev->status->desc.bEndpointAddress), - ¬ification, sizeof(notification), &partial, - RNDIS_CONTROL_TIMEOUT_MS); - if (unlikely(retval < 0)) - return retval; - } - - /* 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, buflen, - 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/event */ - rndis_msg_indicate(dev, (void *)buf, buflen); - - break; - case RNDIS_MSG_KEEPALIVE: { /* ping */ - struct rndis_keepalive_c *msg = (void *)buf; - - msg->msg_type = RNDIS_MSG_KEEPALIVE_C; - msg->msg_len = cpu_to_le32(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(20); - } - dev_dbg(&info->control->dev, "rndis response timeout\n"); - return -ETIMEDOUT; -} -EXPORT_SYMBOL_GPL(rndis_command); - -/* - * 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, __le32 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 = cpu_to_le32(20); - - retval = rndis_command(dev, u.header, CONTROL_BUFFER_SIZE); - 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; -} - -/* same as usbnet_netdev_ops but MTU change not allowed */ -static const struct net_device_ops rndis_netdev_ops = { - .ndo_open = usbnet_open, - .ndo_stop = usbnet_stop, - .ndo_start_xmit = usbnet_start_xmit, - .ndo_tx_timeout = usbnet_tx_timeout, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -int -generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags) -{ - 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; - struct rndis_halt *halt; - } u; - u32 tmp; - __le32 phym_unspec, *phym; - 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 = cpu_to_le32(sizeof *u.init); - u.init->major_version = cpu_to_le32(1); - u.init->minor_version = cpu_to_le32(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->maxpacket = usb_maxpacket(dev->udev, dev->out, 1); - if (dev->maxpacket == 0) { - netif_dbg(dev, probe, dev->net, - "dev->maxpacket can't be 0\n"); - retval = -EINVAL; - goto fail_and_release; - } - - 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->netdev_ops = &rndis_netdev_ops; - - retval = rndis_command(dev, u.header, CONTROL_BUFFER_SIZE); - 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) { - if (tmp <= net->hard_header_len) { - dev_err(&intf->dev, - "dev can't take %u byte packets (max %u)\n", - dev->hard_mtu, tmp); - retval = -EINVAL; - goto halt_fail_and_release; - } - dev_warn(&intf->dev, - "dev can't take %u byte packets (max %u), " - "adjusting MTU to %u\n", - dev->hard_mtu, tmp, tmp - net->hard_header_len); - dev->hard_mtu = tmp; - net->mtu = dev->hard_mtu - net->hard_header_len; - } - - /* 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)); - - /* module has some device initialization code needs to be done right - * after RNDIS_INIT */ - if (dev->driver_info->early_init && - dev->driver_info->early_init(dev) != 0) - goto halt_fail_and_release; - - /* Check physical medium */ - phym = NULL; - reply_len = sizeof *phym; - retval = rndis_query(dev, intf, u.buf, OID_GEN_PHYSICAL_MEDIUM, - 0, (void **) &phym, &reply_len); - if (retval != 0 || !phym) { - /* OID is optional so don't fail here. */ - phym_unspec = RNDIS_PHYSICAL_MEDIUM_UNSPECIFIED; - phym = &phym_unspec; - } - if ((flags & FLAG_RNDIS_PHYM_WIRELESS) && - *phym != RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN) { - netif_dbg(dev, probe, dev->net, - "driver requires wireless physical medium, but device is not\n"); - retval = -ENODEV; - goto halt_fail_and_release; - } - if ((flags & FLAG_RNDIS_PHYM_NOT_WIRELESS) && - *phym == RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN) { - netif_dbg(dev, probe, dev->net, - "driver requires non-wireless physical medium, but device is wireless.\n"); - retval = -ENODEV; - goto halt_fail_and_release; - } - - /* 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 halt_fail_and_release; - } - memcpy(net->dev_addr, bp, ETH_ALEN); - memcpy(net->perm_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 = cpu_to_le32(4 + sizeof *u.set); - u.set->oid = OID_GEN_CURRENT_PACKET_FILTER; - u.set->len = cpu_to_le32(4); - u.set->offset = cpu_to_le32((sizeof *u.set) - 8); - *(__le32 *)(u.buf + sizeof *u.set) = RNDIS_DEFAULT_FILTER; - - retval = rndis_command(dev, u.header, CONTROL_BUFFER_SIZE); - if (unlikely(retval < 0)) { - dev_err(&intf->dev, "rndis set packet filter, %d\n", retval); - goto halt_fail_and_release; - } - - retval = 0; - - kfree(u.buf); - return retval; - -halt_fail_and_release: - memset(u.halt, 0, sizeof *u.halt); - u.halt->msg_type = RNDIS_MSG_HALT; - u.halt->msg_len = cpu_to_le32(sizeof *u.halt); - (void) rndis_command(dev, (void *)u.halt, CONTROL_BUFFER_SIZE); -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; -} -EXPORT_SYMBOL_GPL(generic_rndis_bind); - -static int rndis_bind(struct usbnet *dev, struct usb_interface *intf) -{ - return generic_rndis_bind(dev, intf, FLAG_RNDIS_PHYM_NOT_WIRELESS); -} - -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(CONTROL_BUFFER_SIZE, GFP_KERNEL); - if (halt) { - halt->msg_type = RNDIS_MSG_HALT; - halt->msg_len = cpu_to_le32(sizeof *halt); - (void) rndis_command(dev, (void *)halt, CONTROL_BUFFER_SIZE); - kfree(halt); - } - - usbnet_cdc_unbind(dev, intf); -} -EXPORT_SYMBOL_GPL(rndis_unbind); - -/* - * DATA -- host must not write zlps - */ -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->net->stats.rx_frame_errors++; - netdev_dbg(dev->net, "bad rndis message %d/%d/%d/%d, len %d\n", - 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; -} -EXPORT_SYMBOL_GPL(rndis_rx_fixup); - -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 = cpu_to_le32(sizeof(*hdr) - 8); - hdr->data_len = cpu_to_le32(len); - - /* FIXME make the last packet always be short ... */ - return skb; -} -EXPORT_SYMBOL_GPL(rndis_tx_fixup); - - -static const struct driver_info rndis_info = { - .description = "RNDIS device", - .flags = FLAG_ETHER | FLAG_POINTTOPOINT | 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, -}; - -static const struct driver_info rndis_poll_status_info = { - .description = "RNDIS device (poll status before control)", - .flags = FLAG_ETHER | FLAG_POINTTOPOINT | FLAG_FRAMING_RN | FLAG_NO_SETINT, - .data = RNDIS_DRIVER_DATA_POLL_STATUS, - .bind = rndis_bind, - .unbind = rndis_unbind, - .status = rndis_status, - .rx_fixup = rndis_rx_fixup, - .tx_fixup = rndis_tx_fixup, -}; - -/*-------------------------------------------------------------------------*/ - -static const struct usb_device_id products [] = { -{ - /* 2Wire HomePortal 1000SW */ - USB_DEVICE_AND_INTERFACE_INFO(0x1630, 0x0042, - USB_CLASS_COMM, 2 /* ACM */, 0x0ff), - .driver_info = (unsigned long) &rndis_poll_status_info, -}, { - /* 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_poll_status_info, -}, { - /* RNDIS for tethering */ - USB_INTERFACE_INFO(USB_CLASS_WIRELESS_CONTROLLER, 1, 3), - .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, -}; - -module_usb_driver(rndis_driver); - -MODULE_AUTHOR("David Brownell"); -MODULE_DESCRIPTION("USB Host side RNDIS driver"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/net/usb/rtl8150.c b/ANDROID_3.4.5/drivers/net/usb/rtl8150.c deleted file mode 100644 index d363b310..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/rtl8150.c +++ /dev/null @@ -1,957 +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 - - -#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 *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 const char driver_name [] = "rtl8150"; - -/* -** -** 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; - int status = urb->status; - - switch (status) { - case 0: - break; - case -EINPROGRESS: - break; - case -ENOENT: - break; - default: - if (printk_ratelimit()) - dev_warn(&urb->dev->dev, "ctrl urb status %d\n", 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); - - if (netif_running(netdev)) - return -EBUSY; - - memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); - dbg("%s: Setting MAC address to %pM\n", netdev->name, netdev->dev_addr); - /* Set the IDR registers. */ - set_registers(dev, IDR, netdev->addr_len, netdev->dev_addr); -#ifdef EEPROM_WRITE - { - int i; - 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->ctrl_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 = urb->status; - int result; - - dev = urb->context; - if (!dev) - return; - if (test_bit(RTL8150_UNPLUG, &dev->flags)) - return; - netdev = dev->netdev; - if (!netif_device_present(netdev)) - return; - - switch (status) { - case 0: - break; - case -ENOENT: - return; /* the urb is in unlink state */ - case -ETIME: - if (printk_ratelimit()) - dev_warn(&urb->dev->dev, "may be reset is needed?..\n"); - goto goon; - default: - if (printk_ratelimit()) - dev_warn(&urb->dev->dev, "Rx status %d\n", 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); - netdev->stats.rx_packets++; - netdev->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); - result = usb_submit_urb(dev->rx_urb, GFP_ATOMIC); - if (result == -ENODEV) - netif_device_detach(dev->netdev); - else if (result) { - 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 write_bulk_callback(struct urb *urb) -{ - rtl8150_t *dev; - int status = urb->status; - - dev = urb->context; - if (!dev) - return; - dev_kfree_skb_irq(dev->tx_skb); - if (!netif_device_present(dev->netdev)) - return; - if (status) - dev_info(&urb->dev->dev, "%s: Tx status %d\n", - dev->netdev->name, 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 = urb->status; - int res; - - dev = urb->context; - if (!dev) - return; - switch (status) { - case 0: /* success */ - break; - case -ECONNRESET: /* unlink */ - case -ENOENT: - case -ESHUTDOWN: - return; - /* -EPIPE: should clear the halt */ - default: - dev_info(&urb->dev->dev, "%s: intr status %d\n", - dev->netdev->name, status); - goto resubmit; - } - - d = urb->transfer_buffer; - if (d[0] & TSR_ERRORS) { - dev->netdev->stats.tx_errors++; - if (d[INT_TSR] & (TSR_ECOL | TSR_JBR)) - dev->netdev->stats.tx_aborted_errors++; - if (d[INT_TSR] & TSR_LCOL) - dev->netdev->stats.tx_window_errors++; - if (d[INT_TSR] & TSR_LOSS_CRS) - dev->netdev->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: - res = usb_submit_urb (urb, GFP_ATOMIC); - if (res == -ENODEV) - netif_device_detach(dev->netdev); - else if (res) - err ("can't resubmit intr, %s-%s/input0, status %d", - dev->udev->bus->bus_name, - dev->udev->devpath, res); -} - -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 void rx_fixup(unsigned long data) -{ - struct rtl8150 *dev = (struct rtl8150 *)data; - struct sk_buff *skb; - int status; - - 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 int enable_net_traffic(rtl8150_t * dev) -{ - u8 cr, tcr, rcr, msr; - - if (!rtl8150_reset(dev)) { - dev_warn(&dev->udev->dev, "device reset failed\n"); - } - /* 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 void rtl8150_tx_timeout(struct net_device *netdev) -{ - rtl8150_t *dev = netdev_priv(netdev); - dev_warn(&netdev->dev, "Tx timeout.\n"); - usb_unlink_urb(dev->tx_urb); - netdev->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); - dev_info(&netdev->dev, "%s: promiscuous mode\n", netdev->name); - } else if (!netdev_mc_empty(netdev) || - (netdev->flags & IFF_ALLMULTI)) { - dev->rx_creg &= cpu_to_le16(0xfffe); - dev->rx_creg |= cpu_to_le16(0x0002); - dev_info(&netdev->dev, "%s: allmulti set\n", 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 netdev_tx_t 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 { - dev_warn(&netdev->dev, "failed tx_urb %d\n", res); - netdev->stats.tx_errors++; - netif_start_queue(netdev); - } - } else { - netdev->stats.tx_packets++; - netdev->stats.tx_bytes += skb->len; - netdev->trans_start = jiffies; - } - - return NETDEV_TX_OK; -} - - -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); - dev_warn(&netdev->dev, "rx_urb submit failed: %d\n", 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); - dev_warn(&netdev->dev, "intr_urb submit failed: %d\n", 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) { - u32 speed = ((lpa & (LPA_100HALF | LPA_100FULL)) ? - SPEED_100 : SPEED_10); - ethtool_cmd_speed_set(ecmd, speed); - ecmd->autoneg = AUTONEG_ENABLE; - if (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; - ethtool_cmd_speed_set(ecmd, ((bmcr & BMCR_SPEED100) ? - SPEED_100 : SPEED_10)); - ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? - DUPLEX_FULL : DUPLEX_HALF; - } - return 0; -} - -static const 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 const struct net_device_ops rtl8150_netdev_ops = { - .ndo_open = rtl8150_open, - .ndo_stop = rtl8150_close, - .ndo_do_ioctl = rtl8150_ioctl, - .ndo_start_xmit = rtl8150_start_xmit, - .ndo_tx_timeout = rtl8150_tx_timeout, - .ndo_set_rx_mode = rtl8150_set_multicast, - .ndo_set_mac_address = rtl8150_set_mac_address, - - .ndo_change_mtu = eth_change_mtu, - .ndo_validate_addr = eth_validate_addr, -}; - -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) - return -ENOMEM; - - dev = netdev_priv(netdev); - - 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; - netdev->netdev_ops = &rtl8150_netdev_ops; - netdev->watchdog_timeo = RTL8150_TX_TIMEOUT; - 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; - } - - dev_info(&intf->dev, "%s: rtl8150 is detected\n", 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_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 struct usb_driver rtl8150_driver = { - .name = driver_name, - .probe = rtl8150_probe, - .disconnect = rtl8150_disconnect, - .id_table = rtl8150_table, - .suspend = rtl8150_suspend, - .resume = rtl8150_resume -}; - -module_usb_driver(rtl8150_driver); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/net/usb/sierra_net.c b/ANDROID_3.4.5/drivers/net/usb/sierra_net.c deleted file mode 100644 index cc9776c2..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/sierra_net.c +++ /dev/null @@ -1,998 +0,0 @@ -/* - * USB-to-WWAN Driver for Sierra Wireless modems - * - * Copyright (C) 2008, 2009, 2010 Paxton Smith, Matthew Safar, Rory Filer - * <linux@sierrawireless.com> - * - * Portions of this based on the cdc_ether driver by David Brownell (2003-2005) - * and Ole Andre Vadla Ravnas (ActiveSync) (2006). - * - * IMPORTANT DISCLAIMER: This driver is not commercially supported by - * Sierra Wireless. Use at your own risk. - * - * 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 DRIVER_VERSION "v.2.0" -#define DRIVER_AUTHOR "Paxton Smith, Matthew Safar, Rory Filer" -#define DRIVER_DESC "USB-to-WWAN Driver for Sierra Wireless modems" -static const char driver_name[] = "sierra_net"; - -/* if defined debug messages enabled */ -/*#define DEBUG*/ - -#include <linux/module.h> -#include <linux/etherdevice.h> -#include <linux/ethtool.h> -#include <linux/mii.h> -#include <linux/sched.h> -#include <linux/timer.h> -#include <linux/usb.h> -#include <linux/usb/cdc.h> -#include <net/ip.h> -#include <net/udp.h> -#include <asm/unaligned.h> -#include <linux/usb/usbnet.h> - -#define SWI_USB_REQUEST_GET_FW_ATTR 0x06 -#define SWI_GET_FW_ATTR_MASK 0x08 - -/* atomic counter partially included in MAC address to make sure 2 devices - * do not end up with the same MAC - concept breaks in case of > 255 ifaces - */ -static atomic_t iface_counter = ATOMIC_INIT(0); - -/* - * SYNC Timer Delay definition used to set the expiry time - */ -#define SIERRA_NET_SYNCDELAY (2*HZ) - -/* Max. MTU supported. The modem buffers are limited to 1500 */ -#define SIERRA_NET_MAX_SUPPORTED_MTU 1500 - -/* The SIERRA_NET_USBCTL_BUF_LEN defines a buffer size allocated for control - * message reception ... and thus the max. received packet. - * (May be the cause for parse_hip returning -EINVAL) - */ -#define SIERRA_NET_USBCTL_BUF_LEN 1024 - -/* list of interface numbers - used for constructing interface lists */ -struct sierra_net_iface_info { - const u32 infolen; /* number of interface numbers on list */ - const u8 *ifaceinfo; /* pointer to the array holding the numbers */ -}; - -struct sierra_net_info_data { - u16 rx_urb_size; - struct sierra_net_iface_info whitelist; -}; - -/* Private data structure */ -struct sierra_net_data { - - u8 ethr_hdr_tmpl[ETH_HLEN]; /* ethernet header template for rx'd pkts */ - - u16 link_up; /* air link up or down */ - u8 tx_hdr_template[4]; /* part of HIP hdr for tx'd packets */ - - u8 sync_msg[4]; /* SYNC message */ - u8 shdwn_msg[4]; /* Shutdown message */ - - /* Backpointer to the container */ - struct usbnet *usbnet; - - u8 ifnum; /* interface number */ - -/* Bit masks, must be a power of 2 */ -#define SIERRA_NET_EVENT_RESP_AVAIL 0x01 -#define SIERRA_NET_TIMER_EXPIRY 0x02 - unsigned long kevent_flags; - struct work_struct sierra_net_kevent; - struct timer_list sync_timer; /* For retrying SYNC sequence */ -}; - -struct param { - int is_present; - union { - void *ptr; - u32 dword; - u16 word; - u8 byte; - }; -}; - -/* HIP message type */ -#define SIERRA_NET_HIP_EXTENDEDID 0x7F -#define SIERRA_NET_HIP_HSYNC_ID 0x60 /* Modem -> host */ -#define SIERRA_NET_HIP_RESTART_ID 0x62 /* Modem -> host */ -#define SIERRA_NET_HIP_MSYNC_ID 0x20 /* Host -> modem */ -#define SIERRA_NET_HIP_SHUTD_ID 0x26 /* Host -> modem */ - -#define SIERRA_NET_HIP_EXT_IP_IN_ID 0x0202 -#define SIERRA_NET_HIP_EXT_IP_OUT_ID 0x0002 - -/* 3G UMTS Link Sense Indication definitions */ -#define SIERRA_NET_HIP_LSI_UMTSID 0x78 - -/* Reverse Channel Grant Indication HIP message */ -#define SIERRA_NET_HIP_RCGI 0x64 - -/* LSI Protocol types */ -#define SIERRA_NET_PROTOCOL_UMTS 0x01 -/* LSI Coverage */ -#define SIERRA_NET_COVERAGE_NONE 0x00 -#define SIERRA_NET_COVERAGE_NOPACKET 0x01 - -/* LSI Session */ -#define SIERRA_NET_SESSION_IDLE 0x00 -/* LSI Link types */ -#define SIERRA_NET_AS_LINK_TYPE_IPv4 0x00 - -struct lsi_umts { - u8 protocol; - u8 unused1; - __be16 length; - /* eventually use a union for the rest - assume umts for now */ - u8 coverage; - u8 unused2[41]; - u8 session_state; - u8 unused3[33]; - u8 link_type; - u8 pdp_addr_len; /* NW-supplied PDP address len */ - u8 pdp_addr[16]; /* NW-supplied PDP address (bigendian)) */ - u8 unused4[23]; - u8 dns1_addr_len; /* NW-supplied 1st DNS address len (bigendian) */ - u8 dns1_addr[16]; /* NW-supplied 1st DNS address */ - u8 dns2_addr_len; /* NW-supplied 2nd DNS address len */ - u8 dns2_addr[16]; /* NW-supplied 2nd DNS address (bigendian)*/ - u8 wins1_addr_len; /* NW-supplied 1st Wins address len */ - u8 wins1_addr[16]; /* NW-supplied 1st Wins address (bigendian)*/ - u8 wins2_addr_len; /* NW-supplied 2nd Wins address len */ - u8 wins2_addr[16]; /* NW-supplied 2nd Wins address (bigendian) */ - u8 unused5[4]; - u8 gw_addr_len; /* NW-supplied GW address len */ - u8 gw_addr[16]; /* NW-supplied GW address (bigendian) */ - u8 reserved[8]; -} __packed; - -#define SIERRA_NET_LSI_COMMON_LEN 4 -#define SIERRA_NET_LSI_UMTS_LEN (sizeof(struct lsi_umts)) -#define SIERRA_NET_LSI_UMTS_STATUS_LEN \ - (SIERRA_NET_LSI_UMTS_LEN - SIERRA_NET_LSI_COMMON_LEN) - -/* Forward definitions */ -static void sierra_sync_timer(unsigned long syncdata); -static int sierra_net_change_mtu(struct net_device *net, int new_mtu); - -/* Our own net device operations structure */ -static const struct net_device_ops sierra_net_device_ops = { - .ndo_open = usbnet_open, - .ndo_stop = usbnet_stop, - .ndo_start_xmit = usbnet_start_xmit, - .ndo_tx_timeout = usbnet_tx_timeout, - .ndo_change_mtu = sierra_net_change_mtu, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -/* get private data associated with passed in usbnet device */ -static inline struct sierra_net_data *sierra_net_get_private(struct usbnet *dev) -{ - return (struct sierra_net_data *)dev->data[0]; -} - -/* set private data associated with passed in usbnet device */ -static inline void sierra_net_set_private(struct usbnet *dev, - struct sierra_net_data *priv) -{ - dev->data[0] = (unsigned long)priv; -} - -/* is packet IPv4 */ -static inline int is_ip(struct sk_buff *skb) -{ - return skb->protocol == cpu_to_be16(ETH_P_IP); -} - -/* - * check passed in packet and make sure that: - * - it is linear (no scatter/gather) - * - it is ethernet (mac_header properly set) - */ -static int check_ethip_packet(struct sk_buff *skb, struct usbnet *dev) -{ - skb_reset_mac_header(skb); /* ethernet header */ - - if (skb_is_nonlinear(skb)) { - netdev_err(dev->net, "Non linear buffer-dropping\n"); - return 0; - } - - if (!pskb_may_pull(skb, ETH_HLEN)) - return 0; - skb->protocol = eth_hdr(skb)->h_proto; - - return 1; -} - -static const u8 *save16bit(struct param *p, const u8 *datap) -{ - p->is_present = 1; - p->word = get_unaligned_be16(datap); - return datap + sizeof(p->word); -} - -static const u8 *save8bit(struct param *p, const u8 *datap) -{ - p->is_present = 1; - p->byte = *datap; - return datap + sizeof(p->byte); -} - -/*----------------------------------------------------------------------------* - * BEGIN HIP * - *----------------------------------------------------------------------------*/ -/* HIP header */ -#define SIERRA_NET_HIP_HDR_LEN 4 -/* Extended HIP header */ -#define SIERRA_NET_HIP_EXT_HDR_LEN 6 - -struct hip_hdr { - int hdrlen; - struct param payload_len; - struct param msgid; - struct param msgspecific; - struct param extmsgid; -}; - -static int parse_hip(const u8 *buf, const u32 buflen, struct hip_hdr *hh) -{ - const u8 *curp = buf; - int padded; - - if (buflen < SIERRA_NET_HIP_HDR_LEN) - return -EPROTO; - - curp = save16bit(&hh->payload_len, curp); - curp = save8bit(&hh->msgid, curp); - curp = save8bit(&hh->msgspecific, curp); - - padded = hh->msgid.byte & 0x80; - hh->msgid.byte &= 0x7F; /* 7 bits */ - - hh->extmsgid.is_present = (hh->msgid.byte == SIERRA_NET_HIP_EXTENDEDID); - if (hh->extmsgid.is_present) { - if (buflen < SIERRA_NET_HIP_EXT_HDR_LEN) - return -EPROTO; - - hh->payload_len.word &= 0x3FFF; /* 14 bits */ - - curp = save16bit(&hh->extmsgid, curp); - hh->extmsgid.word &= 0x03FF; /* 10 bits */ - - hh->hdrlen = SIERRA_NET_HIP_EXT_HDR_LEN; - } else { - hh->payload_len.word &= 0x07FF; /* 11 bits */ - hh->hdrlen = SIERRA_NET_HIP_HDR_LEN; - } - - if (padded) { - hh->hdrlen++; - hh->payload_len.word--; - } - - /* if real packet shorter than the claimed length */ - if (buflen < (hh->hdrlen + hh->payload_len.word)) - return -EINVAL; - - return 0; -} - -static void build_hip(u8 *buf, const u16 payloadlen, - struct sierra_net_data *priv) -{ - /* the following doesn't have the full functionality. We - * currently build only one kind of header, so it is faster this way - */ - put_unaligned_be16(payloadlen, buf); - memcpy(buf+2, priv->tx_hdr_template, sizeof(priv->tx_hdr_template)); -} -/*----------------------------------------------------------------------------* - * END HIP * - *----------------------------------------------------------------------------*/ - -static int sierra_net_send_cmd(struct usbnet *dev, - u8 *cmd, int cmdlen, const char * cmd_name) -{ - struct sierra_net_data *priv = sierra_net_get_private(dev); - int status; - - status = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), - USB_CDC_SEND_ENCAPSULATED_COMMAND, - USB_DIR_OUT|USB_TYPE_CLASS|USB_RECIP_INTERFACE, 0, - priv->ifnum, cmd, cmdlen, USB_CTRL_SET_TIMEOUT); - - if (status != cmdlen && status != -ENODEV) - netdev_err(dev->net, "Submit %s failed %d\n", cmd_name, status); - - return status; -} - -static int sierra_net_send_sync(struct usbnet *dev) -{ - int status; - struct sierra_net_data *priv = sierra_net_get_private(dev); - - dev_dbg(&dev->udev->dev, "%s", __func__); - - status = sierra_net_send_cmd(dev, priv->sync_msg, - sizeof(priv->sync_msg), "SYNC"); - - return status; -} - -static void sierra_net_set_ctx_index(struct sierra_net_data *priv, u8 ctx_ix) -{ - dev_dbg(&(priv->usbnet->udev->dev), "%s %d", __func__, ctx_ix); - priv->tx_hdr_template[0] = 0x3F; - priv->tx_hdr_template[1] = ctx_ix; - *((u16 *)&priv->tx_hdr_template[2]) = - cpu_to_be16(SIERRA_NET_HIP_EXT_IP_OUT_ID); -} - -static inline int sierra_net_is_valid_addrlen(u8 len) -{ - return len == sizeof(struct in_addr); -} - -static int sierra_net_parse_lsi(struct usbnet *dev, char *data, int datalen) -{ - struct lsi_umts *lsi = (struct lsi_umts *)data; - - if (datalen < sizeof(struct lsi_umts)) { - netdev_err(dev->net, "%s: Data length %d, exp %Zu\n", - __func__, datalen, - sizeof(struct lsi_umts)); - return -1; - } - - if (lsi->length != cpu_to_be16(SIERRA_NET_LSI_UMTS_STATUS_LEN)) { - netdev_err(dev->net, "%s: LSI_UMTS_STATUS_LEN %d, exp %u\n", - __func__, be16_to_cpu(lsi->length), - (u32)SIERRA_NET_LSI_UMTS_STATUS_LEN); - return -1; - } - - /* Validate the protocol - only support UMTS for now */ - if (lsi->protocol != SIERRA_NET_PROTOCOL_UMTS) { - netdev_err(dev->net, "Protocol unsupported, 0x%02x\n", - lsi->protocol); - return -1; - } - - /* Validate the link type */ - if (lsi->link_type != SIERRA_NET_AS_LINK_TYPE_IPv4) { - netdev_err(dev->net, "Link type unsupported: 0x%02x\n", - lsi->link_type); - return -1; - } - - /* Validate the coverage */ - if (lsi->coverage == SIERRA_NET_COVERAGE_NONE - || lsi->coverage == SIERRA_NET_COVERAGE_NOPACKET) { - netdev_err(dev->net, "No coverage, 0x%02x\n", lsi->coverage); - return 0; - } - - /* Validate the session state */ - if (lsi->session_state == SIERRA_NET_SESSION_IDLE) { - netdev_err(dev->net, "Session idle, 0x%02x\n", - lsi->session_state); - return 0; - } - - /* Set link_sense true */ - return 1; -} - -static void sierra_net_handle_lsi(struct usbnet *dev, char *data, - struct hip_hdr *hh) -{ - struct sierra_net_data *priv = sierra_net_get_private(dev); - int link_up; - - link_up = sierra_net_parse_lsi(dev, data + hh->hdrlen, - hh->payload_len.word); - if (link_up < 0) { - netdev_err(dev->net, "Invalid LSI\n"); - return; - } - if (link_up) { - sierra_net_set_ctx_index(priv, hh->msgspecific.byte); - priv->link_up = 1; - netif_carrier_on(dev->net); - } else { - priv->link_up = 0; - netif_carrier_off(dev->net); - } -} - -static void sierra_net_dosync(struct usbnet *dev) -{ - int status; - struct sierra_net_data *priv = sierra_net_get_private(dev); - - dev_dbg(&dev->udev->dev, "%s", __func__); - - /* tell modem we are ready */ - status = sierra_net_send_sync(dev); - if (status < 0) - netdev_err(dev->net, - "Send SYNC failed, status %d\n", status); - status = sierra_net_send_sync(dev); - if (status < 0) - netdev_err(dev->net, - "Send SYNC failed, status %d\n", status); - - /* Now, start a timer and make sure we get the Restart Indication */ - priv->sync_timer.function = sierra_sync_timer; - priv->sync_timer.data = (unsigned long) dev; - priv->sync_timer.expires = jiffies + SIERRA_NET_SYNCDELAY; - add_timer(&priv->sync_timer); -} - -static void sierra_net_kevent(struct work_struct *work) -{ - struct sierra_net_data *priv = - container_of(work, struct sierra_net_data, sierra_net_kevent); - struct usbnet *dev = priv->usbnet; - int len; - int err; - u8 *buf; - u8 ifnum; - - if (test_bit(SIERRA_NET_EVENT_RESP_AVAIL, &priv->kevent_flags)) { - clear_bit(SIERRA_NET_EVENT_RESP_AVAIL, &priv->kevent_flags); - - /* Query the modem for the LSI message */ - buf = kzalloc(SIERRA_NET_USBCTL_BUF_LEN, GFP_KERNEL); - if (!buf) { - netdev_err(dev->net, - "failed to allocate buf for LS msg\n"); - return; - } - ifnum = priv->ifnum; - len = 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, ifnum, buf, SIERRA_NET_USBCTL_BUF_LEN, - USB_CTRL_SET_TIMEOUT); - - if (len < 0) { - netdev_err(dev->net, - "usb_control_msg failed, status %d\n", len); - } else { - struct hip_hdr hh; - - dev_dbg(&dev->udev->dev, "%s: Received status message," - " %04x bytes", __func__, len); - - err = parse_hip(buf, len, &hh); - if (err) { - netdev_err(dev->net, "%s: Bad packet," - " parse result %d\n", __func__, err); - kfree(buf); - return; - } - - /* Validate packet length */ - if (len != hh.hdrlen + hh.payload_len.word) { - netdev_err(dev->net, "%s: Bad packet, received" - " %d, expected %d\n", __func__, len, - hh.hdrlen + hh.payload_len.word); - kfree(buf); - return; - } - - /* Switch on received message types */ - switch (hh.msgid.byte) { - case SIERRA_NET_HIP_LSI_UMTSID: - dev_dbg(&dev->udev->dev, "LSI for ctx:%d", - hh.msgspecific.byte); - sierra_net_handle_lsi(dev, buf, &hh); - break; - case SIERRA_NET_HIP_RESTART_ID: - dev_dbg(&dev->udev->dev, "Restart reported: %d," - " stopping sync timer", - hh.msgspecific.byte); - /* Got sync resp - stop timer & clear mask */ - del_timer_sync(&priv->sync_timer); - clear_bit(SIERRA_NET_TIMER_EXPIRY, - &priv->kevent_flags); - break; - case SIERRA_NET_HIP_HSYNC_ID: - dev_dbg(&dev->udev->dev, "SYNC received"); - err = sierra_net_send_sync(dev); - if (err < 0) - netdev_err(dev->net, - "Send SYNC failed %d\n", err); - break; - case SIERRA_NET_HIP_EXTENDEDID: - netdev_err(dev->net, "Unrecognized HIP msg, " - "extmsgid 0x%04x\n", hh.extmsgid.word); - break; - case SIERRA_NET_HIP_RCGI: - /* Ignored */ - break; - default: - netdev_err(dev->net, "Unrecognized HIP msg, " - "msgid 0x%02x\n", hh.msgid.byte); - break; - } - } - kfree(buf); - } - /* The sync timer bit might be set */ - if (test_bit(SIERRA_NET_TIMER_EXPIRY, &priv->kevent_flags)) { - clear_bit(SIERRA_NET_TIMER_EXPIRY, &priv->kevent_flags); - dev_dbg(&dev->udev->dev, "Deferred sync timer expiry"); - sierra_net_dosync(priv->usbnet); - } - - if (priv->kevent_flags) - dev_dbg(&dev->udev->dev, "sierra_net_kevent done, " - "kevent_flags = 0x%lx", priv->kevent_flags); -} - -static void sierra_net_defer_kevent(struct usbnet *dev, int work) -{ - struct sierra_net_data *priv = sierra_net_get_private(dev); - - set_bit(work, &priv->kevent_flags); - schedule_work(&priv->sierra_net_kevent); -} - -/* - * Sync Retransmit Timer Handler. On expiry, kick the work queue - */ -void sierra_sync_timer(unsigned long syncdata) -{ - struct usbnet *dev = (struct usbnet *)syncdata; - - dev_dbg(&dev->udev->dev, "%s", __func__); - /* Kick the tasklet */ - sierra_net_defer_kevent(dev, SIERRA_NET_TIMER_EXPIRY); -} - -static void sierra_net_status(struct usbnet *dev, struct urb *urb) -{ - struct usb_cdc_notification *event; - - dev_dbg(&dev->udev->dev, "%s", __func__); - - if (urb->actual_length < sizeof *event) - return; - - /* Add cases to handle other standard notifications. */ - event = urb->transfer_buffer; - switch (event->bNotificationType) { - case USB_CDC_NOTIFY_NETWORK_CONNECTION: - case USB_CDC_NOTIFY_SPEED_CHANGE: - /* USB 305 sends those */ - break; - case USB_CDC_NOTIFY_RESPONSE_AVAILABLE: - sierra_net_defer_kevent(dev, SIERRA_NET_EVENT_RESP_AVAIL); - break; - default: - netdev_err(dev->net, ": unexpected notification %02x!\n", - event->bNotificationType); - break; - } -} - -static void sierra_net_get_drvinfo(struct net_device *net, - struct ethtool_drvinfo *info) -{ - /* 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); -} - -static u32 sierra_net_get_link(struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - /* Report link is down whenever the interface is down */ - return sierra_net_get_private(dev)->link_up && netif_running(net); -} - -static const struct ethtool_ops sierra_net_ethtool_ops = { - .get_drvinfo = sierra_net_get_drvinfo, - .get_link = sierra_net_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, -}; - -/* MTU can not be more than 1500 bytes, enforce it. */ -static int sierra_net_change_mtu(struct net_device *net, int new_mtu) -{ - if (new_mtu > SIERRA_NET_MAX_SUPPORTED_MTU) - return -EINVAL; - - return usbnet_change_mtu(net, new_mtu); -} - -static int is_whitelisted(const u8 ifnum, - const struct sierra_net_iface_info *whitelist) -{ - if (whitelist) { - const u8 *list = whitelist->ifaceinfo; - int i; - - for (i = 0; i < whitelist->infolen; i++) { - if (list[i] == ifnum) - return 1; - } - } - return 0; -} - -static int sierra_net_get_fw_attr(struct usbnet *dev, u16 *datap) -{ - int result = 0; - u16 *attrdata; - - attrdata = kmalloc(sizeof(*attrdata), GFP_KERNEL); - if (!attrdata) - return -ENOMEM; - - result = usb_control_msg( - dev->udev, - usb_rcvctrlpipe(dev->udev, 0), - /* _u8 vendor specific request */ - SWI_USB_REQUEST_GET_FW_ATTR, - USB_DIR_IN | USB_TYPE_VENDOR, /* __u8 request type */ - 0x0000, /* __u16 value not used */ - 0x0000, /* __u16 index not used */ - attrdata, /* char *data */ - sizeof(*attrdata), /* __u16 size */ - USB_CTRL_SET_TIMEOUT); /* int timeout */ - - if (result < 0) { - kfree(attrdata); - return -EIO; - } - - *datap = *attrdata; - - kfree(attrdata); - return result; -} - -/* - * collects the bulk endpoints, the status endpoint. - */ -static int sierra_net_bind(struct usbnet *dev, struct usb_interface *intf) -{ - u8 ifacenum; - u8 numendpoints; - u16 fwattr = 0; - int status; - struct ethhdr *eth; - struct sierra_net_data *priv; - static const u8 sync_tmplate[sizeof(priv->sync_msg)] = { - 0x00, 0x00, SIERRA_NET_HIP_MSYNC_ID, 0x00}; - static const u8 shdwn_tmplate[sizeof(priv->shdwn_msg)] = { - 0x00, 0x00, SIERRA_NET_HIP_SHUTD_ID, 0x00}; - - struct sierra_net_info_data *data = - (struct sierra_net_info_data *)dev->driver_info->data; - - dev_dbg(&dev->udev->dev, "%s", __func__); - - ifacenum = intf->cur_altsetting->desc.bInterfaceNumber; - /* We only accept certain interfaces */ - if (!is_whitelisted(ifacenum, &data->whitelist)) { - dev_dbg(&dev->udev->dev, "Ignoring interface: %d", ifacenum); - return -ENODEV; - } - numendpoints = intf->cur_altsetting->desc.bNumEndpoints; - /* We have three endpoints, bulk in and out, and a status */ - if (numendpoints != 3) { - dev_err(&dev->udev->dev, "Expected 3 endpoints, found: %d", - numendpoints); - return -ENODEV; - } - /* Status endpoint set in usbnet_get_endpoints() */ - dev->status = NULL; - status = usbnet_get_endpoints(dev, intf); - if (status < 0) { - dev_err(&dev->udev->dev, "Error in usbnet_get_endpoints (%d)", - status); - return -ENODEV; - } - /* Initialize sierra private data */ - priv = kzalloc(sizeof *priv, GFP_KERNEL); - if (!priv) { - dev_err(&dev->udev->dev, "No memory"); - return -ENOMEM; - } - - priv->usbnet = dev; - priv->ifnum = ifacenum; - dev->net->netdev_ops = &sierra_net_device_ops; - - /* change MAC addr to include, ifacenum, and to be unique */ - dev->net->dev_addr[ETH_ALEN-2] = atomic_inc_return(&iface_counter); - dev->net->dev_addr[ETH_ALEN-1] = ifacenum; - - /* we will have to manufacture ethernet headers, prepare template */ - eth = (struct ethhdr *)priv->ethr_hdr_tmpl; - memcpy(ð->h_dest, dev->net->dev_addr, ETH_ALEN); - eth->h_proto = cpu_to_be16(ETH_P_IP); - - /* prepare shutdown message template */ - memcpy(priv->shdwn_msg, shdwn_tmplate, sizeof(priv->shdwn_msg)); - /* set context index initially to 0 - prepares tx hdr template */ - sierra_net_set_ctx_index(priv, 0); - - /* decrease the rx_urb_size and max_tx_size to 4k on USB 1.1 */ - dev->rx_urb_size = data->rx_urb_size; - if (dev->udev->speed != USB_SPEED_HIGH) - dev->rx_urb_size = min_t(size_t, 4096, data->rx_urb_size); - - dev->net->hard_header_len += SIERRA_NET_HIP_EXT_HDR_LEN; - dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len; - - /* Set up the netdev */ - dev->net->flags |= IFF_NOARP; - dev->net->ethtool_ops = &sierra_net_ethtool_ops; - netif_carrier_off(dev->net); - - sierra_net_set_private(dev, priv); - - priv->kevent_flags = 0; - - /* Use the shared workqueue */ - INIT_WORK(&priv->sierra_net_kevent, sierra_net_kevent); - - /* Only need to do this once */ - init_timer(&priv->sync_timer); - - /* verify fw attributes */ - status = sierra_net_get_fw_attr(dev, &fwattr); - dev_dbg(&dev->udev->dev, "Fw attr: %x\n", fwattr); - - /* test whether firmware supports DHCP */ - if (!(status == sizeof(fwattr) && (fwattr & SWI_GET_FW_ATTR_MASK))) { - /* found incompatible firmware version */ - dev_err(&dev->udev->dev, "Incompatible driver and firmware" - " versions\n"); - kfree(priv); - return -ENODEV; - } - /* prepare sync message from template */ - memcpy(priv->sync_msg, sync_tmplate, sizeof(priv->sync_msg)); - - /* initiate the sync sequence */ - sierra_net_dosync(dev); - - return 0; -} - -static void sierra_net_unbind(struct usbnet *dev, struct usb_interface *intf) -{ - int status; - struct sierra_net_data *priv = sierra_net_get_private(dev); - - dev_dbg(&dev->udev->dev, "%s", __func__); - - /* kill the timer and work */ - del_timer_sync(&priv->sync_timer); - cancel_work_sync(&priv->sierra_net_kevent); - - /* tell modem we are going away */ - status = sierra_net_send_cmd(dev, priv->shdwn_msg, - sizeof(priv->shdwn_msg), "Shutdown"); - if (status < 0) - netdev_err(dev->net, - "usb_control_msg failed, status %d\n", status); - - sierra_net_set_private(dev, NULL); - - kfree(priv); -} - -static struct sk_buff *sierra_net_skb_clone(struct usbnet *dev, - struct sk_buff *skb, int len) -{ - struct sk_buff *new_skb; - - /* clone skb */ - new_skb = skb_clone(skb, GFP_ATOMIC); - - /* remove len bytes from original */ - skb_pull(skb, len); - - /* trim next packet to it's length */ - if (new_skb) { - skb_trim(new_skb, len); - } else { - if (netif_msg_rx_err(dev)) - netdev_err(dev->net, "failed to get skb\n"); - dev->net->stats.rx_dropped++; - } - - return new_skb; -} - -/* ---------------------------- Receive data path ----------------------*/ -static int sierra_net_rx_fixup(struct usbnet *dev, struct sk_buff *skb) -{ - int err; - struct hip_hdr hh; - struct sk_buff *new_skb; - - dev_dbg(&dev->udev->dev, "%s", __func__); - - /* could contain multiple packets */ - while (likely(skb->len)) { - err = parse_hip(skb->data, skb->len, &hh); - if (err) { - if (netif_msg_rx_err(dev)) - netdev_err(dev->net, "Invalid HIP header %d\n", - err); - /* dev->net->stats.rx_errors incremented by caller */ - dev->net->stats.rx_length_errors++; - return 0; - } - - /* Validate Extended HIP header */ - if (!hh.extmsgid.is_present - || hh.extmsgid.word != SIERRA_NET_HIP_EXT_IP_IN_ID) { - if (netif_msg_rx_err(dev)) - netdev_err(dev->net, "HIP/ETH: Invalid pkt\n"); - - dev->net->stats.rx_frame_errors++; - /* dev->net->stats.rx_errors incremented by caller */; - return 0; - } - - skb_pull(skb, hh.hdrlen); - - /* We are going to accept this packet, prepare it */ - memcpy(skb->data, sierra_net_get_private(dev)->ethr_hdr_tmpl, - ETH_HLEN); - - /* Last packet in batch handled by usbnet */ - if (hh.payload_len.word == skb->len) - return 1; - - new_skb = sierra_net_skb_clone(dev, skb, hh.payload_len.word); - if (new_skb) - usbnet_skb_return(dev, new_skb); - - } /* while */ - - return 0; -} - -/* ---------------------------- Transmit data path ----------------------*/ -struct sk_buff *sierra_net_tx_fixup(struct usbnet *dev, struct sk_buff *skb, - gfp_t flags) -{ - struct sierra_net_data *priv = sierra_net_get_private(dev); - u16 len; - bool need_tail; - - BUILD_BUG_ON(FIELD_SIZEOF(struct usbnet, data) - < sizeof(struct cdc_state)); - - dev_dbg(&dev->udev->dev, "%s", __func__); - if (priv->link_up && check_ethip_packet(skb, dev) && is_ip(skb)) { - /* enough head room as is? */ - if (SIERRA_NET_HIP_EXT_HDR_LEN <= skb_headroom(skb)) { - /* Save the Eth/IP length and set up HIP hdr */ - len = skb->len; - skb_push(skb, SIERRA_NET_HIP_EXT_HDR_LEN); - /* Handle ZLP issue */ - need_tail = ((len + SIERRA_NET_HIP_EXT_HDR_LEN) - % dev->maxpacket == 0); - if (need_tail) { - if (unlikely(skb_tailroom(skb) == 0)) { - netdev_err(dev->net, "tx_fixup:" - "no room for packet\n"); - dev_kfree_skb_any(skb); - return NULL; - } else { - skb->data[skb->len] = 0; - __skb_put(skb, 1); - len = len + 1; - } - } - build_hip(skb->data, len, priv); - return skb; - } else { - /* - * compensate in the future if necessary - */ - netdev_err(dev->net, "tx_fixup: no room for HIP\n"); - } /* headroom */ - } - - if (!priv->link_up) - dev->net->stats.tx_carrier_errors++; - - /* tx_dropped incremented by usbnet */ - - /* filter the packet out, release it */ - dev_kfree_skb_any(skb); - return NULL; -} - -static const u8 sierra_net_ifnum_list[] = { 7, 10, 11 }; -static const struct sierra_net_info_data sierra_net_info_data_direct_ip = { - .rx_urb_size = 8 * 1024, - .whitelist = { - .infolen = ARRAY_SIZE(sierra_net_ifnum_list), - .ifaceinfo = sierra_net_ifnum_list - } -}; - -static const struct driver_info sierra_net_info_direct_ip = { - .description = "Sierra Wireless USB-to-WWAN Modem", - .flags = FLAG_WWAN | FLAG_SEND_ZLP, - .bind = sierra_net_bind, - .unbind = sierra_net_unbind, - .status = sierra_net_status, - .rx_fixup = sierra_net_rx_fixup, - .tx_fixup = sierra_net_tx_fixup, - .data = (unsigned long)&sierra_net_info_data_direct_ip, -}; - -static const struct usb_device_id products[] = { - {USB_DEVICE(0x1199, 0x68A3), /* Sierra Wireless USB-to-WWAN modem */ - .driver_info = (unsigned long) &sierra_net_info_direct_ip}, - {USB_DEVICE(0x0F3D, 0x68A3), /* AT&T Direct IP modem */ - .driver_info = (unsigned long) &sierra_net_info_direct_ip}, - {USB_DEVICE(0x1199, 0x68AA), /* Sierra Wireless Direct IP LTE modem */ - .driver_info = (unsigned long) &sierra_net_info_direct_ip}, - {USB_DEVICE(0x0F3D, 0x68AA), /* AT&T Direct IP LTE modem */ - .driver_info = (unsigned long) &sierra_net_info_direct_ip}, - - {}, /* last item */ -}; -MODULE_DEVICE_TABLE(usb, products); - -/* We are based on usbnet, so let it handle the USB driver specifics */ -static struct usb_driver sierra_net_driver = { - .name = "sierra_net", - .id_table = products, - .probe = usbnet_probe, - .disconnect = usbnet_disconnect, - .suspend = usbnet_suspend, - .resume = usbnet_resume, - .no_dynamic_id = 1, -}; - -module_usb_driver(sierra_net_driver); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/net/usb/smsc75xx.c b/ANDROID_3.4.5/drivers/net/usb/smsc75xx.c deleted file mode 100644 index 00103a8c..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/smsc75xx.c +++ /dev/null @@ -1,1260 +0,0 @@ - /*************************************************************************** - * - * Copyright (C) 2007-2010 SMSC - * - * 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/mii.h> -#include <linux/usb.h> -#include <linux/crc32.h> -#include <linux/usb/usbnet.h> -#include <linux/slab.h> -#include "smsc75xx.h" - -#define SMSC_CHIPNAME "smsc75xx" -#define SMSC_DRIVER_VERSION "1.0.0" -#define HS_USB_PKT_SIZE (512) -#define FS_USB_PKT_SIZE (64) -#define DEFAULT_HS_BURST_CAP_SIZE (16 * 1024 + 5 * HS_USB_PKT_SIZE) -#define DEFAULT_FS_BURST_CAP_SIZE (6 * 1024 + 33 * FS_USB_PKT_SIZE) -#define DEFAULT_BULK_IN_DELAY (0x00002000) -#define MAX_SINGLE_PACKET_SIZE (9000) -#define LAN75XX_EEPROM_MAGIC (0x7500) -#define EEPROM_MAC_OFFSET (0x01) -#define DEFAULT_TX_CSUM_ENABLE (true) -#define DEFAULT_RX_CSUM_ENABLE (true) -#define DEFAULT_TSO_ENABLE (true) -#define SMSC75XX_INTERNAL_PHY_ID (1) -#define SMSC75XX_TX_OVERHEAD (8) -#define MAX_RX_FIFO_SIZE (20 * 1024) -#define MAX_TX_FIFO_SIZE (12 * 1024) -#define USB_VENDOR_ID_SMSC (0x0424) -#define USB_PRODUCT_ID_LAN7500 (0x7500) -#define USB_PRODUCT_ID_LAN7505 (0x7505) -#define RXW_PADDING 2 - -#define check_warn(ret, fmt, args...) \ - ({ if (ret < 0) netdev_warn(dev->net, fmt, ##args); }) - -#define check_warn_return(ret, fmt, args...) \ - ({ if (ret < 0) { netdev_warn(dev->net, fmt, ##args); return ret; } }) - -#define check_warn_goto_done(ret, fmt, args...) \ - ({ if (ret < 0) { netdev_warn(dev->net, fmt, ##args); goto done; } }) - -struct smsc75xx_priv { - struct usbnet *dev; - u32 rfe_ctl; - u32 multicast_hash_table[DP_SEL_VHF_HASH_LEN]; - struct mutex dataport_mutex; - spinlock_t rfe_ctl_lock; - struct work_struct set_multicast; -}; - -struct usb_context { - struct usb_ctrlrequest req; - struct usbnet *dev; -}; - -static bool turbo_mode = true; -module_param(turbo_mode, bool, 0644); -MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction"); - -static int __must_check smsc75xx_read_reg(struct usbnet *dev, u32 index, - u32 *data) -{ - u32 *buf = kmalloc(4, GFP_KERNEL); - int ret; - - BUG_ON(!dev); - - if (!buf) - return -ENOMEM; - - ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), - USB_VENDOR_REQUEST_READ_REGISTER, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 00, index, buf, 4, USB_CTRL_GET_TIMEOUT); - - if (unlikely(ret < 0)) - netdev_warn(dev->net, - "Failed to read reg index 0x%08x: %d", index, ret); - - le32_to_cpus(buf); - *data = *buf; - kfree(buf); - - return ret; -} - -static int __must_check smsc75xx_write_reg(struct usbnet *dev, u32 index, - u32 data) -{ - u32 *buf = kmalloc(4, GFP_KERNEL); - int ret; - - BUG_ON(!dev); - - if (!buf) - return -ENOMEM; - - *buf = data; - cpu_to_le32s(buf); - - ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), - USB_VENDOR_REQUEST_WRITE_REGISTER, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 00, index, buf, 4, USB_CTRL_SET_TIMEOUT); - - if (unlikely(ret < 0)) - netdev_warn(dev->net, - "Failed to write reg index 0x%08x: %d", index, ret); - - kfree(buf); - - return ret; -} - -/* Loop until the read is completed with timeout - * called with phy_mutex held */ -static int smsc75xx_phy_wait_not_busy(struct usbnet *dev) -{ - unsigned long start_time = jiffies; - u32 val; - int ret; - - do { - ret = smsc75xx_read_reg(dev, MII_ACCESS, &val); - check_warn_return(ret, "Error reading MII_ACCESS"); - - if (!(val & MII_ACCESS_BUSY)) - return 0; - } while (!time_after(jiffies, start_time + HZ)); - - return -EIO; -} - -static int smsc75xx_mdio_read(struct net_device *netdev, int phy_id, int idx) -{ - struct usbnet *dev = netdev_priv(netdev); - u32 val, addr; - int ret; - - mutex_lock(&dev->phy_mutex); - - /* confirm MII not busy */ - ret = smsc75xx_phy_wait_not_busy(dev); - check_warn_goto_done(ret, "MII is busy in smsc75xx_mdio_read"); - - /* set the address, index & direction (read from PHY) */ - phy_id &= dev->mii.phy_id_mask; - idx &= dev->mii.reg_num_mask; - addr = ((phy_id << MII_ACCESS_PHY_ADDR_SHIFT) & MII_ACCESS_PHY_ADDR) - | ((idx << MII_ACCESS_REG_ADDR_SHIFT) & MII_ACCESS_REG_ADDR) - | MII_ACCESS_READ | MII_ACCESS_BUSY; - ret = smsc75xx_write_reg(dev, MII_ACCESS, addr); - check_warn_goto_done(ret, "Error writing MII_ACCESS"); - - ret = smsc75xx_phy_wait_not_busy(dev); - check_warn_goto_done(ret, "Timed out reading MII reg %02X", idx); - - ret = smsc75xx_read_reg(dev, MII_DATA, &val); - check_warn_goto_done(ret, "Error reading MII_DATA"); - - ret = (u16)(val & 0xFFFF); - -done: - mutex_unlock(&dev->phy_mutex); - return ret; -} - -static void smsc75xx_mdio_write(struct net_device *netdev, int phy_id, int idx, - int regval) -{ - struct usbnet *dev = netdev_priv(netdev); - u32 val, addr; - int ret; - - mutex_lock(&dev->phy_mutex); - - /* confirm MII not busy */ - ret = smsc75xx_phy_wait_not_busy(dev); - check_warn_goto_done(ret, "MII is busy in smsc75xx_mdio_write"); - - val = regval; - ret = smsc75xx_write_reg(dev, MII_DATA, val); - check_warn_goto_done(ret, "Error writing MII_DATA"); - - /* set the address, index & direction (write to PHY) */ - phy_id &= dev->mii.phy_id_mask; - idx &= dev->mii.reg_num_mask; - addr = ((phy_id << MII_ACCESS_PHY_ADDR_SHIFT) & MII_ACCESS_PHY_ADDR) - | ((idx << MII_ACCESS_REG_ADDR_SHIFT) & MII_ACCESS_REG_ADDR) - | MII_ACCESS_WRITE | MII_ACCESS_BUSY; - ret = smsc75xx_write_reg(dev, MII_ACCESS, addr); - check_warn_goto_done(ret, "Error writing MII_ACCESS"); - - ret = smsc75xx_phy_wait_not_busy(dev); - check_warn_goto_done(ret, "Timed out writing MII reg %02X", idx); - -done: - mutex_unlock(&dev->phy_mutex); -} - -static int smsc75xx_wait_eeprom(struct usbnet *dev) -{ - unsigned long start_time = jiffies; - u32 val; - int ret; - - do { - ret = smsc75xx_read_reg(dev, E2P_CMD, &val); - check_warn_return(ret, "Error reading E2P_CMD"); - - if (!(val & E2P_CMD_BUSY) || (val & E2P_CMD_TIMEOUT)) - break; - udelay(40); - } while (!time_after(jiffies, start_time + HZ)); - - if (val & (E2P_CMD_TIMEOUT | E2P_CMD_BUSY)) { - netdev_warn(dev->net, "EEPROM read operation timeout"); - return -EIO; - } - - return 0; -} - -static int smsc75xx_eeprom_confirm_not_busy(struct usbnet *dev) -{ - unsigned long start_time = jiffies; - u32 val; - int ret; - - do { - ret = smsc75xx_read_reg(dev, E2P_CMD, &val); - check_warn_return(ret, "Error reading E2P_CMD"); - - if (!(val & E2P_CMD_BUSY)) - return 0; - - udelay(40); - } while (!time_after(jiffies, start_time + HZ)); - - netdev_warn(dev->net, "EEPROM is busy"); - return -EIO; -} - -static int smsc75xx_read_eeprom(struct usbnet *dev, u32 offset, u32 length, - u8 *data) -{ - u32 val; - int i, ret; - - BUG_ON(!dev); - BUG_ON(!data); - - ret = smsc75xx_eeprom_confirm_not_busy(dev); - if (ret) - return ret; - - for (i = 0; i < length; i++) { - val = E2P_CMD_BUSY | E2P_CMD_READ | (offset & E2P_CMD_ADDR); - ret = smsc75xx_write_reg(dev, E2P_CMD, val); - check_warn_return(ret, "Error writing E2P_CMD"); - - ret = smsc75xx_wait_eeprom(dev); - if (ret < 0) - return ret; - - ret = smsc75xx_read_reg(dev, E2P_DATA, &val); - check_warn_return(ret, "Error reading E2P_DATA"); - - data[i] = val & 0xFF; - offset++; - } - - return 0; -} - -static int smsc75xx_write_eeprom(struct usbnet *dev, u32 offset, u32 length, - u8 *data) -{ - u32 val; - int i, ret; - - BUG_ON(!dev); - BUG_ON(!data); - - ret = smsc75xx_eeprom_confirm_not_busy(dev); - if (ret) - return ret; - - /* Issue write/erase enable command */ - val = E2P_CMD_BUSY | E2P_CMD_EWEN; - ret = smsc75xx_write_reg(dev, E2P_CMD, val); - check_warn_return(ret, "Error writing E2P_CMD"); - - ret = smsc75xx_wait_eeprom(dev); - if (ret < 0) - return ret; - - for (i = 0; i < length; i++) { - - /* Fill data register */ - val = data[i]; - ret = smsc75xx_write_reg(dev, E2P_DATA, val); - check_warn_return(ret, "Error writing E2P_DATA"); - - /* Send "write" command */ - val = E2P_CMD_BUSY | E2P_CMD_WRITE | (offset & E2P_CMD_ADDR); - ret = smsc75xx_write_reg(dev, E2P_CMD, val); - check_warn_return(ret, "Error writing E2P_CMD"); - - ret = smsc75xx_wait_eeprom(dev); - if (ret < 0) - return ret; - - offset++; - } - - return 0; -} - -static int smsc75xx_dataport_wait_not_busy(struct usbnet *dev) -{ - int i, ret; - - for (i = 0; i < 100; i++) { - u32 dp_sel; - ret = smsc75xx_read_reg(dev, DP_SEL, &dp_sel); - check_warn_return(ret, "Error reading DP_SEL"); - - if (dp_sel & DP_SEL_DPRDY) - return 0; - - udelay(40); - } - - netdev_warn(dev->net, "smsc75xx_dataport_wait_not_busy timed out"); - - return -EIO; -} - -static int smsc75xx_dataport_write(struct usbnet *dev, u32 ram_select, u32 addr, - u32 length, u32 *buf) -{ - struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); - u32 dp_sel; - int i, ret; - - mutex_lock(&pdata->dataport_mutex); - - ret = smsc75xx_dataport_wait_not_busy(dev); - check_warn_goto_done(ret, "smsc75xx_dataport_write busy on entry"); - - ret = smsc75xx_read_reg(dev, DP_SEL, &dp_sel); - check_warn_goto_done(ret, "Error reading DP_SEL"); - - dp_sel &= ~DP_SEL_RSEL; - dp_sel |= ram_select; - ret = smsc75xx_write_reg(dev, DP_SEL, dp_sel); - check_warn_goto_done(ret, "Error writing DP_SEL"); - - for (i = 0; i < length; i++) { - ret = smsc75xx_write_reg(dev, DP_ADDR, addr + i); - check_warn_goto_done(ret, "Error writing DP_ADDR"); - - ret = smsc75xx_write_reg(dev, DP_DATA, buf[i]); - check_warn_goto_done(ret, "Error writing DP_DATA"); - - ret = smsc75xx_write_reg(dev, DP_CMD, DP_CMD_WRITE); - check_warn_goto_done(ret, "Error writing DP_CMD"); - - ret = smsc75xx_dataport_wait_not_busy(dev); - check_warn_goto_done(ret, "smsc75xx_dataport_write timeout"); - } - -done: - mutex_unlock(&pdata->dataport_mutex); - return ret; -} - -/* returns hash bit number for given MAC address */ -static u32 smsc75xx_hash(char addr[ETH_ALEN]) -{ - return (ether_crc(ETH_ALEN, addr) >> 23) & 0x1ff; -} - -static void smsc75xx_deferred_multicast_write(struct work_struct *param) -{ - struct smsc75xx_priv *pdata = - container_of(param, struct smsc75xx_priv, set_multicast); - struct usbnet *dev = pdata->dev; - int ret; - - netif_dbg(dev, drv, dev->net, "deferred multicast write 0x%08x", - pdata->rfe_ctl); - - smsc75xx_dataport_write(dev, DP_SEL_VHF, DP_SEL_VHF_VLAN_LEN, - DP_SEL_VHF_HASH_LEN, pdata->multicast_hash_table); - - ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); - check_warn(ret, "Error writing RFE_CRL"); -} - -static void smsc75xx_set_multicast(struct net_device *netdev) -{ - struct usbnet *dev = netdev_priv(netdev); - struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); - unsigned long flags; - int i; - - spin_lock_irqsave(&pdata->rfe_ctl_lock, flags); - - pdata->rfe_ctl &= - ~(RFE_CTL_AU | RFE_CTL_AM | RFE_CTL_DPF | RFE_CTL_MHF); - pdata->rfe_ctl |= RFE_CTL_AB; - - for (i = 0; i < DP_SEL_VHF_HASH_LEN; i++) - pdata->multicast_hash_table[i] = 0; - - if (dev->net->flags & IFF_PROMISC) { - netif_dbg(dev, drv, dev->net, "promiscuous mode enabled"); - pdata->rfe_ctl |= RFE_CTL_AM | RFE_CTL_AU; - } else if (dev->net->flags & IFF_ALLMULTI) { - netif_dbg(dev, drv, dev->net, "receive all multicast enabled"); - pdata->rfe_ctl |= RFE_CTL_AM | RFE_CTL_DPF; - } else if (!netdev_mc_empty(dev->net)) { - struct netdev_hw_addr *ha; - - netif_dbg(dev, drv, dev->net, "receive multicast hash filter"); - - pdata->rfe_ctl |= RFE_CTL_MHF | RFE_CTL_DPF; - - netdev_for_each_mc_addr(ha, netdev) { - u32 bitnum = smsc75xx_hash(ha->addr); - pdata->multicast_hash_table[bitnum / 32] |= - (1 << (bitnum % 32)); - } - } else { - netif_dbg(dev, drv, dev->net, "receive own packets only"); - pdata->rfe_ctl |= RFE_CTL_DPF; - } - - spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags); - - /* defer register writes to a sleepable context */ - schedule_work(&pdata->set_multicast); -} - -static int smsc75xx_update_flowcontrol(struct usbnet *dev, u8 duplex, - u16 lcladv, u16 rmtadv) -{ - u32 flow = 0, fct_flow = 0; - int ret; - - if (duplex == DUPLEX_FULL) { - u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv); - - if (cap & FLOW_CTRL_TX) { - flow = (FLOW_TX_FCEN | 0xFFFF); - /* set fct_flow thresholds to 20% and 80% */ - fct_flow = (8 << 8) | 32; - } - - if (cap & FLOW_CTRL_RX) - flow |= FLOW_RX_FCEN; - - netif_dbg(dev, link, dev->net, "rx pause %s, tx pause %s", - (cap & FLOW_CTRL_RX ? "enabled" : "disabled"), - (cap & FLOW_CTRL_TX ? "enabled" : "disabled")); - } else { - netif_dbg(dev, link, dev->net, "half duplex"); - } - - ret = smsc75xx_write_reg(dev, FLOW, flow); - check_warn_return(ret, "Error writing FLOW"); - - ret = smsc75xx_write_reg(dev, FCT_FLOW, fct_flow); - check_warn_return(ret, "Error writing FCT_FLOW"); - - return 0; -} - -static int smsc75xx_link_reset(struct usbnet *dev) -{ - struct mii_if_info *mii = &dev->mii; - struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; - u16 lcladv, rmtadv; - int ret; - - /* read and write to clear phy interrupt status */ - ret = smsc75xx_mdio_read(dev->net, mii->phy_id, PHY_INT_SRC); - check_warn_return(ret, "Error reading PHY_INT_SRC"); - smsc75xx_mdio_write(dev->net, mii->phy_id, PHY_INT_SRC, 0xffff); - - ret = smsc75xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL); - check_warn_return(ret, "Error writing INT_STS"); - - mii_check_media(mii, 1, 1); - mii_ethtool_gset(&dev->mii, &ecmd); - lcladv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE); - rmtadv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_LPA); - - netif_dbg(dev, link, dev->net, "speed: %u duplex: %d lcladv: %04x" - " rmtadv: %04x", ethtool_cmd_speed(&ecmd), - ecmd.duplex, lcladv, rmtadv); - - return smsc75xx_update_flowcontrol(dev, ecmd.duplex, lcladv, rmtadv); -} - -static void smsc75xx_status(struct usbnet *dev, struct urb *urb) -{ - u32 intdata; - - if (urb->actual_length != 4) { - netdev_warn(dev->net, - "unexpected urb length %d", urb->actual_length); - return; - } - - memcpy(&intdata, urb->transfer_buffer, 4); - le32_to_cpus(&intdata); - - netif_dbg(dev, link, dev->net, "intdata: 0x%08X", intdata); - - if (intdata & INT_ENP_PHY_INT) - usbnet_defer_kevent(dev, EVENT_LINK_RESET); - else - netdev_warn(dev->net, - "unexpected interrupt, intdata=0x%08X", intdata); -} - -static int smsc75xx_ethtool_get_eeprom_len(struct net_device *net) -{ - return MAX_EEPROM_SIZE; -} - -static int smsc75xx_ethtool_get_eeprom(struct net_device *netdev, - struct ethtool_eeprom *ee, u8 *data) -{ - struct usbnet *dev = netdev_priv(netdev); - - ee->magic = LAN75XX_EEPROM_MAGIC; - - return smsc75xx_read_eeprom(dev, ee->offset, ee->len, data); -} - -static int smsc75xx_ethtool_set_eeprom(struct net_device *netdev, - struct ethtool_eeprom *ee, u8 *data) -{ - struct usbnet *dev = netdev_priv(netdev); - - if (ee->magic != LAN75XX_EEPROM_MAGIC) { - netdev_warn(dev->net, - "EEPROM: magic value mismatch: 0x%x", ee->magic); - return -EINVAL; - } - - return smsc75xx_write_eeprom(dev, ee->offset, ee->len, data); -} - -static const struct ethtool_ops smsc75xx_ethtool_ops = { - .get_link = usbnet_get_link, - .nway_reset = usbnet_nway_reset, - .get_drvinfo = usbnet_get_drvinfo, - .get_msglevel = usbnet_get_msglevel, - .set_msglevel = usbnet_set_msglevel, - .get_settings = usbnet_get_settings, - .set_settings = usbnet_set_settings, - .get_eeprom_len = smsc75xx_ethtool_get_eeprom_len, - .get_eeprom = smsc75xx_ethtool_get_eeprom, - .set_eeprom = smsc75xx_ethtool_set_eeprom, -}; - -static int smsc75xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) -{ - struct usbnet *dev = netdev_priv(netdev); - - if (!netif_running(netdev)) - return -EINVAL; - - return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); -} - -static void smsc75xx_init_mac_address(struct usbnet *dev) -{ - /* try reading mac address from EEPROM */ - if (smsc75xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN, - dev->net->dev_addr) == 0) { - if (is_valid_ether_addr(dev->net->dev_addr)) { - /* eeprom values are valid so use them */ - netif_dbg(dev, ifup, dev->net, - "MAC address read from EEPROM"); - return; - } - } - - /* no eeprom, or eeprom values are invalid. generate random MAC */ - eth_hw_addr_random(dev->net); - netif_dbg(dev, ifup, dev->net, "MAC address set to random_ether_addr"); -} - -static int smsc75xx_set_mac_address(struct usbnet *dev) -{ - u32 addr_lo = dev->net->dev_addr[0] | dev->net->dev_addr[1] << 8 | - dev->net->dev_addr[2] << 16 | dev->net->dev_addr[3] << 24; - u32 addr_hi = dev->net->dev_addr[4] | dev->net->dev_addr[5] << 8; - - int ret = smsc75xx_write_reg(dev, RX_ADDRH, addr_hi); - check_warn_return(ret, "Failed to write RX_ADDRH: %d", ret); - - ret = smsc75xx_write_reg(dev, RX_ADDRL, addr_lo); - check_warn_return(ret, "Failed to write RX_ADDRL: %d", ret); - - addr_hi |= ADDR_FILTX_FB_VALID; - ret = smsc75xx_write_reg(dev, ADDR_FILTX, addr_hi); - check_warn_return(ret, "Failed to write ADDR_FILTX: %d", ret); - - ret = smsc75xx_write_reg(dev, ADDR_FILTX + 4, addr_lo); - check_warn_return(ret, "Failed to write ADDR_FILTX+4: %d", ret); - - return 0; -} - -static int smsc75xx_phy_initialize(struct usbnet *dev) -{ - int bmcr, ret, timeout = 0; - - /* Initialize MII structure */ - dev->mii.dev = dev->net; - dev->mii.mdio_read = smsc75xx_mdio_read; - dev->mii.mdio_write = smsc75xx_mdio_write; - dev->mii.phy_id_mask = 0x1f; - dev->mii.reg_num_mask = 0x1f; - dev->mii.supports_gmii = 1; - dev->mii.phy_id = SMSC75XX_INTERNAL_PHY_ID; - - /* reset phy and wait for reset to complete */ - smsc75xx_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); - - do { - msleep(10); - bmcr = smsc75xx_mdio_read(dev->net, dev->mii.phy_id, MII_BMCR); - check_warn_return(bmcr, "Error reading MII_BMCR"); - timeout++; - } while ((bmcr & BMCR_RESET) && (timeout < 100)); - - if (timeout >= 100) { - netdev_warn(dev->net, "timeout on PHY Reset"); - return -EIO; - } - - smsc75xx_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, - ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP | - ADVERTISE_PAUSE_ASYM); - smsc75xx_mdio_write(dev->net, dev->mii.phy_id, MII_CTRL1000, - ADVERTISE_1000FULL); - - /* read and write to clear phy interrupt status */ - ret = smsc75xx_mdio_read(dev->net, dev->mii.phy_id, PHY_INT_SRC); - check_warn_return(ret, "Error reading PHY_INT_SRC"); - smsc75xx_mdio_write(dev->net, dev->mii.phy_id, PHY_INT_SRC, 0xffff); - - smsc75xx_mdio_write(dev->net, dev->mii.phy_id, PHY_INT_MASK, - PHY_INT_MASK_DEFAULT); - mii_nway_restart(&dev->mii); - - netif_dbg(dev, ifup, dev->net, "phy initialised successfully"); - return 0; -} - -static int smsc75xx_set_rx_max_frame_length(struct usbnet *dev, int size) -{ - int ret = 0; - u32 buf; - bool rxenabled; - - ret = smsc75xx_read_reg(dev, MAC_RX, &buf); - check_warn_return(ret, "Failed to read MAC_RX: %d", ret); - - rxenabled = ((buf & MAC_RX_RXEN) != 0); - - if (rxenabled) { - buf &= ~MAC_RX_RXEN; - ret = smsc75xx_write_reg(dev, MAC_RX, buf); - check_warn_return(ret, "Failed to write MAC_RX: %d", ret); - } - - /* add 4 to size for FCS */ - buf &= ~MAC_RX_MAX_SIZE; - buf |= (((size + 4) << MAC_RX_MAX_SIZE_SHIFT) & MAC_RX_MAX_SIZE); - - ret = smsc75xx_write_reg(dev, MAC_RX, buf); - check_warn_return(ret, "Failed to write MAC_RX: %d", ret); - - if (rxenabled) { - buf |= MAC_RX_RXEN; - ret = smsc75xx_write_reg(dev, MAC_RX, buf); - check_warn_return(ret, "Failed to write MAC_RX: %d", ret); - } - - return 0; -} - -static int smsc75xx_change_mtu(struct net_device *netdev, int new_mtu) -{ - struct usbnet *dev = netdev_priv(netdev); - - int ret = smsc75xx_set_rx_max_frame_length(dev, new_mtu); - check_warn_return(ret, "Failed to set mac rx frame length"); - - return usbnet_change_mtu(netdev, new_mtu); -} - -/* Enable or disable Rx checksum offload engine */ -static int smsc75xx_set_features(struct net_device *netdev, - netdev_features_t features) -{ - struct usbnet *dev = netdev_priv(netdev); - struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); - unsigned long flags; - int ret; - - spin_lock_irqsave(&pdata->rfe_ctl_lock, flags); - - if (features & NETIF_F_RXCSUM) - pdata->rfe_ctl |= RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM; - else - pdata->rfe_ctl &= ~(RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM); - - spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags); - /* it's racing here! */ - - ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); - check_warn_return(ret, "Error writing RFE_CTL"); - - return 0; -} - -static int smsc75xx_reset(struct usbnet *dev) -{ - struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); - u32 buf; - int ret = 0, timeout; - - netif_dbg(dev, ifup, dev->net, "entering smsc75xx_reset"); - - ret = smsc75xx_read_reg(dev, HW_CFG, &buf); - check_warn_return(ret, "Failed to read HW_CFG: %d", ret); - - buf |= HW_CFG_LRST; - - ret = smsc75xx_write_reg(dev, HW_CFG, buf); - check_warn_return(ret, "Failed to write HW_CFG: %d", ret); - - timeout = 0; - do { - msleep(10); - ret = smsc75xx_read_reg(dev, HW_CFG, &buf); - check_warn_return(ret, "Failed to read HW_CFG: %d", ret); - timeout++; - } while ((buf & HW_CFG_LRST) && (timeout < 100)); - - if (timeout >= 100) { - netdev_warn(dev->net, "timeout on completion of Lite Reset"); - return -EIO; - } - - netif_dbg(dev, ifup, dev->net, "Lite reset complete, resetting PHY"); - - ret = smsc75xx_read_reg(dev, PMT_CTL, &buf); - check_warn_return(ret, "Failed to read PMT_CTL: %d", ret); - - buf |= PMT_CTL_PHY_RST; - - ret = smsc75xx_write_reg(dev, PMT_CTL, buf); - check_warn_return(ret, "Failed to write PMT_CTL: %d", ret); - - timeout = 0; - do { - msleep(10); - ret = smsc75xx_read_reg(dev, PMT_CTL, &buf); - check_warn_return(ret, "Failed to read PMT_CTL: %d", ret); - timeout++; - } while ((buf & PMT_CTL_PHY_RST) && (timeout < 100)); - - if (timeout >= 100) { - netdev_warn(dev->net, "timeout waiting for PHY Reset"); - return -EIO; - } - - netif_dbg(dev, ifup, dev->net, "PHY reset complete"); - - smsc75xx_init_mac_address(dev); - - ret = smsc75xx_set_mac_address(dev); - check_warn_return(ret, "Failed to set mac address"); - - netif_dbg(dev, ifup, dev->net, "MAC Address: %pM", dev->net->dev_addr); - - ret = smsc75xx_read_reg(dev, HW_CFG, &buf); - check_warn_return(ret, "Failed to read HW_CFG: %d", ret); - - netif_dbg(dev, ifup, dev->net, "Read Value from HW_CFG : 0x%08x", buf); - - buf |= HW_CFG_BIR; - - ret = smsc75xx_write_reg(dev, HW_CFG, buf); - check_warn_return(ret, "Failed to write HW_CFG: %d", ret); - - ret = smsc75xx_read_reg(dev, HW_CFG, &buf); - check_warn_return(ret, "Failed to read HW_CFG: %d", ret); - - netif_dbg(dev, ifup, dev->net, "Read Value from HW_CFG after " - "writing HW_CFG_BIR: 0x%08x", buf); - - if (!turbo_mode) { - buf = 0; - dev->rx_urb_size = MAX_SINGLE_PACKET_SIZE; - } else if (dev->udev->speed == USB_SPEED_HIGH) { - buf = DEFAULT_HS_BURST_CAP_SIZE / HS_USB_PKT_SIZE; - dev->rx_urb_size = DEFAULT_HS_BURST_CAP_SIZE; - } else { - buf = DEFAULT_FS_BURST_CAP_SIZE / FS_USB_PKT_SIZE; - dev->rx_urb_size = DEFAULT_FS_BURST_CAP_SIZE; - } - - netif_dbg(dev, ifup, dev->net, "rx_urb_size=%ld", - (ulong)dev->rx_urb_size); - - ret = smsc75xx_write_reg(dev, BURST_CAP, buf); - check_warn_return(ret, "Failed to write BURST_CAP: %d", ret); - - ret = smsc75xx_read_reg(dev, BURST_CAP, &buf); - check_warn_return(ret, "Failed to read BURST_CAP: %d", ret); - - netif_dbg(dev, ifup, dev->net, - "Read Value from BURST_CAP after writing: 0x%08x", buf); - - ret = smsc75xx_write_reg(dev, BULK_IN_DLY, DEFAULT_BULK_IN_DELAY); - check_warn_return(ret, "Failed to write BULK_IN_DLY: %d", ret); - - ret = smsc75xx_read_reg(dev, BULK_IN_DLY, &buf); - check_warn_return(ret, "Failed to read BULK_IN_DLY: %d", ret); - - netif_dbg(dev, ifup, dev->net, - "Read Value from BULK_IN_DLY after writing: 0x%08x", buf); - - if (turbo_mode) { - ret = smsc75xx_read_reg(dev, HW_CFG, &buf); - check_warn_return(ret, "Failed to read HW_CFG: %d", ret); - - netif_dbg(dev, ifup, dev->net, "HW_CFG: 0x%08x", buf); - - buf |= (HW_CFG_MEF | HW_CFG_BCE); - - ret = smsc75xx_write_reg(dev, HW_CFG, buf); - check_warn_return(ret, "Failed to write HW_CFG: %d", ret); - - ret = smsc75xx_read_reg(dev, HW_CFG, &buf); - check_warn_return(ret, "Failed to read HW_CFG: %d", ret); - - netif_dbg(dev, ifup, dev->net, "HW_CFG: 0x%08x", buf); - } - - /* set FIFO sizes */ - buf = (MAX_RX_FIFO_SIZE - 512) / 512; - ret = smsc75xx_write_reg(dev, FCT_RX_FIFO_END, buf); - check_warn_return(ret, "Failed to write FCT_RX_FIFO_END: %d", ret); - - netif_dbg(dev, ifup, dev->net, "FCT_RX_FIFO_END set to 0x%08x", buf); - - buf = (MAX_TX_FIFO_SIZE - 512) / 512; - ret = smsc75xx_write_reg(dev, FCT_TX_FIFO_END, buf); - check_warn_return(ret, "Failed to write FCT_TX_FIFO_END: %d", ret); - - netif_dbg(dev, ifup, dev->net, "FCT_TX_FIFO_END set to 0x%08x", buf); - - ret = smsc75xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL); - check_warn_return(ret, "Failed to write INT_STS: %d", ret); - - ret = smsc75xx_read_reg(dev, ID_REV, &buf); - check_warn_return(ret, "Failed to read ID_REV: %d", ret); - - netif_dbg(dev, ifup, dev->net, "ID_REV = 0x%08x", buf); - - /* Configure GPIO pins as LED outputs */ - ret = smsc75xx_read_reg(dev, LED_GPIO_CFG, &buf); - check_warn_return(ret, "Failed to read LED_GPIO_CFG: %d", ret); - - buf &= ~(LED_GPIO_CFG_LED2_FUN_SEL | LED_GPIO_CFG_LED10_FUN_SEL); - buf |= LED_GPIO_CFG_LEDGPIO_EN | LED_GPIO_CFG_LED2_FUN_SEL; - - ret = smsc75xx_write_reg(dev, LED_GPIO_CFG, buf); - check_warn_return(ret, "Failed to write LED_GPIO_CFG: %d", ret); - - ret = smsc75xx_write_reg(dev, FLOW, 0); - check_warn_return(ret, "Failed to write FLOW: %d", ret); - - ret = smsc75xx_write_reg(dev, FCT_FLOW, 0); - check_warn_return(ret, "Failed to write FCT_FLOW: %d", ret); - - /* Don't need rfe_ctl_lock during initialisation */ - ret = smsc75xx_read_reg(dev, RFE_CTL, &pdata->rfe_ctl); - check_warn_return(ret, "Failed to read RFE_CTL: %d", ret); - - pdata->rfe_ctl |= RFE_CTL_AB | RFE_CTL_DPF; - - ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); - check_warn_return(ret, "Failed to write RFE_CTL: %d", ret); - - ret = smsc75xx_read_reg(dev, RFE_CTL, &pdata->rfe_ctl); - check_warn_return(ret, "Failed to read RFE_CTL: %d", ret); - - netif_dbg(dev, ifup, dev->net, "RFE_CTL set to 0x%08x", pdata->rfe_ctl); - - /* Enable or disable checksum offload engines */ - smsc75xx_set_features(dev->net, dev->net->features); - - smsc75xx_set_multicast(dev->net); - - ret = smsc75xx_phy_initialize(dev); - check_warn_return(ret, "Failed to initialize PHY: %d", ret); - - ret = smsc75xx_read_reg(dev, INT_EP_CTL, &buf); - check_warn_return(ret, "Failed to read INT_EP_CTL: %d", ret); - - /* enable PHY interrupts */ - buf |= INT_ENP_PHY_INT; - - ret = smsc75xx_write_reg(dev, INT_EP_CTL, buf); - check_warn_return(ret, "Failed to write INT_EP_CTL: %d", ret); - - /* allow mac to detect speed and duplex from phy */ - ret = smsc75xx_read_reg(dev, MAC_CR, &buf); - check_warn_return(ret, "Failed to read MAC_CR: %d", ret); - - buf |= (MAC_CR_ADD | MAC_CR_ASD); - ret = smsc75xx_write_reg(dev, MAC_CR, buf); - check_warn_return(ret, "Failed to write MAC_CR: %d", ret); - - ret = smsc75xx_read_reg(dev, MAC_TX, &buf); - check_warn_return(ret, "Failed to read MAC_TX: %d", ret); - - buf |= MAC_TX_TXEN; - - ret = smsc75xx_write_reg(dev, MAC_TX, buf); - check_warn_return(ret, "Failed to write MAC_TX: %d", ret); - - netif_dbg(dev, ifup, dev->net, "MAC_TX set to 0x%08x", buf); - - ret = smsc75xx_read_reg(dev, FCT_TX_CTL, &buf); - check_warn_return(ret, "Failed to read FCT_TX_CTL: %d", ret); - - buf |= FCT_TX_CTL_EN; - - ret = smsc75xx_write_reg(dev, FCT_TX_CTL, buf); - check_warn_return(ret, "Failed to write FCT_TX_CTL: %d", ret); - - netif_dbg(dev, ifup, dev->net, "FCT_TX_CTL set to 0x%08x", buf); - - ret = smsc75xx_set_rx_max_frame_length(dev, 1514); - check_warn_return(ret, "Failed to set max rx frame length"); - - ret = smsc75xx_read_reg(dev, MAC_RX, &buf); - check_warn_return(ret, "Failed to read MAC_RX: %d", ret); - - buf |= MAC_RX_RXEN; - - ret = smsc75xx_write_reg(dev, MAC_RX, buf); - check_warn_return(ret, "Failed to write MAC_RX: %d", ret); - - netif_dbg(dev, ifup, dev->net, "MAC_RX set to 0x%08x", buf); - - ret = smsc75xx_read_reg(dev, FCT_RX_CTL, &buf); - check_warn_return(ret, "Failed to read FCT_RX_CTL: %d", ret); - - buf |= FCT_RX_CTL_EN; - - ret = smsc75xx_write_reg(dev, FCT_RX_CTL, buf); - check_warn_return(ret, "Failed to write FCT_RX_CTL: %d", ret); - - netif_dbg(dev, ifup, dev->net, "FCT_RX_CTL set to 0x%08x", buf); - - netif_dbg(dev, ifup, dev->net, "smsc75xx_reset, return 0"); - return 0; -} - -static const struct net_device_ops smsc75xx_netdev_ops = { - .ndo_open = usbnet_open, - .ndo_stop = usbnet_stop, - .ndo_start_xmit = usbnet_start_xmit, - .ndo_tx_timeout = usbnet_tx_timeout, - .ndo_change_mtu = smsc75xx_change_mtu, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, - .ndo_do_ioctl = smsc75xx_ioctl, - .ndo_set_rx_mode = smsc75xx_set_multicast, - .ndo_set_features = smsc75xx_set_features, -}; - -static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf) -{ - struct smsc75xx_priv *pdata = NULL; - int ret; - - printk(KERN_INFO SMSC_CHIPNAME " v" SMSC_DRIVER_VERSION "\n"); - - ret = usbnet_get_endpoints(dev, intf); - check_warn_return(ret, "usbnet_get_endpoints failed: %d", ret); - - dev->data[0] = (unsigned long)kzalloc(sizeof(struct smsc75xx_priv), - GFP_KERNEL); - - pdata = (struct smsc75xx_priv *)(dev->data[0]); - if (!pdata) { - netdev_warn(dev->net, "Unable to allocate smsc75xx_priv"); - return -ENOMEM; - } - - pdata->dev = dev; - - spin_lock_init(&pdata->rfe_ctl_lock); - mutex_init(&pdata->dataport_mutex); - - INIT_WORK(&pdata->set_multicast, smsc75xx_deferred_multicast_write); - - if (DEFAULT_TX_CSUM_ENABLE) { - dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; - if (DEFAULT_TSO_ENABLE) - dev->net->features |= NETIF_F_SG | - NETIF_F_TSO | NETIF_F_TSO6; - } - if (DEFAULT_RX_CSUM_ENABLE) - dev->net->features |= NETIF_F_RXCSUM; - - dev->net->hw_features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | - NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_RXCSUM; - - /* Init all registers */ - ret = smsc75xx_reset(dev); - - dev->net->netdev_ops = &smsc75xx_netdev_ops; - dev->net->ethtool_ops = &smsc75xx_ethtool_ops; - dev->net->flags |= IFF_MULTICAST; - dev->net->hard_header_len += SMSC75XX_TX_OVERHEAD; - dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len; - return 0; -} - -static void smsc75xx_unbind(struct usbnet *dev, struct usb_interface *intf) -{ - struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); - if (pdata) { - netif_dbg(dev, ifdown, dev->net, "free pdata"); - kfree(pdata); - pdata = NULL; - dev->data[0] = 0; - } -} - -static void smsc75xx_rx_csum_offload(struct usbnet *dev, struct sk_buff *skb, - u32 rx_cmd_a, u32 rx_cmd_b) -{ - if (!(dev->net->features & NETIF_F_RXCSUM) || - unlikely(rx_cmd_a & RX_CMD_A_LCSM)) { - skb->ip_summed = CHECKSUM_NONE; - } else { - skb->csum = ntohs((u16)(rx_cmd_b >> RX_CMD_B_CSUM_SHIFT)); - skb->ip_summed = CHECKSUM_COMPLETE; - } -} - -static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) -{ - while (skb->len > 0) { - u32 rx_cmd_a, rx_cmd_b, align_count, size; - struct sk_buff *ax_skb; - unsigned char *packet; - - memcpy(&rx_cmd_a, skb->data, sizeof(rx_cmd_a)); - le32_to_cpus(&rx_cmd_a); - skb_pull(skb, 4); - - memcpy(&rx_cmd_b, skb->data, sizeof(rx_cmd_b)); - le32_to_cpus(&rx_cmd_b); - skb_pull(skb, 4 + RXW_PADDING); - - packet = skb->data; - - /* get the packet length */ - size = (rx_cmd_a & RX_CMD_A_LEN) - RXW_PADDING; - align_count = (4 - ((size + RXW_PADDING) % 4)) % 4; - - if (unlikely(rx_cmd_a & RX_CMD_A_RED)) { - netif_dbg(dev, rx_err, dev->net, - "Error rx_cmd_a=0x%08x", rx_cmd_a); - dev->net->stats.rx_errors++; - dev->net->stats.rx_dropped++; - - if (rx_cmd_a & RX_CMD_A_FCS) - dev->net->stats.rx_crc_errors++; - else if (rx_cmd_a & (RX_CMD_A_LONG | RX_CMD_A_RUNT)) - dev->net->stats.rx_frame_errors++; - } else { - /* ETH_FRAME_LEN + 4(CRC) + 2(COE) + 4(Vlan) */ - if (unlikely(size > (ETH_FRAME_LEN + 12))) { - netif_dbg(dev, rx_err, dev->net, - "size err rx_cmd_a=0x%08x", rx_cmd_a); - return 0; - } - - /* last frame in this batch */ - if (skb->len == size) { - smsc75xx_rx_csum_offload(dev, skb, rx_cmd_a, - rx_cmd_b); - - skb_trim(skb, skb->len - 4); /* remove fcs */ - skb->truesize = size + sizeof(struct sk_buff); - - return 1; - } - - ax_skb = skb_clone(skb, GFP_ATOMIC); - if (unlikely(!ax_skb)) { - netdev_warn(dev->net, "Error allocating skb"); - return 0; - } - - ax_skb->len = size; - ax_skb->data = packet; - skb_set_tail_pointer(ax_skb, size); - - smsc75xx_rx_csum_offload(dev, ax_skb, rx_cmd_a, - rx_cmd_b); - - skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */ - ax_skb->truesize = size + sizeof(struct sk_buff); - - usbnet_skb_return(dev, ax_skb); - } - - skb_pull(skb, size); - - /* padding bytes before the next frame starts */ - if (skb->len) - skb_pull(skb, align_count); - } - - if (unlikely(skb->len < 0)) { - netdev_warn(dev->net, "invalid rx length<0 %d", skb->len); - return 0; - } - - return 1; -} - -static struct sk_buff *smsc75xx_tx_fixup(struct usbnet *dev, - struct sk_buff *skb, gfp_t flags) -{ - u32 tx_cmd_a, tx_cmd_b; - - skb_linearize(skb); - - if (skb_headroom(skb) < SMSC75XX_TX_OVERHEAD) { - struct sk_buff *skb2 = - skb_copy_expand(skb, SMSC75XX_TX_OVERHEAD, 0, flags); - dev_kfree_skb_any(skb); - skb = skb2; - if (!skb) - return NULL; - } - - tx_cmd_a = (u32)(skb->len & TX_CMD_A_LEN) | TX_CMD_A_FCS; - - if (skb->ip_summed == CHECKSUM_PARTIAL) - tx_cmd_a |= TX_CMD_A_IPE | TX_CMD_A_TPE; - - if (skb_is_gso(skb)) { - u16 mss = max(skb_shinfo(skb)->gso_size, TX_MSS_MIN); - tx_cmd_b = (mss << TX_CMD_B_MSS_SHIFT) & TX_CMD_B_MSS; - - tx_cmd_a |= TX_CMD_A_LSO; - } else { - tx_cmd_b = 0; - } - - skb_push(skb, 4); - cpu_to_le32s(&tx_cmd_b); - memcpy(skb->data, &tx_cmd_b, 4); - - skb_push(skb, 4); - cpu_to_le32s(&tx_cmd_a); - memcpy(skb->data, &tx_cmd_a, 4); - - return skb; -} - -static const struct driver_info smsc75xx_info = { - .description = "smsc75xx USB 2.0 Gigabit Ethernet", - .bind = smsc75xx_bind, - .unbind = smsc75xx_unbind, - .link_reset = smsc75xx_link_reset, - .reset = smsc75xx_reset, - .rx_fixup = smsc75xx_rx_fixup, - .tx_fixup = smsc75xx_tx_fixup, - .status = smsc75xx_status, - .flags = FLAG_ETHER | FLAG_SEND_ZLP | FLAG_LINK_INTR, -}; - -static const struct usb_device_id products[] = { - { - /* SMSC7500 USB Gigabit Ethernet Device */ - USB_DEVICE(USB_VENDOR_ID_SMSC, USB_PRODUCT_ID_LAN7500), - .driver_info = (unsigned long) &smsc75xx_info, - }, - { - /* SMSC7500 USB Gigabit Ethernet Device */ - USB_DEVICE(USB_VENDOR_ID_SMSC, USB_PRODUCT_ID_LAN7505), - .driver_info = (unsigned long) &smsc75xx_info, - }, - { }, /* END */ -}; -MODULE_DEVICE_TABLE(usb, products); - -static struct usb_driver smsc75xx_driver = { - .name = SMSC_CHIPNAME, - .id_table = products, - .probe = usbnet_probe, - .suspend = usbnet_suspend, - .resume = usbnet_resume, - .disconnect = usbnet_disconnect, -}; - -module_usb_driver(smsc75xx_driver); - -MODULE_AUTHOR("Nancy Lin"); -MODULE_AUTHOR("Steve Glendinning <steve.glendinning@smsc.com>"); -MODULE_DESCRIPTION("SMSC75XX USB 2.0 Gigabit Ethernet Devices"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/net/usb/smsc75xx.h b/ANDROID_3.4.5/drivers/net/usb/smsc75xx.h deleted file mode 100644 index 16e98c77..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/smsc75xx.h +++ /dev/null @@ -1,421 +0,0 @@ - /*************************************************************************** - * - * Copyright (C) 2007-2010 SMSC - * - * 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 _SMSC75XX_H -#define _SMSC75XX_H - -/* Tx command words */ -#define TX_CMD_A_LSO (0x08000000) -#define TX_CMD_A_IPE (0x04000000) -#define TX_CMD_A_TPE (0x02000000) -#define TX_CMD_A_IVTG (0x01000000) -#define TX_CMD_A_RVTG (0x00800000) -#define TX_CMD_A_FCS (0x00400000) -#define TX_CMD_A_LEN (0x000FFFFF) - -#define TX_CMD_B_MSS (0x3FFF0000) -#define TX_CMD_B_MSS_SHIFT (16) -#define TX_MSS_MIN ((u16)8) -#define TX_CMD_B_VTAG (0x0000FFFF) - -/* Rx command words */ -#define RX_CMD_A_ICE (0x80000000) -#define RX_CMD_A_TCE (0x40000000) -#define RX_CMD_A_IPV (0x20000000) -#define RX_CMD_A_PID (0x18000000) -#define RX_CMD_A_PID_NIP (0x00000000) -#define RX_CMD_A_PID_TCP (0x08000000) -#define RX_CMD_A_PID_UDP (0x10000000) -#define RX_CMD_A_PID_PP (0x18000000) -#define RX_CMD_A_PFF (0x04000000) -#define RX_CMD_A_BAM (0x02000000) -#define RX_CMD_A_MAM (0x01000000) -#define RX_CMD_A_FVTG (0x00800000) -#define RX_CMD_A_RED (0x00400000) -#define RX_CMD_A_RWT (0x00200000) -#define RX_CMD_A_RUNT (0x00100000) -#define RX_CMD_A_LONG (0x00080000) -#define RX_CMD_A_RXE (0x00040000) -#define RX_CMD_A_DRB (0x00020000) -#define RX_CMD_A_FCS (0x00010000) -#define RX_CMD_A_UAM (0x00008000) -#define RX_CMD_A_LCSM (0x00004000) -#define RX_CMD_A_LEN (0x00003FFF) - -#define RX_CMD_B_CSUM (0xFFFF0000) -#define RX_CMD_B_CSUM_SHIFT (16) -#define RX_CMD_B_VTAG (0x0000FFFF) - -/* SCSRs */ -#define ID_REV (0x0000) - -#define FPGA_REV (0x0004) - -#define BOND_CTL (0x0008) - -#define INT_STS (0x000C) -#define INT_STS_RDFO_INT (0x00400000) -#define INT_STS_TXE_INT (0x00200000) -#define INT_STS_MACRTO_INT (0x00100000) -#define INT_STS_TX_DIS_INT (0x00080000) -#define INT_STS_RX_DIS_INT (0x00040000) -#define INT_STS_PHY_INT_ (0x00020000) -#define INT_STS_MAC_ERR_INT (0x00008000) -#define INT_STS_TDFU (0x00004000) -#define INT_STS_TDFO (0x00002000) -#define INT_STS_GPIOS (0x00000FFF) -#define INT_STS_CLEAR_ALL (0xFFFFFFFF) - -#define HW_CFG (0x0010) -#define HW_CFG_SMDET_STS (0x00008000) -#define HW_CFG_SMDET_EN (0x00004000) -#define HW_CFG_EEM (0x00002000) -#define HW_CFG_RST_PROTECT (0x00001000) -#define HW_CFG_PORT_SWAP (0x00000800) -#define HW_CFG_PHY_BOOST (0x00000600) -#define HW_CFG_PHY_BOOST_NORMAL (0x00000000) -#define HW_CFG_PHY_BOOST_4 (0x00002000) -#define HW_CFG_PHY_BOOST_8 (0x00004000) -#define HW_CFG_PHY_BOOST_12 (0x00006000) -#define HW_CFG_LEDB (0x00000100) -#define HW_CFG_BIR (0x00000080) -#define HW_CFG_SBP (0x00000040) -#define HW_CFG_IME (0x00000020) -#define HW_CFG_MEF (0x00000010) -#define HW_CFG_ETC (0x00000008) -#define HW_CFG_BCE (0x00000004) -#define HW_CFG_LRST (0x00000002) -#define HW_CFG_SRST (0x00000001) - -#define PMT_CTL (0x0014) -#define PMT_CTL_PHY_PWRUP (0x00000400) -#define PMT_CTL_RES_CLR_WKP_EN (0x00000100) -#define PMT_CTL_DEV_RDY (0x00000080) -#define PMT_CTL_SUS_MODE (0x00000060) -#define PMT_CTL_SUS_MODE_0 (0x00000000) -#define PMT_CTL_SUS_MODE_1 (0x00000020) -#define PMT_CTL_SUS_MODE_2 (0x00000040) -#define PMT_CTL_SUS_MODE_3 (0x00000060) -#define PMT_CTL_PHY_RST (0x00000010) -#define PMT_CTL_WOL_EN (0x00000008) -#define PMT_CTL_ED_EN (0x00000004) -#define PMT_CTL_WUPS (0x00000003) -#define PMT_CTL_WUPS_NO (0x00000000) -#define PMT_CTL_WUPS_ED (0x00000001) -#define PMT_CTL_WUPS_WOL (0x00000002) -#define PMT_CTL_WUPS_MULTI (0x00000003) - -#define LED_GPIO_CFG (0x0018) -#define LED_GPIO_CFG_LED2_FUN_SEL (0x80000000) -#define LED_GPIO_CFG_LED10_FUN_SEL (0x40000000) -#define LED_GPIO_CFG_LEDGPIO_EN (0x0000F000) -#define LED_GPIO_CFG_LEDGPIO_EN_0 (0x00001000) -#define LED_GPIO_CFG_LEDGPIO_EN_1 (0x00002000) -#define LED_GPIO_CFG_LEDGPIO_EN_2 (0x00004000) -#define LED_GPIO_CFG_LEDGPIO_EN_3 (0x00008000) -#define LED_GPIO_CFG_GPBUF (0x00000F00) -#define LED_GPIO_CFG_GPBUF_0 (0x00000100) -#define LED_GPIO_CFG_GPBUF_1 (0x00000200) -#define LED_GPIO_CFG_GPBUF_2 (0x00000400) -#define LED_GPIO_CFG_GPBUF_3 (0x00000800) -#define LED_GPIO_CFG_GPDIR (0x000000F0) -#define LED_GPIO_CFG_GPDIR_0 (0x00000010) -#define LED_GPIO_CFG_GPDIR_1 (0x00000020) -#define LED_GPIO_CFG_GPDIR_2 (0x00000040) -#define LED_GPIO_CFG_GPDIR_3 (0x00000080) -#define LED_GPIO_CFG_GPDATA (0x0000000F) -#define LED_GPIO_CFG_GPDATA_0 (0x00000001) -#define LED_GPIO_CFG_GPDATA_1 (0x00000002) -#define LED_GPIO_CFG_GPDATA_2 (0x00000004) -#define LED_GPIO_CFG_GPDATA_3 (0x00000008) - -#define GPIO_CFG (0x001C) -#define GPIO_CFG_SHIFT (24) -#define GPIO_CFG_GPEN (0xFF000000) -#define GPIO_CFG_GPBUF (0x00FF0000) -#define GPIO_CFG_GPDIR (0x0000FF00) -#define GPIO_CFG_GPDATA (0x000000FF) - -#define GPIO_WAKE (0x0020) -#define GPIO_WAKE_PHY_LINKUP_EN (0x80000000) -#define GPIO_WAKE_POL (0x0FFF0000) -#define GPIO_WAKE_POL_SHIFT (16) -#define GPIO_WAKE_WK (0x00000FFF) - -#define DP_SEL (0x0024) -#define DP_SEL_DPRDY (0x80000000) -#define DP_SEL_RSEL (0x0000000F) -#define DP_SEL_URX (0x00000000) -#define DP_SEL_VHF (0x00000001) -#define DP_SEL_VHF_HASH_LEN (16) -#define DP_SEL_VHF_VLAN_LEN (128) -#define DP_SEL_LSO_HEAD (0x00000002) -#define DP_SEL_FCT_RX (0x00000003) -#define DP_SEL_FCT_TX (0x00000004) -#define DP_SEL_DESCRIPTOR (0x00000005) -#define DP_SEL_WOL (0x00000006) - -#define DP_CMD (0x0028) -#define DP_CMD_WRITE (0x01) -#define DP_CMD_READ (0x00) - -#define DP_ADDR (0x002C) - -#define DP_DATA (0x0030) - -#define BURST_CAP (0x0034) -#define BURST_CAP_MASK (0x0000000F) - -#define INT_EP_CTL (0x0038) -#define INT_EP_CTL_INTEP_ON (0x80000000) -#define INT_EP_CTL_RDFO_EN (0x00400000) -#define INT_EP_CTL_TXE_EN (0x00200000) -#define INT_EP_CTL_MACROTO_EN (0x00100000) -#define INT_EP_CTL_TX_DIS_EN (0x00080000) -#define INT_EP_CTL_RX_DIS_EN (0x00040000) -#define INT_EP_CTL_PHY_EN_ (0x00020000) -#define INT_EP_CTL_MAC_ERR_EN (0x00008000) -#define INT_EP_CTL_TDFU_EN (0x00004000) -#define INT_EP_CTL_TDFO_EN (0x00002000) -#define INT_EP_CTL_RX_FIFO_EN (0x00001000) -#define INT_EP_CTL_GPIOX_EN (0x00000FFF) - -#define BULK_IN_DLY (0x003C) -#define BULK_IN_DLY_MASK (0xFFFF) - -#define E2P_CMD (0x0040) -#define E2P_CMD_BUSY (0x80000000) -#define E2P_CMD_MASK (0x70000000) -#define E2P_CMD_READ (0x00000000) -#define E2P_CMD_EWDS (0x10000000) -#define E2P_CMD_EWEN (0x20000000) -#define E2P_CMD_WRITE (0x30000000) -#define E2P_CMD_WRAL (0x40000000) -#define E2P_CMD_ERASE (0x50000000) -#define E2P_CMD_ERAL (0x60000000) -#define E2P_CMD_RELOAD (0x70000000) -#define E2P_CMD_TIMEOUT (0x00000400) -#define E2P_CMD_LOADED (0x00000200) -#define E2P_CMD_ADDR (0x000001FF) - -#define MAX_EEPROM_SIZE (512) - -#define E2P_DATA (0x0044) -#define E2P_DATA_MASK_ (0x000000FF) - -#define RFE_CTL (0x0060) -#define RFE_CTL_TCPUDP_CKM (0x00001000) -#define RFE_CTL_IP_CKM (0x00000800) -#define RFE_CTL_AB (0x00000400) -#define RFE_CTL_AM (0x00000200) -#define RFE_CTL_AU (0x00000100) -#define RFE_CTL_VS (0x00000080) -#define RFE_CTL_UF (0x00000040) -#define RFE_CTL_VF (0x00000020) -#define RFE_CTL_SPF (0x00000010) -#define RFE_CTL_MHF (0x00000008) -#define RFE_CTL_DHF (0x00000004) -#define RFE_CTL_DPF (0x00000002) -#define RFE_CTL_RST_RF (0x00000001) - -#define VLAN_TYPE (0x0064) -#define VLAN_TYPE_MASK (0x0000FFFF) - -#define FCT_RX_CTL (0x0090) -#define FCT_RX_CTL_EN (0x80000000) -#define FCT_RX_CTL_RST (0x40000000) -#define FCT_RX_CTL_SBF (0x02000000) -#define FCT_RX_CTL_OVERFLOW (0x01000000) -#define FCT_RX_CTL_FRM_DROP (0x00800000) -#define FCT_RX_CTL_RX_NOT_EMPTY (0x00400000) -#define FCT_RX_CTL_RX_EMPTY (0x00200000) -#define FCT_RX_CTL_RX_DISABLED (0x00100000) -#define FCT_RX_CTL_RXUSED (0x0000FFFF) - -#define FCT_TX_CTL (0x0094) -#define FCT_TX_CTL_EN (0x80000000) -#define FCT_TX_CTL_RST (0x40000000) -#define FCT_TX_CTL_TX_NOT_EMPTY (0x00400000) -#define FCT_TX_CTL_TX_EMPTY (0x00200000) -#define FCT_TX_CTL_TX_DISABLED (0x00100000) -#define FCT_TX_CTL_TXUSED (0x0000FFFF) - -#define FCT_RX_FIFO_END (0x0098) -#define FCT_RX_FIFO_END_MASK (0x0000007F) - -#define FCT_TX_FIFO_END (0x009C) -#define FCT_TX_FIFO_END_MASK (0x0000003F) - -#define FCT_FLOW (0x00A0) -#define FCT_FLOW_THRESHOLD_OFF (0x00007F00) -#define FCT_FLOW_THRESHOLD_OFF_SHIFT (8) -#define FCT_FLOW_THRESHOLD_ON (0x0000007F) - -/* MAC CSRs */ -#define MAC_CR (0x100) -#define MAC_CR_ADP (0x00002000) -#define MAC_CR_ADD (0x00001000) -#define MAC_CR_ASD (0x00000800) -#define MAC_CR_INT_LOOP (0x00000400) -#define MAC_CR_BOLMT (0x000000C0) -#define MAC_CR_FDPX (0x00000008) -#define MAC_CR_CFG (0x00000006) -#define MAC_CR_CFG_10 (0x00000000) -#define MAC_CR_CFG_100 (0x00000002) -#define MAC_CR_CFG_1000 (0x00000004) -#define MAC_CR_RST (0x00000001) - -#define MAC_RX (0x104) -#define MAC_RX_MAX_SIZE (0x3FFF0000) -#define MAC_RX_MAX_SIZE_SHIFT (16) -#define MAC_RX_FCS_STRIP (0x00000010) -#define MAC_RX_FSE (0x00000004) -#define MAC_RX_RXD (0x00000002) -#define MAC_RX_RXEN (0x00000001) - -#define MAC_TX (0x108) -#define MAC_TX_BFCS (0x00000004) -#define MAC_TX_TXD (0x00000002) -#define MAC_TX_TXEN (0x00000001) - -#define FLOW (0x10C) -#define FLOW_FORCE_FC (0x80000000) -#define FLOW_TX_FCEN (0x40000000) -#define FLOW_RX_FCEN (0x20000000) -#define FLOW_FPF (0x10000000) -#define FLOW_PAUSE_TIME (0x0000FFFF) - -#define RAND_SEED (0x110) -#define RAND_SEED_MASK (0x0000FFFF) - -#define ERR_STS (0x114) -#define ERR_STS_FCS_ERR (0x00000100) -#define ERR_STS_LFRM_ERR (0x00000080) -#define ERR_STS_RUNT_ERR (0x00000040) -#define ERR_STS_COLLISION_ERR (0x00000010) -#define ERR_STS_ALIGN_ERR (0x00000008) -#define ERR_STS_URUN_ERR (0x00000004) - -#define RX_ADDRH (0x118) -#define RX_ADDRH_MASK (0x0000FFFF) - -#define RX_ADDRL (0x11C) - -#define MII_ACCESS (0x120) -#define MII_ACCESS_PHY_ADDR (0x0000F800) -#define MII_ACCESS_PHY_ADDR_SHIFT (11) -#define MII_ACCESS_REG_ADDR (0x000007C0) -#define MII_ACCESS_REG_ADDR_SHIFT (6) -#define MII_ACCESS_READ (0x00000000) -#define MII_ACCESS_WRITE (0x00000002) -#define MII_ACCESS_BUSY (0x00000001) - -#define MII_DATA (0x124) -#define MII_DATA_MASK (0x0000FFFF) - -#define WUCSR (0x140) -#define WUCSR_PFDA_FR (0x00000080) -#define WUCSR_WUFR (0x00000040) -#define WUCSR_MPR (0x00000020) -#define WUCSR_BCAST_FR (0x00000010) -#define WUCSR_PFDA_EN (0x00000008) -#define WUCSR_WUEN (0x00000004) -#define WUCSR_MPEN (0x00000002) -#define WUCSR_BCST_EN (0x00000001) - -#define WUF_CFGX (0x144) -#define WUF_CFGX_EN (0x80000000) -#define WUF_CFGX_ATYPE (0x03000000) -#define WUF_CFGX_ATYPE_UNICAST (0x00000000) -#define WUF_CFGX_ATYPE_MULTICAST (0x02000000) -#define WUF_CFGX_ATYPE_ALL (0x03000000) -#define WUF_CFGX_PATTERN_OFFSET (0x007F0000) -#define WUF_CFGX_PATTERN_OFFSET_SHIFT (16) -#define WUF_CFGX_CRC16 (0x0000FFFF) -#define WUF_NUM (8) - -#define WUF_MASKX (0x170) -#define WUF_MASKX_AVALID (0x80000000) -#define WUF_MASKX_ATYPE (0x40000000) - -#define ADDR_FILTX (0x300) -#define ADDR_FILTX_FB_VALID (0x80000000) -#define ADDR_FILTX_FB_TYPE (0x40000000) -#define ADDR_FILTX_FB_ADDRHI (0x0000FFFF) -#define ADDR_FILTX_SB_ADDRLO (0xFFFFFFFF) - -#define WUCSR2 (0x500) -#define WUCSR2_NS_RCD (0x00000040) -#define WUCSR2_ARP_RCD (0x00000020) -#define WUCSR2_TCPSYN_RCD (0x00000010) -#define WUCSR2_NS_OFFLOAD (0x00000004) -#define WUCSR2_ARP_OFFLOAD (0x00000002) -#define WUCSR2_TCPSYN_OFFLOAD (0x00000001) - -#define WOL_FIFO_STS (0x504) - -#define IPV6_ADDRX (0x510) - -#define IPV4_ADDRX (0x590) - - -/* Vendor-specific PHY Definitions */ - -/* Mode Control/Status Register */ -#define PHY_MODE_CTRL_STS (17) -#define MODE_CTRL_STS_EDPWRDOWN ((u16)0x2000) -#define MODE_CTRL_STS_ENERGYON ((u16)0x0002) - -#define PHY_INT_SRC (29) -#define PHY_INT_SRC_ENERGY_ON ((u16)0x0080) -#define PHY_INT_SRC_ANEG_COMP ((u16)0x0040) -#define PHY_INT_SRC_REMOTE_FAULT ((u16)0x0020) -#define PHY_INT_SRC_LINK_DOWN ((u16)0x0010) - -#define PHY_INT_MASK (30) -#define PHY_INT_MASK_ENERGY_ON ((u16)0x0080) -#define PHY_INT_MASK_ANEG_COMP ((u16)0x0040) -#define PHY_INT_MASK_REMOTE_FAULT ((u16)0x0020) -#define PHY_INT_MASK_LINK_DOWN ((u16)0x0010) -#define PHY_INT_MASK_DEFAULT (PHY_INT_MASK_ANEG_COMP | \ - PHY_INT_MASK_LINK_DOWN) - -#define PHY_SPECIAL (31) -#define PHY_SPECIAL_SPD ((u16)0x001C) -#define PHY_SPECIAL_SPD_10HALF ((u16)0x0004) -#define PHY_SPECIAL_SPD_10FULL ((u16)0x0014) -#define PHY_SPECIAL_SPD_100HALF ((u16)0x0008) -#define PHY_SPECIAL_SPD_100FULL ((u16)0x0018) - -/* USB Vendor Requests */ -#define USB_VENDOR_REQUEST_WRITE_REGISTER 0xA0 -#define USB_VENDOR_REQUEST_READ_REGISTER 0xA1 -#define USB_VENDOR_REQUEST_GET_STATS 0xA2 - -/* Interrupt Endpoint status word bitfields */ -#define INT_ENP_RDFO_INT ((u32)BIT(22)) -#define INT_ENP_TXE_INT ((u32)BIT(21)) -#define INT_ENP_TX_DIS_INT ((u32)BIT(19)) -#define INT_ENP_RX_DIS_INT ((u32)BIT(18)) -#define INT_ENP_PHY_INT ((u32)BIT(17)) -#define INT_ENP_MAC_ERR_INT ((u32)BIT(15)) -#define INT_ENP_RX_FIFO_DATA_INT ((u32)BIT(12)) - -#endif /* _SMSC75XX_H */ diff --git a/ANDROID_3.4.5/drivers/net/usb/smsc95xx.c b/ANDROID_3.4.5/drivers/net/usb/smsc95xx.c deleted file mode 100644 index 94ae6699..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/smsc95xx.c +++ /dev/null @@ -1,1307 +0,0 @@ - /*************************************************************************** - * - * Copyright (C) 2007-2008 SMSC - * - * 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/mii.h> -#include <linux/usb.h> -#include <linux/crc32.h> -#include <linux/usb/usbnet.h> -#include <linux/slab.h> -#include "smsc95xx.h" - -#define SMSC_CHIPNAME "smsc95xx" -#define SMSC_DRIVER_VERSION "1.0.4" -#define HS_USB_PKT_SIZE (512) -#define FS_USB_PKT_SIZE (64) -#define DEFAULT_HS_BURST_CAP_SIZE (16 * 1024 + 5 * HS_USB_PKT_SIZE) -#define DEFAULT_FS_BURST_CAP_SIZE (6 * 1024 + 33 * FS_USB_PKT_SIZE) -#define DEFAULT_BULK_IN_DELAY (0x00002000) -#define MAX_SINGLE_PACKET_SIZE (2048) -#define LAN95XX_EEPROM_MAGIC (0x9500) -#define EEPROM_MAC_OFFSET (0x01) -#define DEFAULT_TX_CSUM_ENABLE (true) -#define DEFAULT_RX_CSUM_ENABLE (true) -#define SMSC95XX_INTERNAL_PHY_ID (1) -#define SMSC95XX_TX_OVERHEAD (8) -#define SMSC95XX_TX_OVERHEAD_CSUM (12) - -struct smsc95xx_priv { - u32 mac_cr; - u32 hash_hi; - u32 hash_lo; - spinlock_t mac_cr_lock; -}; - -struct usb_context { - struct usb_ctrlrequest req; - struct usbnet *dev; -}; - -static bool turbo_mode = true; -module_param(turbo_mode, bool, 0644); -MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction"); - -static int smsc95xx_read_reg(struct usbnet *dev, u32 index, u32 *data) -{ - u32 *buf = kmalloc(4, GFP_KERNEL); - int ret; - - BUG_ON(!dev); - - if (!buf) - return -ENOMEM; - - ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), - USB_VENDOR_REQUEST_READ_REGISTER, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 00, index, buf, 4, USB_CTRL_GET_TIMEOUT); - - if (unlikely(ret < 0)) - netdev_warn(dev->net, "Failed to read register index 0x%08x\n", index); - - le32_to_cpus(buf); - *data = *buf; - kfree(buf); - - return ret; -} - -static int smsc95xx_write_reg(struct usbnet *dev, u32 index, u32 data) -{ - u32 *buf = kmalloc(4, GFP_KERNEL); - int ret; - - BUG_ON(!dev); - - if (!buf) - return -ENOMEM; - - *buf = data; - cpu_to_le32s(buf); - - ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), - USB_VENDOR_REQUEST_WRITE_REGISTER, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 00, index, buf, 4, USB_CTRL_SET_TIMEOUT); - - if (unlikely(ret < 0)) - netdev_warn(dev->net, "Failed to write register index 0x%08x\n", index); - - kfree(buf); - - return ret; -} - -/* Loop until the read is completed with timeout - * called with phy_mutex held */ -static int smsc95xx_phy_wait_not_busy(struct usbnet *dev) -{ - unsigned long start_time = jiffies; - u32 val; - - do { - smsc95xx_read_reg(dev, MII_ADDR, &val); - if (!(val & MII_BUSY_)) - return 0; - } while (!time_after(jiffies, start_time + HZ)); - - return -EIO; -} - -static int smsc95xx_mdio_read(struct net_device *netdev, int phy_id, int idx) -{ - struct usbnet *dev = netdev_priv(netdev); - u32 val, addr; - - mutex_lock(&dev->phy_mutex); - - /* confirm MII not busy */ - if (smsc95xx_phy_wait_not_busy(dev)) { - netdev_warn(dev->net, "MII is busy in smsc95xx_mdio_read\n"); - mutex_unlock(&dev->phy_mutex); - return -EIO; - } - - /* set the address, index & direction (read from PHY) */ - phy_id &= dev->mii.phy_id_mask; - idx &= dev->mii.reg_num_mask; - addr = (phy_id << 11) | (idx << 6) | MII_READ_; - smsc95xx_write_reg(dev, MII_ADDR, addr); - - if (smsc95xx_phy_wait_not_busy(dev)) { - netdev_warn(dev->net, "Timed out reading MII reg %02X\n", idx); - mutex_unlock(&dev->phy_mutex); - return -EIO; - } - - smsc95xx_read_reg(dev, MII_DATA, &val); - - mutex_unlock(&dev->phy_mutex); - - return (u16)(val & 0xFFFF); -} - -static void smsc95xx_mdio_write(struct net_device *netdev, int phy_id, int idx, - int regval) -{ - struct usbnet *dev = netdev_priv(netdev); - u32 val, addr; - - mutex_lock(&dev->phy_mutex); - - /* confirm MII not busy */ - if (smsc95xx_phy_wait_not_busy(dev)) { - netdev_warn(dev->net, "MII is busy in smsc95xx_mdio_write\n"); - mutex_unlock(&dev->phy_mutex); - return; - } - - val = regval; - smsc95xx_write_reg(dev, MII_DATA, val); - - /* set the address, index & direction (write to PHY) */ - phy_id &= dev->mii.phy_id_mask; - idx &= dev->mii.reg_num_mask; - addr = (phy_id << 11) | (idx << 6) | MII_WRITE_; - smsc95xx_write_reg(dev, MII_ADDR, addr); - - if (smsc95xx_phy_wait_not_busy(dev)) - netdev_warn(dev->net, "Timed out writing MII reg %02X\n", idx); - - mutex_unlock(&dev->phy_mutex); -} - -static int smsc95xx_wait_eeprom(struct usbnet *dev) -{ - unsigned long start_time = jiffies; - u32 val; - - do { - smsc95xx_read_reg(dev, E2P_CMD, &val); - if (!(val & E2P_CMD_BUSY_) || (val & E2P_CMD_TIMEOUT_)) - break; - udelay(40); - } while (!time_after(jiffies, start_time + HZ)); - - if (val & (E2P_CMD_TIMEOUT_ | E2P_CMD_BUSY_)) { - netdev_warn(dev->net, "EEPROM read operation timeout\n"); - return -EIO; - } - - return 0; -} - -static int smsc95xx_eeprom_confirm_not_busy(struct usbnet *dev) -{ - unsigned long start_time = jiffies; - u32 val; - - do { - smsc95xx_read_reg(dev, E2P_CMD, &val); - - if (!(val & E2P_CMD_BUSY_)) - return 0; - - udelay(40); - } while (!time_after(jiffies, start_time + HZ)); - - netdev_warn(dev->net, "EEPROM is busy\n"); - return -EIO; -} - -static int smsc95xx_read_eeprom(struct usbnet *dev, u32 offset, u32 length, - u8 *data) -{ - u32 val; - int i, ret; - - BUG_ON(!dev); - BUG_ON(!data); - - ret = smsc95xx_eeprom_confirm_not_busy(dev); - if (ret) - return ret; - - for (i = 0; i < length; i++) { - val = E2P_CMD_BUSY_ | E2P_CMD_READ_ | (offset & E2P_CMD_ADDR_); - smsc95xx_write_reg(dev, E2P_CMD, val); - - ret = smsc95xx_wait_eeprom(dev); - if (ret < 0) - return ret; - - smsc95xx_read_reg(dev, E2P_DATA, &val); - - data[i] = val & 0xFF; - offset++; - } - - return 0; -} - -static int smsc95xx_write_eeprom(struct usbnet *dev, u32 offset, u32 length, - u8 *data) -{ - u32 val; - int i, ret; - - BUG_ON(!dev); - BUG_ON(!data); - - ret = smsc95xx_eeprom_confirm_not_busy(dev); - if (ret) - return ret; - - /* Issue write/erase enable command */ - val = E2P_CMD_BUSY_ | E2P_CMD_EWEN_; - smsc95xx_write_reg(dev, E2P_CMD, val); - - ret = smsc95xx_wait_eeprom(dev); - if (ret < 0) - return ret; - - for (i = 0; i < length; i++) { - - /* Fill data register */ - val = data[i]; - smsc95xx_write_reg(dev, E2P_DATA, val); - - /* Send "write" command */ - val = E2P_CMD_BUSY_ | E2P_CMD_WRITE_ | (offset & E2P_CMD_ADDR_); - smsc95xx_write_reg(dev, E2P_CMD, val); - - ret = smsc95xx_wait_eeprom(dev); - if (ret < 0) - return ret; - - offset++; - } - - return 0; -} - -static void smsc95xx_async_cmd_callback(struct urb *urb) -{ - struct usb_context *usb_context = urb->context; - struct usbnet *dev = usb_context->dev; - int status = urb->status; - - if (status < 0) - netdev_warn(dev->net, "async callback failed with %d\n", status); - - kfree(usb_context); - usb_free_urb(urb); -} - -static int smsc95xx_write_reg_async(struct usbnet *dev, u16 index, u32 *data) -{ - struct usb_context *usb_context; - int status; - struct urb *urb; - const u16 size = 4; - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) { - netdev_warn(dev->net, "Error allocating URB\n"); - return -ENOMEM; - } - - usb_context = kmalloc(sizeof(struct usb_context), GFP_ATOMIC); - if (usb_context == NULL) { - netdev_warn(dev->net, "Error allocating control msg\n"); - usb_free_urb(urb); - return -ENOMEM; - } - - usb_context->req.bRequestType = - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; - usb_context->req.bRequest = USB_VENDOR_REQUEST_WRITE_REGISTER; - usb_context->req.wValue = 00; - usb_context->req.wIndex = cpu_to_le16(index); - usb_context->req.wLength = cpu_to_le16(size); - - usb_fill_control_urb(urb, dev->udev, usb_sndctrlpipe(dev->udev, 0), - (void *)&usb_context->req, data, size, - smsc95xx_async_cmd_callback, - (void *)usb_context); - - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status < 0) { - netdev_warn(dev->net, "Error submitting control msg, sts=%d\n", - status); - kfree(usb_context); - usb_free_urb(urb); - } - - return status; -} - -/* returns hash bit number for given MAC address - * example: - * 01 00 5E 00 00 01 -> returns bit number 31 */ -static unsigned int smsc95xx_hash(char addr[ETH_ALEN]) -{ - return (ether_crc(ETH_ALEN, addr) >> 26) & 0x3f; -} - -static void smsc95xx_set_multicast(struct net_device *netdev) -{ - struct usbnet *dev = netdev_priv(netdev); - struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); - unsigned long flags; - - pdata->hash_hi = 0; - pdata->hash_lo = 0; - - spin_lock_irqsave(&pdata->mac_cr_lock, flags); - - if (dev->net->flags & IFF_PROMISC) { - netif_dbg(dev, drv, dev->net, "promiscuous mode enabled\n"); - pdata->mac_cr |= MAC_CR_PRMS_; - pdata->mac_cr &= ~(MAC_CR_MCPAS_ | MAC_CR_HPFILT_); - } else if (dev->net->flags & IFF_ALLMULTI) { - netif_dbg(dev, drv, dev->net, "receive all multicast enabled\n"); - pdata->mac_cr |= MAC_CR_MCPAS_; - pdata->mac_cr &= ~(MAC_CR_PRMS_ | MAC_CR_HPFILT_); - } else if (!netdev_mc_empty(dev->net)) { - struct netdev_hw_addr *ha; - - pdata->mac_cr |= MAC_CR_HPFILT_; - pdata->mac_cr &= ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_); - - netdev_for_each_mc_addr(ha, netdev) { - u32 bitnum = smsc95xx_hash(ha->addr); - u32 mask = 0x01 << (bitnum & 0x1F); - if (bitnum & 0x20) - pdata->hash_hi |= mask; - else - pdata->hash_lo |= mask; - } - - netif_dbg(dev, drv, dev->net, "HASHH=0x%08X, HASHL=0x%08X\n", - pdata->hash_hi, pdata->hash_lo); - } else { - netif_dbg(dev, drv, dev->net, "receive own packets only\n"); - pdata->mac_cr &= - ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_ | MAC_CR_HPFILT_); - } - - spin_unlock_irqrestore(&pdata->mac_cr_lock, flags); - - /* Initiate async writes, as we can't wait for completion here */ - smsc95xx_write_reg_async(dev, HASHH, &pdata->hash_hi); - smsc95xx_write_reg_async(dev, HASHL, &pdata->hash_lo); - smsc95xx_write_reg_async(dev, MAC_CR, &pdata->mac_cr); -} - -static void smsc95xx_phy_update_flowcontrol(struct usbnet *dev, u8 duplex, - u16 lcladv, u16 rmtadv) -{ - u32 flow, afc_cfg = 0; - - int ret = smsc95xx_read_reg(dev, AFC_CFG, &afc_cfg); - if (ret < 0) { - netdev_warn(dev->net, "error reading AFC_CFG\n"); - return; - } - - if (duplex == DUPLEX_FULL) { - u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv); - - if (cap & FLOW_CTRL_RX) - flow = 0xFFFF0002; - else - flow = 0; - - if (cap & FLOW_CTRL_TX) - afc_cfg |= 0xF; - else - afc_cfg &= ~0xF; - - netif_dbg(dev, link, dev->net, "rx pause %s, tx pause %s\n", - cap & FLOW_CTRL_RX ? "enabled" : "disabled", - cap & FLOW_CTRL_TX ? "enabled" : "disabled"); - } else { - netif_dbg(dev, link, dev->net, "half duplex\n"); - flow = 0; - afc_cfg |= 0xF; - } - - smsc95xx_write_reg(dev, FLOW, flow); - smsc95xx_write_reg(dev, AFC_CFG, afc_cfg); -} - -static int smsc95xx_link_reset(struct usbnet *dev) -{ - struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); - struct mii_if_info *mii = &dev->mii; - struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; - unsigned long flags; - u16 lcladv, rmtadv; - u32 intdata; - - /* clear interrupt status */ - smsc95xx_mdio_read(dev->net, mii->phy_id, PHY_INT_SRC); - intdata = 0xFFFFFFFF; - smsc95xx_write_reg(dev, INT_STS, intdata); - - mii_check_media(mii, 1, 1); - mii_ethtool_gset(&dev->mii, &ecmd); - lcladv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE); - rmtadv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_LPA); - - netif_dbg(dev, link, dev->net, - "speed: %u duplex: %d lcladv: %04x rmtadv: %04x\n", - ethtool_cmd_speed(&ecmd), ecmd.duplex, lcladv, rmtadv); - - spin_lock_irqsave(&pdata->mac_cr_lock, flags); - if (ecmd.duplex != DUPLEX_FULL) { - pdata->mac_cr &= ~MAC_CR_FDPX_; - pdata->mac_cr |= MAC_CR_RCVOWN_; - } else { - pdata->mac_cr &= ~MAC_CR_RCVOWN_; - pdata->mac_cr |= MAC_CR_FDPX_; - } - spin_unlock_irqrestore(&pdata->mac_cr_lock, flags); - - smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr); - - smsc95xx_phy_update_flowcontrol(dev, ecmd.duplex, lcladv, rmtadv); - - return 0; -} - -static void smsc95xx_status(struct usbnet *dev, struct urb *urb) -{ - u32 intdata; - - if (urb->actual_length != 4) { - netdev_warn(dev->net, "unexpected urb length %d\n", - urb->actual_length); - return; - } - - memcpy(&intdata, urb->transfer_buffer, 4); - le32_to_cpus(&intdata); - - netif_dbg(dev, link, dev->net, "intdata: 0x%08X\n", intdata); - - if (intdata & INT_ENP_PHY_INT_) - usbnet_defer_kevent(dev, EVENT_LINK_RESET); - else - netdev_warn(dev->net, "unexpected interrupt, intdata=0x%08X\n", - intdata); -} - -/* Enable or disable Tx & Rx checksum offload engines */ -static int smsc95xx_set_features(struct net_device *netdev, - netdev_features_t features) -{ - struct usbnet *dev = netdev_priv(netdev); - u32 read_buf; - int ret; - - ret = smsc95xx_read_reg(dev, COE_CR, &read_buf); - if (ret < 0) { - netdev_warn(dev->net, "Failed to read COE_CR: %d\n", ret); - return ret; - } - - if (features & NETIF_F_HW_CSUM) - read_buf |= Tx_COE_EN_; - else - read_buf &= ~Tx_COE_EN_; - - if (features & NETIF_F_RXCSUM) - read_buf |= Rx_COE_EN_; - else - read_buf &= ~Rx_COE_EN_; - - ret = smsc95xx_write_reg(dev, COE_CR, read_buf); - if (ret < 0) { - netdev_warn(dev->net, "Failed to write COE_CR: %d\n", ret); - return ret; - } - - netif_dbg(dev, hw, dev->net, "COE_CR = 0x%08x\n", read_buf); - return 0; -} - -static int smsc95xx_ethtool_get_eeprom_len(struct net_device *net) -{ - return MAX_EEPROM_SIZE; -} - -static int smsc95xx_ethtool_get_eeprom(struct net_device *netdev, - struct ethtool_eeprom *ee, u8 *data) -{ - struct usbnet *dev = netdev_priv(netdev); - - ee->magic = LAN95XX_EEPROM_MAGIC; - - return smsc95xx_read_eeprom(dev, ee->offset, ee->len, data); -} - -static int smsc95xx_ethtool_set_eeprom(struct net_device *netdev, - struct ethtool_eeprom *ee, u8 *data) -{ - struct usbnet *dev = netdev_priv(netdev); - - if (ee->magic != LAN95XX_EEPROM_MAGIC) { - netdev_warn(dev->net, "EEPROM: magic value mismatch, magic = 0x%x\n", - ee->magic); - return -EINVAL; - } - - return smsc95xx_write_eeprom(dev, ee->offset, ee->len, data); -} - -static const struct ethtool_ops smsc95xx_ethtool_ops = { - .get_link = usbnet_get_link, - .nway_reset = usbnet_nway_reset, - .get_drvinfo = usbnet_get_drvinfo, - .get_msglevel = usbnet_get_msglevel, - .set_msglevel = usbnet_set_msglevel, - .get_settings = usbnet_get_settings, - .set_settings = usbnet_set_settings, - .get_eeprom_len = smsc95xx_ethtool_get_eeprom_len, - .get_eeprom = smsc95xx_ethtool_get_eeprom, - .set_eeprom = smsc95xx_ethtool_set_eeprom, -}; - -static int smsc95xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) -{ - struct usbnet *dev = netdev_priv(netdev); - - if (!netif_running(netdev)) - return -EINVAL; - - return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); -} - -static void smsc95xx_init_mac_address(struct usbnet *dev) -{ - /* try reading mac address from EEPROM */ - if (smsc95xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN, - dev->net->dev_addr) == 0) { - if (is_valid_ether_addr(dev->net->dev_addr)) { - /* eeprom values are valid so use them */ - netif_dbg(dev, ifup, dev->net, "MAC address read from EEPROM\n"); - return; - } - } - - /* no eeprom, or eeprom values are invalid. generate random MAC */ - eth_hw_addr_random(dev->net); - netif_dbg(dev, ifup, dev->net, "MAC address set to random_ether_addr\n"); -} - -static int smsc95xx_set_mac_address(struct usbnet *dev) -{ - u32 addr_lo = dev->net->dev_addr[0] | dev->net->dev_addr[1] << 8 | - dev->net->dev_addr[2] << 16 | dev->net->dev_addr[3] << 24; - u32 addr_hi = dev->net->dev_addr[4] | dev->net->dev_addr[5] << 8; - int ret; - - ret = smsc95xx_write_reg(dev, ADDRL, addr_lo); - if (ret < 0) { - netdev_warn(dev->net, "Failed to write ADDRL: %d\n", ret); - return ret; - } - - ret = smsc95xx_write_reg(dev, ADDRH, addr_hi); - if (ret < 0) { - netdev_warn(dev->net, "Failed to write ADDRH: %d\n", ret); - return ret; - } - - return 0; -} - -/* starts the TX path */ -static void smsc95xx_start_tx_path(struct usbnet *dev) -{ - struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); - unsigned long flags; - u32 reg_val; - - /* Enable Tx at MAC */ - spin_lock_irqsave(&pdata->mac_cr_lock, flags); - pdata->mac_cr |= MAC_CR_TXEN_; - spin_unlock_irqrestore(&pdata->mac_cr_lock, flags); - - smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr); - - /* Enable Tx at SCSRs */ - reg_val = TX_CFG_ON_; - smsc95xx_write_reg(dev, TX_CFG, reg_val); -} - -/* Starts the Receive path */ -static void smsc95xx_start_rx_path(struct usbnet *dev) -{ - struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); - unsigned long flags; - - spin_lock_irqsave(&pdata->mac_cr_lock, flags); - pdata->mac_cr |= MAC_CR_RXEN_; - spin_unlock_irqrestore(&pdata->mac_cr_lock, flags); - - smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr); -} - -static int smsc95xx_phy_initialize(struct usbnet *dev) -{ - int bmcr, timeout = 0; - - /* Initialize MII structure */ - dev->mii.dev = dev->net; - dev->mii.mdio_read = smsc95xx_mdio_read; - dev->mii.mdio_write = smsc95xx_mdio_write; - dev->mii.phy_id_mask = 0x1f; - dev->mii.reg_num_mask = 0x1f; - dev->mii.phy_id = SMSC95XX_INTERNAL_PHY_ID; - - /* reset phy and wait for reset to complete */ - smsc95xx_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); - - do { - msleep(10); - bmcr = smsc95xx_mdio_read(dev->net, dev->mii.phy_id, MII_BMCR); - timeout++; - } while ((bmcr & BMCR_RESET) && (timeout < 100)); - - if (timeout >= 100) { - netdev_warn(dev->net, "timeout on PHY Reset"); - return -EIO; - } - - smsc95xx_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, - ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP | - ADVERTISE_PAUSE_ASYM); - - /* read to clear */ - smsc95xx_mdio_read(dev->net, dev->mii.phy_id, PHY_INT_SRC); - - smsc95xx_mdio_write(dev->net, dev->mii.phy_id, PHY_INT_MASK, - PHY_INT_MASK_DEFAULT_); - mii_nway_restart(&dev->mii); - - netif_dbg(dev, ifup, dev->net, "phy initialised successfully\n"); - return 0; -} - -static int smsc95xx_reset(struct usbnet *dev) -{ - struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); - u32 read_buf, write_buf, burst_cap; - int ret = 0, timeout; - - netif_dbg(dev, ifup, dev->net, "entering smsc95xx_reset\n"); - - write_buf = HW_CFG_LRST_; - ret = smsc95xx_write_reg(dev, HW_CFG, write_buf); - if (ret < 0) { - netdev_warn(dev->net, "Failed to write HW_CFG_LRST_ bit in HW_CFG register, ret = %d\n", - ret); - return ret; - } - - timeout = 0; - do { - ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf); - if (ret < 0) { - netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret); - return ret; - } - msleep(10); - timeout++; - } while ((read_buf & HW_CFG_LRST_) && (timeout < 100)); - - if (timeout >= 100) { - netdev_warn(dev->net, "timeout waiting for completion of Lite Reset\n"); - return ret; - } - - write_buf = PM_CTL_PHY_RST_; - ret = smsc95xx_write_reg(dev, PM_CTRL, write_buf); - if (ret < 0) { - netdev_warn(dev->net, "Failed to write PM_CTRL: %d\n", ret); - return ret; - } - - timeout = 0; - do { - ret = smsc95xx_read_reg(dev, PM_CTRL, &read_buf); - if (ret < 0) { - netdev_warn(dev->net, "Failed to read PM_CTRL: %d\n", ret); - return ret; - } - msleep(10); - timeout++; - } while ((read_buf & PM_CTL_PHY_RST_) && (timeout < 100)); - - if (timeout >= 100) { - netdev_warn(dev->net, "timeout waiting for PHY Reset\n"); - return ret; - } - - ret = smsc95xx_set_mac_address(dev); - if (ret < 0) - return ret; - - netif_dbg(dev, ifup, dev->net, - "MAC Address: %pM\n", dev->net->dev_addr); - - ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf); - if (ret < 0) { - netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret); - return ret; - } - - netif_dbg(dev, ifup, dev->net, - "Read Value from HW_CFG : 0x%08x\n", read_buf); - - read_buf |= HW_CFG_BIR_; - - ret = smsc95xx_write_reg(dev, HW_CFG, read_buf); - if (ret < 0) { - netdev_warn(dev->net, "Failed to write HW_CFG_BIR_ bit in HW_CFG register, ret = %d\n", - ret); - return ret; - } - - ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf); - if (ret < 0) { - netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret); - return ret; - } - netif_dbg(dev, ifup, dev->net, - "Read Value from HW_CFG after writing HW_CFG_BIR_: 0x%08x\n", - read_buf); - - if (!turbo_mode) { - burst_cap = 0; - dev->rx_urb_size = MAX_SINGLE_PACKET_SIZE; - } else if (dev->udev->speed == USB_SPEED_HIGH) { - burst_cap = DEFAULT_HS_BURST_CAP_SIZE / HS_USB_PKT_SIZE; - dev->rx_urb_size = DEFAULT_HS_BURST_CAP_SIZE; - } else { - burst_cap = DEFAULT_FS_BURST_CAP_SIZE / FS_USB_PKT_SIZE; - dev->rx_urb_size = DEFAULT_FS_BURST_CAP_SIZE; - } - - netif_dbg(dev, ifup, dev->net, - "rx_urb_size=%ld\n", (ulong)dev->rx_urb_size); - - ret = smsc95xx_write_reg(dev, BURST_CAP, burst_cap); - if (ret < 0) { - netdev_warn(dev->net, "Failed to write BURST_CAP: %d\n", ret); - return ret; - } - - ret = smsc95xx_read_reg(dev, BURST_CAP, &read_buf); - if (ret < 0) { - netdev_warn(dev->net, "Failed to read BURST_CAP: %d\n", ret); - return ret; - } - netif_dbg(dev, ifup, dev->net, - "Read Value from BURST_CAP after writing: 0x%08x\n", - read_buf); - - read_buf = DEFAULT_BULK_IN_DELAY; - ret = smsc95xx_write_reg(dev, BULK_IN_DLY, read_buf); - if (ret < 0) { - netdev_warn(dev->net, "ret = %d\n", ret); - return ret; - } - - ret = smsc95xx_read_reg(dev, BULK_IN_DLY, &read_buf); - if (ret < 0) { - netdev_warn(dev->net, "Failed to read BULK_IN_DLY: %d\n", ret); - return ret; - } - netif_dbg(dev, ifup, dev->net, - "Read Value from BULK_IN_DLY after writing: 0x%08x\n", - read_buf); - - ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf); - if (ret < 0) { - netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret); - return ret; - } - netif_dbg(dev, ifup, dev->net, - "Read Value from HW_CFG: 0x%08x\n", read_buf); - - if (turbo_mode) - read_buf |= (HW_CFG_MEF_ | HW_CFG_BCE_); - - read_buf &= ~HW_CFG_RXDOFF_; - - /* set Rx data offset=2, Make IP header aligns on word boundary. */ - read_buf |= NET_IP_ALIGN << 9; - - ret = smsc95xx_write_reg(dev, HW_CFG, read_buf); - if (ret < 0) { - netdev_warn(dev->net, "Failed to write HW_CFG register, ret=%d\n", - ret); - return ret; - } - - ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf); - if (ret < 0) { - netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret); - return ret; - } - netif_dbg(dev, ifup, dev->net, - "Read Value from HW_CFG after writing: 0x%08x\n", read_buf); - - write_buf = 0xFFFFFFFF; - ret = smsc95xx_write_reg(dev, INT_STS, write_buf); - if (ret < 0) { - netdev_warn(dev->net, "Failed to write INT_STS register, ret=%d\n", - ret); - return ret; - } - - ret = smsc95xx_read_reg(dev, ID_REV, &read_buf); - if (ret < 0) { - netdev_warn(dev->net, "Failed to read ID_REV: %d\n", ret); - return ret; - } - netif_dbg(dev, ifup, dev->net, "ID_REV = 0x%08x\n", read_buf); - - /* Configure GPIO pins as LED outputs */ - write_buf = LED_GPIO_CFG_SPD_LED | LED_GPIO_CFG_LNK_LED | - LED_GPIO_CFG_FDX_LED; - ret = smsc95xx_write_reg(dev, LED_GPIO_CFG, write_buf); - if (ret < 0) { - netdev_warn(dev->net, "Failed to write LED_GPIO_CFG register, ret=%d\n", - ret); - return ret; - } - - /* Init Tx */ - write_buf = 0; - ret = smsc95xx_write_reg(dev, FLOW, write_buf); - if (ret < 0) { - netdev_warn(dev->net, "Failed to write FLOW: %d\n", ret); - return ret; - } - - read_buf = AFC_CFG_DEFAULT; - ret = smsc95xx_write_reg(dev, AFC_CFG, read_buf); - if (ret < 0) { - netdev_warn(dev->net, "Failed to write AFC_CFG: %d\n", ret); - return ret; - } - - /* Don't need mac_cr_lock during initialisation */ - ret = smsc95xx_read_reg(dev, MAC_CR, &pdata->mac_cr); - if (ret < 0) { - netdev_warn(dev->net, "Failed to read MAC_CR: %d\n", ret); - return ret; - } - - /* Init Rx */ - /* Set Vlan */ - write_buf = (u32)ETH_P_8021Q; - ret = smsc95xx_write_reg(dev, VLAN1, write_buf); - if (ret < 0) { - netdev_warn(dev->net, "Failed to write VAN1: %d\n", ret); - return ret; - } - - /* Enable or disable checksum offload engines */ - smsc95xx_set_features(dev->net, dev->net->features); - - smsc95xx_set_multicast(dev->net); - - if (smsc95xx_phy_initialize(dev) < 0) - return -EIO; - - ret = smsc95xx_read_reg(dev, INT_EP_CTL, &read_buf); - if (ret < 0) { - netdev_warn(dev->net, "Failed to read INT_EP_CTL: %d\n", ret); - return ret; - } - - /* enable PHY interrupts */ - read_buf |= INT_EP_CTL_PHY_INT_; - - ret = smsc95xx_write_reg(dev, INT_EP_CTL, read_buf); - if (ret < 0) { - netdev_warn(dev->net, "Failed to write INT_EP_CTL: %d\n", ret); - return ret; - } - - smsc95xx_start_tx_path(dev); - smsc95xx_start_rx_path(dev); - - netif_dbg(dev, ifup, dev->net, "smsc95xx_reset, return 0\n"); - return 0; -} - -static const struct net_device_ops smsc95xx_netdev_ops = { - .ndo_open = usbnet_open, - .ndo_stop = usbnet_stop, - .ndo_start_xmit = usbnet_start_xmit, - .ndo_tx_timeout = usbnet_tx_timeout, - .ndo_change_mtu = usbnet_change_mtu, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, - .ndo_do_ioctl = smsc95xx_ioctl, - .ndo_set_rx_mode = smsc95xx_set_multicast, - .ndo_set_features = smsc95xx_set_features, -}; - -static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf) -{ - struct smsc95xx_priv *pdata = NULL; - int ret; - - printk(KERN_INFO SMSC_CHIPNAME " v" SMSC_DRIVER_VERSION "\n"); - - ret = usbnet_get_endpoints(dev, intf); - if (ret < 0) { - netdev_warn(dev->net, "usbnet_get_endpoints failed: %d\n", ret); - return ret; - } - - dev->data[0] = (unsigned long)kzalloc(sizeof(struct smsc95xx_priv), - GFP_KERNEL); - - pdata = (struct smsc95xx_priv *)(dev->data[0]); - if (!pdata) { - netdev_warn(dev->net, "Unable to allocate struct smsc95xx_priv\n"); - return -ENOMEM; - } - - spin_lock_init(&pdata->mac_cr_lock); - - if (DEFAULT_TX_CSUM_ENABLE) - dev->net->features |= NETIF_F_HW_CSUM; - if (DEFAULT_RX_CSUM_ENABLE) - dev->net->features |= NETIF_F_RXCSUM; - - dev->net->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM; - - smsc95xx_init_mac_address(dev); - - /* Init all registers */ - ret = smsc95xx_reset(dev); - - dev->net->netdev_ops = &smsc95xx_netdev_ops; - dev->net->ethtool_ops = &smsc95xx_ethtool_ops; - dev->net->flags |= IFF_MULTICAST; - dev->net->hard_header_len += SMSC95XX_TX_OVERHEAD_CSUM; - dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len; - return 0; -} - -static void smsc95xx_unbind(struct usbnet *dev, struct usb_interface *intf) -{ - struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); - if (pdata) { - netif_dbg(dev, ifdown, dev->net, "free pdata\n"); - kfree(pdata); - pdata = NULL; - dev->data[0] = 0; - } -} - -static void smsc95xx_rx_csum_offload(struct sk_buff *skb) -{ - skb->csum = *(u16 *)(skb_tail_pointer(skb) - 2); - skb->ip_summed = CHECKSUM_COMPLETE; - skb_trim(skb, skb->len - 2); -} - -static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) -{ - while (skb->len > 0) { - u32 header, align_count; - struct sk_buff *ax_skb; - unsigned char *packet; - u16 size; - - memcpy(&header, skb->data, sizeof(header)); - le32_to_cpus(&header); - skb_pull(skb, 4 + NET_IP_ALIGN); - packet = skb->data; - - /* get the packet length */ - size = (u16)((header & RX_STS_FL_) >> 16); - align_count = (4 - ((size + NET_IP_ALIGN) % 4)) % 4; - - if (unlikely(header & RX_STS_ES_)) { - netif_dbg(dev, rx_err, dev->net, - "Error header=0x%08x\n", header); - dev->net->stats.rx_errors++; - dev->net->stats.rx_dropped++; - - if (header & RX_STS_CRC_) { - dev->net->stats.rx_crc_errors++; - } else { - if (header & (RX_STS_TL_ | RX_STS_RF_)) - dev->net->stats.rx_frame_errors++; - - if ((header & RX_STS_LE_) && - (!(header & RX_STS_FT_))) - dev->net->stats.rx_length_errors++; - } - } else { - /* ETH_FRAME_LEN + 4(CRC) + 2(COE) + 4(Vlan) */ - if (unlikely(size > (ETH_FRAME_LEN + 12))) { - netif_dbg(dev, rx_err, dev->net, - "size err header=0x%08x\n", header); - return 0; - } - - /* last frame in this batch */ - if (skb->len == size) { - if (dev->net->features & NETIF_F_RXCSUM) - smsc95xx_rx_csum_offload(skb); - skb_trim(skb, skb->len - 4); /* remove fcs */ - skb->truesize = size + sizeof(struct sk_buff); - - return 1; - } - - ax_skb = skb_clone(skb, GFP_ATOMIC); - if (unlikely(!ax_skb)) { - netdev_warn(dev->net, "Error allocating skb\n"); - return 0; - } - - ax_skb->len = size; - ax_skb->data = packet; - skb_set_tail_pointer(ax_skb, size); - - if (dev->net->features & NETIF_F_RXCSUM) - smsc95xx_rx_csum_offload(ax_skb); - skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */ - ax_skb->truesize = size + sizeof(struct sk_buff); - - usbnet_skb_return(dev, ax_skb); - } - - skb_pull(skb, size); - - /* padding bytes before the next frame starts */ - if (skb->len) - skb_pull(skb, align_count); - } - - if (unlikely(skb->len < 0)) { - netdev_warn(dev->net, "invalid rx length<0 %d\n", skb->len); - return 0; - } - - return 1; -} - -static u32 smsc95xx_calc_csum_preamble(struct sk_buff *skb) -{ - u16 low_16 = (u16)skb_checksum_start_offset(skb); - u16 high_16 = low_16 + skb->csum_offset; - return (high_16 << 16) | low_16; -} - -static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev, - struct sk_buff *skb, gfp_t flags) -{ - bool csum = skb->ip_summed == CHECKSUM_PARTIAL; - int overhead = csum ? SMSC95XX_TX_OVERHEAD_CSUM : SMSC95XX_TX_OVERHEAD; - u32 tx_cmd_a, tx_cmd_b; - - /* We do not advertise SG, so skbs should be already linearized */ - BUG_ON(skb_shinfo(skb)->nr_frags); - - if (skb_headroom(skb) < overhead) { - struct sk_buff *skb2 = skb_copy_expand(skb, - overhead, 0, flags); - dev_kfree_skb_any(skb); - skb = skb2; - if (!skb) - return NULL; - } - - if (csum) { - if (skb->len <= 45) { - /* workaround - hardware tx checksum does not work - * properly with extremely small packets */ - long csstart = skb_checksum_start_offset(skb); - __wsum calc = csum_partial(skb->data + csstart, - skb->len - csstart, 0); - *((__sum16 *)(skb->data + csstart - + skb->csum_offset)) = csum_fold(calc); - - csum = false; - } else { - u32 csum_preamble = smsc95xx_calc_csum_preamble(skb); - skb_push(skb, 4); - memcpy(skb->data, &csum_preamble, 4); - } - } - - skb_push(skb, 4); - tx_cmd_b = (u32)(skb->len - 4); - if (csum) - tx_cmd_b |= TX_CMD_B_CSUM_ENABLE; - cpu_to_le32s(&tx_cmd_b); - memcpy(skb->data, &tx_cmd_b, 4); - - skb_push(skb, 4); - tx_cmd_a = (u32)(skb->len - 8) | TX_CMD_A_FIRST_SEG_ | - TX_CMD_A_LAST_SEG_; - cpu_to_le32s(&tx_cmd_a); - memcpy(skb->data, &tx_cmd_a, 4); - - return skb; -} - -static const struct driver_info smsc95xx_info = { - .description = "smsc95xx USB 2.0 Ethernet", - .bind = smsc95xx_bind, - .unbind = smsc95xx_unbind, - .link_reset = smsc95xx_link_reset, - .reset = smsc95xx_reset, - .rx_fixup = smsc95xx_rx_fixup, - .tx_fixup = smsc95xx_tx_fixup, - .status = smsc95xx_status, - .flags = FLAG_ETHER | FLAG_SEND_ZLP | FLAG_LINK_INTR, -}; - -static const struct usb_device_id products[] = { - { - /* SMSC9500 USB Ethernet Device */ - USB_DEVICE(0x0424, 0x9500), - .driver_info = (unsigned long) &smsc95xx_info, - }, - { - /* SMSC9505 USB Ethernet Device */ - USB_DEVICE(0x0424, 0x9505), - .driver_info = (unsigned long) &smsc95xx_info, - }, - { - /* SMSC9500A USB Ethernet Device */ - USB_DEVICE(0x0424, 0x9E00), - .driver_info = (unsigned long) &smsc95xx_info, - }, - { - /* SMSC9505A USB Ethernet Device */ - USB_DEVICE(0x0424, 0x9E01), - .driver_info = (unsigned long) &smsc95xx_info, - }, - { - /* SMSC9512/9514 USB Hub & Ethernet Device */ - USB_DEVICE(0x0424, 0xec00), - .driver_info = (unsigned long) &smsc95xx_info, - }, - { - /* SMSC9500 USB Ethernet Device (SAL10) */ - USB_DEVICE(0x0424, 0x9900), - .driver_info = (unsigned long) &smsc95xx_info, - }, - { - /* SMSC9505 USB Ethernet Device (SAL10) */ - USB_DEVICE(0x0424, 0x9901), - .driver_info = (unsigned long) &smsc95xx_info, - }, - { - /* SMSC9500A USB Ethernet Device (SAL10) */ - USB_DEVICE(0x0424, 0x9902), - .driver_info = (unsigned long) &smsc95xx_info, - }, - { - /* SMSC9505A USB Ethernet Device (SAL10) */ - USB_DEVICE(0x0424, 0x9903), - .driver_info = (unsigned long) &smsc95xx_info, - }, - { - /* SMSC9512/9514 USB Hub & Ethernet Device (SAL10) */ - USB_DEVICE(0x0424, 0x9904), - .driver_info = (unsigned long) &smsc95xx_info, - }, - { - /* SMSC9500A USB Ethernet Device (HAL) */ - USB_DEVICE(0x0424, 0x9905), - .driver_info = (unsigned long) &smsc95xx_info, - }, - { - /* SMSC9505A USB Ethernet Device (HAL) */ - USB_DEVICE(0x0424, 0x9906), - .driver_info = (unsigned long) &smsc95xx_info, - }, - { - /* SMSC9500 USB Ethernet Device (Alternate ID) */ - USB_DEVICE(0x0424, 0x9907), - .driver_info = (unsigned long) &smsc95xx_info, - }, - { - /* SMSC9500A USB Ethernet Device (Alternate ID) */ - USB_DEVICE(0x0424, 0x9908), - .driver_info = (unsigned long) &smsc95xx_info, - }, - { - /* SMSC9512/9514 USB Hub & Ethernet Device (Alternate ID) */ - USB_DEVICE(0x0424, 0x9909), - .driver_info = (unsigned long) &smsc95xx_info, - }, - { - /* SMSC LAN9530 USB Ethernet Device */ - USB_DEVICE(0x0424, 0x9530), - .driver_info = (unsigned long) &smsc95xx_info, - }, - { - /* SMSC LAN9730 USB Ethernet Device */ - USB_DEVICE(0x0424, 0x9730), - .driver_info = (unsigned long) &smsc95xx_info, - }, - { - /* SMSC LAN89530 USB Ethernet Device */ - USB_DEVICE(0x0424, 0x9E08), - .driver_info = (unsigned long) &smsc95xx_info, - }, - { }, /* END */ -}; -MODULE_DEVICE_TABLE(usb, products); - -static struct usb_driver smsc95xx_driver = { - .name = "smsc95xx", - .id_table = products, - .probe = usbnet_probe, - .suspend = usbnet_suspend, - .resume = usbnet_resume, - .disconnect = usbnet_disconnect, -}; - -module_usb_driver(smsc95xx_driver); - -MODULE_AUTHOR("Nancy Lin"); -MODULE_AUTHOR("Steve Glendinning <steve.glendinning@smsc.com>"); -MODULE_DESCRIPTION("SMSC95XX USB 2.0 Ethernet Devices"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/net/usb/smsc95xx.h b/ANDROID_3.4.5/drivers/net/usb/smsc95xx.h deleted file mode 100644 index 86bc4497..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/smsc95xx.h +++ /dev/null @@ -1,256 +0,0 @@ - /*************************************************************************** - * - * Copyright (C) 2007-2008 SMSC - * - * 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 _SMSC95XX_H -#define _SMSC95XX_H - -/* Tx command words */ -#define TX_CMD_A_DATA_OFFSET_ (0x001F0000) -#define TX_CMD_A_FIRST_SEG_ (0x00002000) -#define TX_CMD_A_LAST_SEG_ (0x00001000) -#define TX_CMD_A_BUF_SIZE_ (0x000007FF) - -#define TX_CMD_B_CSUM_ENABLE (0x00004000) -#define TX_CMD_B_ADD_CRC_DISABLE_ (0x00002000) -#define TX_CMD_B_DISABLE_PADDING_ (0x00001000) -#define TX_CMD_B_PKT_BYTE_LENGTH_ (0x000007FF) - -/* Rx status word */ -#define RX_STS_FF_ (0x40000000) /* Filter Fail */ -#define RX_STS_FL_ (0x3FFF0000) /* Frame Length */ -#define RX_STS_ES_ (0x00008000) /* Error Summary */ -#define RX_STS_BF_ (0x00002000) /* Broadcast Frame */ -#define RX_STS_LE_ (0x00001000) /* Length Error */ -#define RX_STS_RF_ (0x00000800) /* Runt Frame */ -#define RX_STS_MF_ (0x00000400) /* Multicast Frame */ -#define RX_STS_TL_ (0x00000080) /* Frame too long */ -#define RX_STS_CS_ (0x00000040) /* Collision Seen */ -#define RX_STS_FT_ (0x00000020) /* Frame Type */ -#define RX_STS_RW_ (0x00000010) /* Receive Watchdog */ -#define RX_STS_ME_ (0x00000008) /* Mii Error */ -#define RX_STS_DB_ (0x00000004) /* Dribbling */ -#define RX_STS_CRC_ (0x00000002) /* CRC Error */ - -/* SCSRs */ -#define ID_REV (0x00) -#define ID_REV_CHIP_ID_MASK_ (0xFFFF0000) -#define ID_REV_CHIP_REV_MASK_ (0x0000FFFF) -#define ID_REV_CHIP_ID_9500_ (0x9500) - -#define INT_STS (0x08) -#define INT_STS_TX_STOP_ (0x00020000) -#define INT_STS_RX_STOP_ (0x00010000) -#define INT_STS_PHY_INT_ (0x00008000) -#define INT_STS_TXE_ (0x00004000) -#define INT_STS_TDFU_ (0x00002000) -#define INT_STS_TDFO_ (0x00001000) -#define INT_STS_RXDF_ (0x00000800) -#define INT_STS_GPIOS_ (0x000007FF) - -#define RX_CFG (0x0C) -#define RX_FIFO_FLUSH_ (0x00000001) - -#define TX_CFG (0x10) -#define TX_CFG_ON_ (0x00000004) -#define TX_CFG_STOP_ (0x00000002) -#define TX_CFG_FIFO_FLUSH_ (0x00000001) - -#define HW_CFG (0x14) -#define HW_CFG_BIR_ (0x00001000) -#define HW_CFG_LEDB_ (0x00000800) -#define HW_CFG_RXDOFF_ (0x00000600) -#define HW_CFG_DRP_ (0x00000040) -#define HW_CFG_MEF_ (0x00000020) -#define HW_CFG_LRST_ (0x00000008) -#define HW_CFG_PSEL_ (0x00000004) -#define HW_CFG_BCE_ (0x00000002) -#define HW_CFG_SRST_ (0x00000001) - -#define PM_CTRL (0x20) -#define PM_CTL_DEV_RDY_ (0x00000080) -#define PM_CTL_SUS_MODE_ (0x00000060) -#define PM_CTL_SUS_MODE_0 (0x00000000) -#define PM_CTL_SUS_MODE_1 (0x00000020) -#define PM_CTL_SUS_MODE_2 (0x00000060) -#define PM_CTL_PHY_RST_ (0x00000010) -#define PM_CTL_WOL_EN_ (0x00000008) -#define PM_CTL_ED_EN_ (0x00000004) -#define PM_CTL_WUPS_ (0x00000003) -#define PM_CTL_WUPS_NO_ (0x00000000) -#define PM_CTL_WUPS_ED_ (0x00000001) -#define PM_CTL_WUPS_WOL_ (0x00000002) -#define PM_CTL_WUPS_MULTI_ (0x00000003) - -#define LED_GPIO_CFG (0x24) -#define LED_GPIO_CFG_SPD_LED (0x01000000) -#define LED_GPIO_CFG_LNK_LED (0x00100000) -#define LED_GPIO_CFG_FDX_LED (0x00010000) - -#define GPIO_CFG (0x28) - -#define AFC_CFG (0x2C) - -/* Hi watermark = 15.5Kb (~10 mtu pkts) */ -/* low watermark = 3k (~2 mtu pkts) */ -/* backpressure duration = ~ 350us */ -/* Apply FC on any frame. */ -#define AFC_CFG_DEFAULT (0x00F830A1) - -#define E2P_CMD (0x30) -#define E2P_CMD_BUSY_ (0x80000000) -#define E2P_CMD_MASK_ (0x70000000) -#define E2P_CMD_READ_ (0x00000000) -#define E2P_CMD_EWDS_ (0x10000000) -#define E2P_CMD_EWEN_ (0x20000000) -#define E2P_CMD_WRITE_ (0x30000000) -#define E2P_CMD_WRAL_ (0x40000000) -#define E2P_CMD_ERASE_ (0x50000000) -#define E2P_CMD_ERAL_ (0x60000000) -#define E2P_CMD_RELOAD_ (0x70000000) -#define E2P_CMD_TIMEOUT_ (0x00000400) -#define E2P_CMD_LOADED_ (0x00000200) -#define E2P_CMD_ADDR_ (0x000001FF) - -#define MAX_EEPROM_SIZE (512) - -#define E2P_DATA (0x34) -#define E2P_DATA_MASK_ (0x000000FF) - -#define BURST_CAP (0x38) - -#define GPIO_WAKE (0x64) - -#define INT_EP_CTL (0x68) -#define INT_EP_CTL_INTEP_ (0x80000000) -#define INT_EP_CTL_MACRTO_ (0x00080000) -#define INT_EP_CTL_TX_STOP_ (0x00020000) -#define INT_EP_CTL_RX_STOP_ (0x00010000) -#define INT_EP_CTL_PHY_INT_ (0x00008000) -#define INT_EP_CTL_TXE_ (0x00004000) -#define INT_EP_CTL_TDFU_ (0x00002000) -#define INT_EP_CTL_TDFO_ (0x00001000) -#define INT_EP_CTL_RXDF_ (0x00000800) -#define INT_EP_CTL_GPIOS_ (0x000007FF) - -#define BULK_IN_DLY (0x6C) - -/* MAC CSRs */ -#define MAC_CR (0x100) -#define MAC_CR_RXALL_ (0x80000000) -#define MAC_CR_RCVOWN_ (0x00800000) -#define MAC_CR_LOOPBK_ (0x00200000) -#define MAC_CR_FDPX_ (0x00100000) -#define MAC_CR_MCPAS_ (0x00080000) -#define MAC_CR_PRMS_ (0x00040000) -#define MAC_CR_INVFILT_ (0x00020000) -#define MAC_CR_PASSBAD_ (0x00010000) -#define MAC_CR_HFILT_ (0x00008000) -#define MAC_CR_HPFILT_ (0x00002000) -#define MAC_CR_LCOLL_ (0x00001000) -#define MAC_CR_BCAST_ (0x00000800) -#define MAC_CR_DISRTY_ (0x00000400) -#define MAC_CR_PADSTR_ (0x00000100) -#define MAC_CR_BOLMT_MASK (0x000000C0) -#define MAC_CR_DFCHK_ (0x00000020) -#define MAC_CR_TXEN_ (0x00000008) -#define MAC_CR_RXEN_ (0x00000004) - -#define ADDRH (0x104) - -#define ADDRL (0x108) - -#define HASHH (0x10C) - -#define HASHL (0x110) - -#define MII_ADDR (0x114) -#define MII_WRITE_ (0x02) -#define MII_BUSY_ (0x01) -#define MII_READ_ (0x00) /* ~of MII Write bit */ - -#define MII_DATA (0x118) - -#define FLOW (0x11C) -#define FLOW_FCPT_ (0xFFFF0000) -#define FLOW_FCPASS_ (0x00000004) -#define FLOW_FCEN_ (0x00000002) -#define FLOW_FCBSY_ (0x00000001) - -#define VLAN1 (0x120) - -#define VLAN2 (0x124) - -#define WUFF (0x128) - -#define WUCSR (0x12C) - -#define COE_CR (0x130) -#define Tx_COE_EN_ (0x00010000) -#define Rx_COE_MODE_ (0x00000002) -#define Rx_COE_EN_ (0x00000001) - -/* Vendor-specific PHY Definitions */ - -/* Mode Control/Status Register */ -#define PHY_MODE_CTRL_STS (17) -#define MODE_CTRL_STS_EDPWRDOWN_ ((u16)0x2000) -#define MODE_CTRL_STS_ENERGYON_ ((u16)0x0002) - -#define SPECIAL_CTRL_STS (27) -#define SPECIAL_CTRL_STS_OVRRD_AMDIX_ ((u16)0x8000) -#define SPECIAL_CTRL_STS_AMDIX_ENABLE_ ((u16)0x4000) -#define SPECIAL_CTRL_STS_AMDIX_STATE_ ((u16)0x2000) - -#define PHY_INT_SRC (29) -#define PHY_INT_SRC_ENERGY_ON_ ((u16)0x0080) -#define PHY_INT_SRC_ANEG_COMP_ ((u16)0x0040) -#define PHY_INT_SRC_REMOTE_FAULT_ ((u16)0x0020) -#define PHY_INT_SRC_LINK_DOWN_ ((u16)0x0010) - -#define PHY_INT_MASK (30) -#define PHY_INT_MASK_ENERGY_ON_ ((u16)0x0080) -#define PHY_INT_MASK_ANEG_COMP_ ((u16)0x0040) -#define PHY_INT_MASK_REMOTE_FAULT_ ((u16)0x0020) -#define PHY_INT_MASK_LINK_DOWN_ ((u16)0x0010) -#define PHY_INT_MASK_DEFAULT_ (PHY_INT_MASK_ANEG_COMP_ | \ - PHY_INT_MASK_LINK_DOWN_) - -#define PHY_SPECIAL (31) -#define PHY_SPECIAL_SPD_ ((u16)0x001C) -#define PHY_SPECIAL_SPD_10HALF_ ((u16)0x0004) -#define PHY_SPECIAL_SPD_10FULL_ ((u16)0x0014) -#define PHY_SPECIAL_SPD_100HALF_ ((u16)0x0008) -#define PHY_SPECIAL_SPD_100FULL_ ((u16)0x0018) - -/* USB Vendor Requests */ -#define USB_VENDOR_REQUEST_WRITE_REGISTER 0xA0 -#define USB_VENDOR_REQUEST_READ_REGISTER 0xA1 -#define USB_VENDOR_REQUEST_GET_STATS 0xA2 - -/* Interrupt Endpoint status word bitfields */ -#define INT_ENP_TX_STOP_ ((u32)BIT(17)) -#define INT_ENP_RX_STOP_ ((u32)BIT(16)) -#define INT_ENP_PHY_INT_ ((u32)BIT(15)) -#define INT_ENP_TXE_ ((u32)BIT(14)) -#define INT_ENP_TDFU_ ((u32)BIT(13)) -#define INT_ENP_TDFO_ ((u32)BIT(12)) -#define INT_ENP_RXDF_ ((u32)BIT(11)) - -#endif /* _SMSC95XX_H */ diff --git a/ANDROID_3.4.5/drivers/net/usb/usbnet.c b/ANDROID_3.4.5/drivers/net/usb/usbnet.c deleted file mode 100644 index 20838aba..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/usbnet.c +++ /dev/null @@ -1,1668 +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/ctype.h> -#include <linux/ethtool.h> -#include <linux/workqueue.h> -#include <linux/mii.h> -#include <linux/usb.h> -#include <linux/usb/usbnet.h> -#include <linux/slab.h> -#include <linux/kernel.h> -#include <linux/pm_runtime.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"); - -/*-------------------------------------------------------------------------*/ - - -//add by kevin -extern int wmt_getsyspara(const char *varname, char *varval, int * varlen); -static unsigned char char2hex(char c){ - unsigned char ret=0xff; - if(c>='0'&&c<='9') - ret= c-'0'; - if(c>='a'&&c<='f') - ret= c-'a'+10; - if(c>='A'&&c<='F') - ret= c-'A'+10; - return ret; -} - -void check_set_mac(unsigned char *buf){ - - char ethbuf[50]; - int len = sizeof(ethbuf); - memset((void*)ethbuf, 0, len); - - //wondermedia set bt mac addr - if(!wmt_getsyspara("ethaddr", ethbuf, &len)){ - - printk("wmt eth addr %s %d\n",ethbuf,strlen(ethbuf)); - //ethaddr=00:40:63:70:13:37 - if(strlen(ethbuf)==17){ - buf[0] = (char2hex(ethbuf[0])<<4)|char2hex(ethbuf[1]); - buf[1] = (char2hex(ethbuf[3])<<4)|char2hex(ethbuf[4]); - buf[2] = (char2hex(ethbuf[6])<<4)|char2hex(ethbuf[7]); - buf[3] = (char2hex(ethbuf[9])<<4)|char2hex(ethbuf[10]); - buf[4] = (char2hex(ethbuf[12])<<4)|char2hex(ethbuf[13]); - buf[5] = (char2hex(ethbuf[15])<<4)|char2hex(ethbuf[16]); - - } - //ethaddr=004063701337 - if(strlen(ethbuf)==12){ - buf[0] = (char2hex(ethbuf[0])<<4)|char2hex(ethbuf[1]); - buf[1] = (char2hex(ethbuf[2])<<4)|char2hex(ethbuf[3]); - buf[2] = (char2hex(ethbuf[4])<<4)|char2hex(ethbuf[5]); - buf[3] = (char2hex(ethbuf[6])<<4)|char2hex(ethbuf[7]); - buf[4] = (char2hex(ethbuf[8])<<4)|char2hex(ethbuf[9]); - buf[5] = (char2hex(ethbuf[10])<<4)|char2hex(ethbuf[11]); - } - } -} - - -/* 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 altsettings. - */ - 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); - -int usbnet_get_ethernet_addr(struct usbnet *dev, int iMACAddress) -{ - int tmp, i; - unsigned char buf [13]; - - tmp = usb_string(dev->udev, iMACAddress, buf, sizeof buf); - if (tmp != 12) { - dev_dbg(&dev->udev->dev, - "bad MAC string %d fetch, %d\n", iMACAddress, tmp); - if (tmp >= 0) - tmp = -EINVAL; - return tmp; - } - for (i = tmp = 0; i < 6; i++, tmp += 2) - dev->net->dev_addr [i] = - (hex_to_bin(buf[tmp]) << 4) + hex_to_bin(buf[tmp + 1]); - return 0; -} -EXPORT_SYMBOL_GPL(usbnet_get_ethernet_addr); - -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->interrupt->transfer_flags |= URB_FREE_BUFFER; - 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; - - if (test_bit(EVENT_RX_PAUSED, &dev->flags)) { - skb_queue_tail(&dev->rxq_pause, skb); - return; - } - - skb->protocol = eth_type_trans (skb, dev->net); - dev->net->stats.rx_packets++; - dev->net->stats.rx_bytes += skb->len; - - netif_dbg(dev, rx_status, dev->net, "< rx, len %zu, type 0x%x\n", - skb->len + sizeof (struct ethhdr), skb->protocol); - memset (skb->cb, 0, sizeof (struct skb_data)); - - if (skb_defer_rx_timestamp(skb)) - return; - - status = netif_rx (skb); - if (status != NET_RX_SUCCESS) - netif_dbg(dev, rx_err, dev->net, - "netif_rx status %d\n", status); -} -EXPORT_SYMBOL_GPL(usbnet_skb_return); - - -/*------------------------------------------------------------------------- - * - * Network Device Driver (peer link to "Host Device", from USB host) - * - *-------------------------------------------------------------------------*/ - -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; -} -EXPORT_SYMBOL_GPL(usbnet_change_mtu); - -/* The caller must hold list->lock */ -static void __usbnet_queue_skb(struct sk_buff_head *list, - struct sk_buff *newsk, enum skb_state state) -{ - struct skb_data *entry = (struct skb_data *) newsk->cb; - - __skb_queue_tail(list, newsk); - entry->state = state; -} - -/*-------------------------------------------------------------------------*/ - -/* some LK 2.4 HCDs oopsed if we freed or resubmitted urbs from - * completion callbacks. 2.5 should have fixed those bugs... - */ - -static enum skb_state defer_bh(struct usbnet *dev, struct sk_buff *skb, - struct sk_buff_head *list, enum skb_state state) -{ - unsigned long flags; - enum skb_state old_state; - struct skb_data *entry = (struct skb_data *) skb->cb; - - spin_lock_irqsave(&list->lock, flags); - old_state = entry->state; - entry->state = state; - __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); - return old_state; -} - -/* 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)) - netdev_err(dev->net, "kevent %d may have been dropped\n", work); - else - netdev_dbg(dev->net, "kevent %d scheduled\n", work); -} -EXPORT_SYMBOL_GPL(usbnet_defer_kevent); - -/*-------------------------------------------------------------------------*/ - -static void rx_complete (struct urb *urb); - -static int 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; - - skb = __netdev_alloc_skb_ip_align(dev->net, size, flags); - if (!skb) { - netif_dbg(dev, rx_err, dev->net, "no rx skb\n"); - usbnet_defer_kevent (dev, EVENT_RX_MEMORY); - usb_free_urb (urb); - return -ENOMEM; - } - - entry = (struct skb_data *) skb->cb; - entry->urb = urb; - entry->dev = dev; - 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) && - !test_bit (EVENT_DEV_ASLEEP, &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: - netif_dbg(dev, ifdown, dev->net, "device gone\n"); - netif_device_detach (dev->net); - break; - case -EHOSTUNREACH: - retval = -ENOLINK; - break; - default: - netif_dbg(dev, rx_err, dev->net, - "rx submit, %d\n", retval); - tasklet_schedule (&dev->bh); - break; - case 0: - __usbnet_queue_skb(&dev->rxq, skb, rx_start); - } - } else { - netif_dbg(dev, ifdown, dev->net, "rx: stopped\n"); - retval = -ENOLINK; - } - spin_unlock_irqrestore (&dev->rxq.lock, lockflags); - if (retval) { - dev_kfree_skb_any (skb); - usb_free_urb (urb); - } - return retval; -} - - -/*-------------------------------------------------------------------------*/ - -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)) { - /* With RX_ASSEMBLE, rx_fixup() must update counters */ - if (!(dev->driver_info->flags & FLAG_RX_ASSEMBLE)) - dev->net->stats.rx_errors++; - goto done; - } - // else network stack removes extra byte if we forced a short packet - - if (skb->len) { - /* all data was already cloned from skb inside the driver */ - if (dev->driver_info->flags & FLAG_MULTI_PACKET) - dev_kfree_skb_any(skb); - else - usbnet_skb_return(dev, skb); - return; - } - - netif_dbg(dev, rx_err, dev->net, "drop\n"); - dev->net->stats.rx_errors++; -done: - 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; - enum skb_state state; - - skb_put (skb, urb->actual_length); - state = rx_done; - entry->urb = NULL; - - switch (urb_status) { - /* success */ - case 0: - if (skb->len < dev->net->hard_header_len) { - state = rx_cleanup; - dev->net->stats.rx_errors++; - dev->net->stats.rx_length_errors++; - netif_dbg(dev, rx_err, dev->net, - "rx length %d\n", skb->len); - } - break; - - /* stalls need manual reset. this is rare ... except that - * when going through USB 2.0 TTs, unplug appears this way. - * we avoid the highspeed version of the ETIMEDOUT/EILSEQ - * storm, recovering as needed. - */ - case -EPIPE: - dev->net->stats.rx_errors++; - usbnet_defer_kevent (dev, EVENT_RX_HALT); - // FALLTHROUGH - - /* software-driven interface shutdown */ - case -ECONNRESET: /* async unlink */ - case -ESHUTDOWN: /* hardware gone */ - netif_dbg(dev, ifdown, dev->net, - "rx shutdown, code %d\n", 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->net->stats.rx_errors++; - if (!timer_pending (&dev->delay)) { - mod_timer (&dev->delay, jiffies + THROTTLE_JIFFIES); - netif_dbg(dev, link, dev->net, - "rx throttle %d\n", urb_status); - } -block: - state = rx_cleanup; - entry->urb = urb; - urb = NULL; - break; - - /* data overrun ... flush fifo? */ - case -EOVERFLOW: - dev->net->stats.rx_over_errors++; - // FALLTHROUGH - - default: - state = rx_cleanup; - dev->net->stats.rx_errors++; - netif_dbg(dev, rx_err, dev->net, "rx status %d\n", urb_status); - break; - } - - state = defer_bh(dev, skb, &dev->rxq, state); - - if (urb) { - if (netif_running (dev->net) && - !test_bit (EVENT_RX_HALT, &dev->flags) && - state != unlink_start) { - rx_submit (dev, urb, GFP_ATOMIC); - usb_mark_last_busy(dev->udev); - return; - } - usb_free_urb (urb); - } - netif_dbg(dev, rx_err, dev->net, "no read resubmitted\n"); -} - -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 */ - netif_dbg(dev, ifdown, dev->net, - "intr shutdown, code %d\n", status); - return; - - /* NOTE: not throttling like RX/TX, since this endpoint - * already polls infrequently - */ - default: - netdev_dbg(dev->net, "intr status %d\n", 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_err(dev, timer, dev->net, - "intr resubmit --> %d\n", status); -} - -/*-------------------------------------------------------------------------*/ -void usbnet_pause_rx(struct usbnet *dev) -{ - set_bit(EVENT_RX_PAUSED, &dev->flags); - - netif_dbg(dev, rx_status, dev->net, "paused rx queue enabled\n"); -} -EXPORT_SYMBOL_GPL(usbnet_pause_rx); - -void usbnet_resume_rx(struct usbnet *dev) -{ - struct sk_buff *skb; - int num = 0; - - clear_bit(EVENT_RX_PAUSED, &dev->flags); - - while ((skb = skb_dequeue(&dev->rxq_pause)) != NULL) { - usbnet_skb_return(dev, skb); - num++; - } - - tasklet_schedule(&dev->bh); - - netif_dbg(dev, rx_status, dev->net, - "paused rx queue disabled, %d skbs requeued\n", num); -} -EXPORT_SYMBOL_GPL(usbnet_resume_rx); - -void usbnet_purge_paused_rxq(struct usbnet *dev) -{ - skb_queue_purge(&dev->rxq_pause); -} -EXPORT_SYMBOL_GPL(usbnet_purge_paused_rxq); - -/*-------------------------------------------------------------------------*/ - -// 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; - int count = 0; - - spin_lock_irqsave (&q->lock, flags); - while (!skb_queue_empty(q)) { - struct skb_data *entry; - struct urb *urb; - int retval; - - skb_queue_walk(q, skb) { - entry = (struct skb_data *) skb->cb; - if (entry->state != unlink_start) - goto found; - } - break; -found: - entry->state = unlink_start; - urb = entry->urb; - - /* - * Get reference count of the URB to avoid it to be - * freed during usb_unlink_urb, which may trigger - * use-after-free problem inside usb_unlink_urb since - * usb_unlink_urb is always racing with .complete - * handler(include defer_bh). - */ - usb_get_urb(urb); - spin_unlock_irqrestore(&q->lock, flags); - // during some PM-driven resume scenarios, - // these (async) unlinks complete immediately - retval = usb_unlink_urb (urb); - if (retval != -EINPROGRESS && retval != 0) - netdev_dbg(dev->net, "unlink urb err, %d\n", retval); - else - count++; - usb_put_urb(urb); - spin_lock_irqsave(&q->lock, flags); - } - 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 void usbnet_terminate_urbs(struct usbnet *dev) -{ - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(unlink_wakeup); - DECLARE_WAITQUEUE(wait, current); - int temp; - - /* ensure there are no more active urbs */ - add_wait_queue(&unlink_wakeup, &wait); - set_current_state(TASK_UNINTERRUPTIBLE); - 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)) { - schedule_timeout(msecs_to_jiffies(UNLINK_TIMEOUT_MS)); - set_current_state(TASK_UNINTERRUPTIBLE); - netif_dbg(dev, ifdown, dev->net, - "waited for %d urb completions\n", temp); - } - set_current_state(TASK_RUNNING); - dev->wait = NULL; - remove_wait_queue(&unlink_wakeup, &wait); -} - -int usbnet_stop (struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - struct driver_info *info = dev->driver_info; - int retval; - - clear_bit(EVENT_DEV_OPEN, &dev->flags); - netif_stop_queue (net); - - netif_info(dev, ifdown, dev->net, - "stop stats: rx/tx %lu/%lu, errs %lu/%lu\n", - net->stats.rx_packets, net->stats.tx_packets, - net->stats.rx_errors, net->stats.tx_errors); - - /* allow minidriver to stop correctly (wireless devices to turn off - * radio etc) */ - if (info->stop) { - retval = info->stop(dev); - if (retval < 0) - netif_info(dev, ifdown, dev->net, - "stop fail (%d) usbnet usb-%s-%s, %s\n", - retval, - dev->udev->bus->bus_name, dev->udev->devpath, - info->description); - } - - if (!(info->flags & FLAG_AVOID_UNLINK_URBS)) - usbnet_terminate_urbs(dev); - - usb_kill_urb(dev->interrupt); - - usbnet_purge_paused_rxq(dev); - - /* 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); - if (info->manage_power) - info->manage_power(dev, 0); - else - usb_autopm_put_interface(dev->intf); - - return 0; -} -EXPORT_SYMBOL_GPL(usbnet_stop); - -/*-------------------------------------------------------------------------*/ - -// posts reads, and enables write queuing - -// precondition: never called in_interrupt - -int usbnet_open (struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - int retval; - struct driver_info *info = dev->driver_info; - - if ((retval = usb_autopm_get_interface(dev->intf)) < 0) { - netif_info(dev, ifup, dev->net, - "resumption fail (%d) usbnet usb-%s-%s, %s\n", - retval, - dev->udev->bus->bus_name, - dev->udev->devpath, - info->description); - goto done_nopm; - } - - // put into "known safe" state - if (info->reset && (retval = info->reset (dev)) < 0) { - netif_info(dev, ifup, dev->net, - "open reset fail (%d) usbnet usb-%s-%s, %s\n", - 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) { - netif_dbg(dev, ifup, dev->net, "can't open; %d\n", retval); - goto done; - } - - /* start any status interrupt transfer */ - if (dev->interrupt) { - retval = usb_submit_urb (dev->interrupt, GFP_KERNEL); - if (retval < 0) { - netif_err(dev, ifup, dev->net, - "intr submit %d\n", retval); - goto done; - } - } - - set_bit(EVENT_DEV_OPEN, &dev->flags); - netif_start_queue (net); - netif_info(dev, ifup, dev->net, - "open: enable queueing (rx %d, tx %d) mtu %d %s framing\n", - (int)RX_QLEN(dev), (int)TX_QLEN(dev), - dev->net->mtu, - (dev->driver_info->flags & FLAG_FRAMING_NC) ? "NetChip" : - (dev->driver_info->flags & FLAG_FRAMING_GL) ? "GeneSys" : - (dev->driver_info->flags & FLAG_FRAMING_Z) ? "Zaurus" : - (dev->driver_info->flags & FLAG_FRAMING_RN) ? "RNDIS" : - (dev->driver_info->flags & FLAG_FRAMING_AX) ? "ASIX" : - "simple"); - - // delay posting reads until we're fully open - tasklet_schedule (&dev->bh); - if (info->manage_power) { - retval = info->manage_power(dev, 1); - if (retval < 0) - goto done; - usb_autopm_put_interface(dev->intf); - } - return retval; - -done: - usb_autopm_put_interface(dev->intf); -done_nopm: - return retval; -} -EXPORT_SYMBOL_GPL(usbnet_open); - -/*-------------------------------------------------------------------------*/ - -/* ethtool methods; minidrivers may need to add some more, but - * they'll probably want to use this base set. - */ - -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, dtrt for drivers calling netif_carrier_{on,off} */ - return ethtool_op_get_link(net); -} -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); - -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 const struct ethtool_ops usbnet_ethtool_ops = { - .get_settings = usbnet_get_settings, - .set_settings = usbnet_set_settings, - .get_link = usbnet_get_link, - .nway_reset = usbnet_nway_reset, - .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_autopm_get_interface(dev->intf); - if (status < 0) - goto fail_pipe; - status = usb_clear_halt (dev->udev, dev->out); - usb_autopm_put_interface(dev->intf); - if (status < 0 && - status != -EPIPE && - status != -ESHUTDOWN) { - if (netif_msg_tx_err (dev)) -fail_pipe: - netdev_err(dev->net, "can't clear tx halt, status %d\n", - 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_autopm_get_interface(dev->intf); - if (status < 0) - goto fail_halt; - status = usb_clear_halt (dev->udev, dev->in); - usb_autopm_put_interface(dev->intf); - if (status < 0 && - status != -EPIPE && - status != -ESHUTDOWN) { - if (netif_msg_rx_err (dev)) -fail_halt: - netdev_err(dev->net, "can't clear rx halt, status %d\n", - 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; - int resched = 1; - - 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); - status = usb_autopm_get_interface(dev->intf); - if (status < 0) { - usb_free_urb(urb); - goto fail_lowmem; - } - if (rx_submit (dev, urb, GFP_KERNEL) == -ENOLINK) - resched = 0; - usb_autopm_put_interface(dev->intf); -fail_lowmem: - if (resched) - 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); - status = usb_autopm_get_interface(dev->intf); - if (status < 0) - goto skip_reset; - if(info->link_reset && (retval = info->link_reset(dev)) < 0) { - usb_autopm_put_interface(dev->intf); -skip_reset: - netdev_info(dev->net, "link reset failed (%d) usbnet usb-%s-%s, %s\n", - retval, - dev->udev->bus->bus_name, - dev->udev->devpath, - info->description); - } else { - usb_autopm_put_interface(dev->intf); - } - } - - if (dev->flags) - netdev_dbg(dev->net, "kevent done, flags = 0x%lx\n", 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) { - if (!(dev->driver_info->flags & FLAG_MULTI_PACKET)) - dev->net->stats.tx_packets++; - dev->net->stats.tx_bytes += entry->length; - } else { - dev->net->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: - usb_mark_last_busy(dev->udev); - if (!timer_pending (&dev->delay)) { - mod_timer (&dev->delay, - jiffies + THROTTLE_JIFFIES); - netif_dbg(dev, link, dev->net, - "tx throttle %d\n", urb->status); - } - netif_stop_queue (dev->net); - break; - default: - netif_dbg(dev, tx_err, dev->net, - "tx err %d\n", entry->urb->status); - break; - } - } - - usb_autopm_put_interface_async(dev->intf); - (void) defer_bh(dev, skb, &dev->txq, tx_done); -} - -/*-------------------------------------------------------------------------*/ - -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? -} -EXPORT_SYMBOL_GPL(usbnet_tx_timeout); - -/*-------------------------------------------------------------------------*/ - -netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, - struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - int length; - struct urb *urb = NULL; - struct skb_data *entry; - struct driver_info *info = dev->driver_info; - unsigned long flags; - int retval; - - if (skb) - skb_tx_timestamp(skb); - - // 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)) { - netif_dbg(dev, tx_err, dev->net, "can't tx_fixup skb\n"); - goto drop; - } else { - /* cdc_ncm collected packet; waits for more */ - goto not_drop; - } - } - } - length = skb->len; - - if (!(urb = usb_alloc_urb (0, GFP_ATOMIC))) { - netif_dbg(dev, tx_err, dev->net, "no urb\n"); - goto drop; - } - - entry = (struct skb_data *) skb->cb; - entry->urb = urb; - entry->dev = dev; - 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. - * NOTE2: CDC NCM specification is different from CDC ECM when - * handling ZLP/short packets, so cdc_ncm driver will make short - * packet itself if needed. - */ - if (length % dev->maxpacket == 0) { - if (!(info->flags & FLAG_SEND_ZLP)) { - if (!(info->flags & FLAG_MULTI_PACKET)) { - urb->transfer_buffer_length++; - if (skb_tailroom(skb)) { - skb->data[skb->len] = 0; - __skb_put(skb, 1); - } - } - } else - urb->transfer_flags |= URB_ZERO_PACKET; - } - - spin_lock_irqsave(&dev->txq.lock, flags); - retval = usb_autopm_get_interface_async(dev->intf); - if (retval < 0) { - spin_unlock_irqrestore(&dev->txq.lock, flags); - goto drop; - } - -#ifdef CONFIG_PM - /* if this triggers the device is still a sleep */ - if (test_bit(EVENT_DEV_ASLEEP, &dev->flags)) { - /* transmission will be done in resume */ - usb_anchor_urb(urb, &dev->deferred); - /* no use to process more packets */ - netif_stop_queue(net); - spin_unlock_irqrestore(&dev->txq.lock, flags); - netdev_dbg(dev->net, "Delaying transmission for resumption\n"); - goto deferred; - } -#endif - - switch ((retval = usb_submit_urb (urb, GFP_ATOMIC))) { - case -EPIPE: - netif_stop_queue (net); - usbnet_defer_kevent (dev, EVENT_TX_HALT); - usb_autopm_put_interface_async(dev->intf); - break; - default: - usb_autopm_put_interface_async(dev->intf); - netif_dbg(dev, tx_err, dev->net, - "tx: submit urb err %d\n", retval); - break; - case 0: - net->trans_start = jiffies; - __usbnet_queue_skb(&dev->txq, skb, tx_start); - if (dev->txq.qlen >= TX_QLEN (dev)) - netif_stop_queue (net); - } - spin_unlock_irqrestore (&dev->txq.lock, flags); - - if (retval) { - netif_dbg(dev, tx_err, dev->net, "drop, code %d\n", retval); -drop: - dev->net->stats.tx_dropped++; -not_drop: - if (skb) - dev_kfree_skb_any (skb); - usb_free_urb (urb); - } else - netif_dbg(dev, tx_queued, dev->net, - "> tx, len %d, type 0x%x\n", length, skb->protocol); -#ifdef CONFIG_PM -deferred: -#endif - return NETDEV_TX_OK; -} -EXPORT_SYMBOL_GPL(usbnet_start_xmit); - -/*-------------------------------------------------------------------------*/ - -// 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: - netdev_dbg(dev->net, "bogus skb state %d\n", entry->state); - } - } - - // waiting for all pending urbs to complete? - if (dev->wait) { - if ((dev->txq.qlen + dev->rxq.qlen + dev->done.qlen) == 0) { - wake_up (dev->wait); - } - - // or are we maybe short a few urbs? - } else if (netif_running (dev->net) && - netif_device_present (dev->net) && - !timer_pending (&dev->delay) && - !test_bit (EVENT_RX_HALT, &dev->flags)) { - int temp = dev->rxq.qlen; - int qlen = RX_QLEN (dev); - - if (temp < qlen) { - struct urb *urb; - int i; - - // don't refill the queue all at once - for (i = 0; i < 10 && dev->rxq.qlen < qlen; i++) { - urb = usb_alloc_urb (0, GFP_ATOMIC); - if (urb != NULL) { - if (rx_submit (dev, urb, GFP_ATOMIC) == - -ENOLINK) - return; - } - } - if (temp != dev->rxq.qlen) - netif_dbg(dev, link, dev->net, - "rxqlen %d --> %d\n", - 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); - - netif_info(dev, probe, dev->net, "unregister '%s' usb-%s-%s, %s\n", - intf->dev.driver->name, - xdev->bus->bus_name, xdev->devpath, - dev->driver_info->description); - - net = dev->net; - unregister_netdev (net); - - cancel_work_sync(&dev->kevent); - - if (dev->driver_info->unbind) - dev->driver_info->unbind (dev, intf); - - usb_kill_urb(dev->interrupt); - usb_free_urb(dev->interrupt); - - free_netdev(net); - usb_put_dev (xdev); -} -EXPORT_SYMBOL_GPL(usbnet_disconnect); - -static const struct net_device_ops usbnet_netdev_ops = { - .ndo_open = usbnet_open, - .ndo_stop = usbnet_stop, - .ndo_start_xmit = usbnet_start_xmit, - .ndo_tx_timeout = usbnet_tx_timeout, - .ndo_change_mtu = usbnet_change_mtu, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -/*-------------------------------------------------------------------------*/ - -// precondition: never called in_interrupt - -static struct device_type wlan_type = { - .name = "wlan", -}; - -static struct device_type wwan_type = { - .name = "wwan", -}; - -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; - struct usb_driver *driver = to_usb_driver(udev->dev.driver); - - /* usbnet already took usb runtime pm, so have to enable the feature - * for usb interface, otherwise usb_autopm_get_interface may return - * failure if USB_SUSPEND(RUNTIME_PM) is enabled. - */ - if (!driver->supports_autosuspend) { - driver->supports_autosuspend = 1; - pm_runtime_enable(&udev->dev); - } - - 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; - -#if 1 - //huawei mu609,skip it's cdc ether device - if(xdev->descriptor.idVendor==0x12d1&&xdev->descriptor.idProduct==0x1573){ - printk("skip %x:%x cdc ether\n",xdev->descriptor.idVendor,xdev->descriptor.idProduct); - goto out; - } -#else -{ - char buf[256]; - int varlen = 256; - int disable = 0; - if( wmt_getsyspara("wmt.cdc.disable",buf,&varlen) == 0) - { - sscanf(buf,"%d",&disable); - if(disable>0) - goto out; - - } -} -#endif - // set up our own records - net = alloc_etherdev(sizeof(*dev)); - if (!net) - goto out; - - /* netdev_printk() needs this so do it as early as possible */ - SET_NETDEV_DEV(net, &udev->dev); - - dev = netdev_priv(net); - dev->udev = xdev; - dev->intf = udev; - dev->driver_info = info; - dev->driver_name = name; - dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV - | NETIF_MSG_PROBE | NETIF_MSG_LINK); - skb_queue_head_init (&dev->rxq); - skb_queue_head_init (&dev->txq); - skb_queue_head_init (&dev->done); - skb_queue_head_init(&dev->rxq_pause); - dev->bh.func = usbnet_bh; - dev->bh.data = (unsigned long) dev; - INIT_WORK (&dev->kevent, kevent); - init_usb_anchor(&dev->deferred); - dev->delay.function = usbnet_bh; - dev->delay.data = (unsigned long) dev; - init_timer (&dev->delay); - mutex_init (&dev->phy_mutex); - - 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_BIT_MASK(64))) - net->features |= NETIF_F_HIGHDMA; -#endif - - net->netdev_ops = &usbnet_netdev_ops; - net->watchdog_timeo = TX_TIMEOUT_JIFFIES; - 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 && - ((dev->driver_info->flags & FLAG_POINTTOPOINT) == 0 || - (net->dev_addr [0] & 0x02) == 0)) - strcpy (net->name, "eth%d"); - /* WLAN devices should always be named "wlan%d" */ - if ((dev->driver_info->flags & FLAG_WLAN) != 0) - strcpy(net->name, "wlan%d"); - /* WWAN devices should always be named "wwan%d" */ - if ((dev->driver_info->flags & FLAG_WWAN) != 0) - strcpy(net->name, "wwan%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); - - if ((dev->driver_info->flags & FLAG_WLAN) != 0) - SET_NETDEV_DEVTYPE(net, &wlan_type); - if ((dev->driver_info->flags & FLAG_WWAN) != 0) - SET_NETDEV_DEVTYPE(net, &wwan_type); - - status = register_netdev (net); - if (status) - goto out4; - netif_info(dev, probe, dev->net, - "register '%s' at usb-%s-%s, %s, %pM\n", - udev->dev.driver->name, - xdev->bus->bus_name, xdev->devpath, - dev->driver_info->description, - net->dev_addr); - - // ok, it's ready to go. - usb_set_intfdata (udev, dev); - - netif_device_attach (net); - - if (dev->driver_info->flags & FLAG_LINK_INTR) - netif_carrier_off(net); - - return 0; - -out4: - usb_free_urb(dev->interrupt); -out3: - if (info->unbind) - info->unbind (dev, udev); -out1: - free_netdev(net); -out: - usb_put_dev(xdev); - return status; -} -EXPORT_SYMBOL_GPL(usbnet_probe); - -/*-------------------------------------------------------------------------*/ - -/* - * suspend the whole driver as soon as the first interface is suspended - * resume only when the last interface is resumed - */ - -int usbnet_suspend (struct usb_interface *intf, pm_message_t message) -{ - struct usbnet *dev = usb_get_intfdata(intf); - - if (!dev->suspend_count++) { - spin_lock_irq(&dev->txq.lock); - /* don't autosuspend while transmitting */ - if (dev->txq.qlen && PMSG_IS_AUTO(message)) { - spin_unlock_irq(&dev->txq.lock); - return -EBUSY; - } else { - set_bit(EVENT_DEV_ASLEEP, &dev->flags); - spin_unlock_irq(&dev->txq.lock); - } - /* - * accelerate emptying of the rx and queues, to avoid - * having everything error out. - */ - netif_device_detach (dev->net); - usbnet_terminate_urbs(dev); - usb_kill_urb(dev->interrupt); - - /* - * reattach so runtime management can use and - * wake the device - */ - netif_device_attach (dev->net); - } - return 0; -} -EXPORT_SYMBOL_GPL(usbnet_suspend); - -int usbnet_resume (struct usb_interface *intf) -{ - struct usbnet *dev = usb_get_intfdata(intf); - struct sk_buff *skb; - struct urb *res; - int retval; - - if (!--dev->suspend_count) { - /* resume interrupt URBs */ - if (dev->interrupt && test_bit(EVENT_DEV_OPEN, &dev->flags)) - usb_submit_urb(dev->interrupt, GFP_NOIO); - - spin_lock_irq(&dev->txq.lock); - while ((res = usb_get_from_anchor(&dev->deferred))) { - - skb = (struct sk_buff *)res->context; - retval = usb_submit_urb(res, GFP_ATOMIC); - if (retval < 0) { - dev_kfree_skb_any(skb); - usb_free_urb(res); - usb_autopm_put_interface_async(dev->intf); - } else { - dev->net->trans_start = jiffies; - __skb_queue_tail(&dev->txq, skb); - } - } - - smp_mb(); - clear_bit(EVENT_DEV_ASLEEP, &dev->flags); - spin_unlock_irq(&dev->txq.lock); - - if (test_bit(EVENT_DEV_OPEN, &dev->flags)) { - if (!(dev->txq.qlen >= TX_QLEN(dev))) - netif_tx_wake_all_queues(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( - FIELD_SIZEOF(struct sk_buff, 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/ANDROID_3.4.5/drivers/net/usb/zaurus.c b/ANDROID_3.4.5/drivers/net/usb/zaurus.c deleted file mode 100644 index 34db195f..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/zaurus.c +++ /dev/null @@ -1,386 +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 <linux/usb/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_POINTTOPOINT | 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_POINTTOPOINT | 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_POINTTOPOINT | 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_POINTTOPOINT | 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, -}, { - /* C-750/C-760/C-860/SL-C3000 PDA in MDLM mode */ - USB_DEVICE_AND_INTERFACE_INFO(0x04DD, 0x9031, USB_CLASS_COMM, - USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), - .driver_info = (unsigned long) &bogus_mdlm_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, -}, -{ - /* Motorola Rokr E6 */ - USB_DEVICE_AND_INTERFACE_INFO(0x22b8, 0x6027, USB_CLASS_COMM, - USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), - .driver_info = (unsigned long) &bogus_mdlm_info, -}, { - /* Motorola MOTOMAGX phones */ - USB_DEVICE_AND_INTERFACE_INFO(0x22b8, 0x6425, 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, -}, - -/* Logitech Harmony 900 - uses the pseudo-MDLM (BLAN) driver */ -{ - USB_DEVICE_AND_INTERFACE_INFO(0x046d, 0xc11f, USB_CLASS_COMM, - USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), - .driver_info = (unsigned long) &bogus_mdlm_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, -}; - -module_usb_driver(zaurus_driver); - -MODULE_AUTHOR("Pavel Machek, David Brownell"); -MODULE_DESCRIPTION("Sharp Zaurus PDA, and compatible products"); -MODULE_LICENSE("GPL"); |