diff --git a/Documentation/networking/device_drivers/wifi/index.rst b/Documentation/networking/device_drivers/wifi/index.rst index bf91a87c7acff..fb394f5de4a94 100644 --- a/Documentation/networking/device_drivers/wifi/index.rst +++ b/Documentation/networking/device_drivers/wifi/index.rst @@ -10,7 +10,6 @@ Contents: intel/ipw2100 intel/ipw2200 - ray_cs .. only:: subproject and html diff --git a/Documentation/networking/device_drivers/wifi/ray_cs.rst b/Documentation/networking/device_drivers/wifi/ray_cs.rst deleted file mode 100644 index 9a46d1ae8f209..0000000000000 --- a/Documentation/networking/device_drivers/wifi/ray_cs.rst +++ /dev/null @@ -1,165 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -.. include:: - -========================= -Raylink wireless LAN card -========================= - -September 21, 1999 - -Copyright |copy| 1998 Corey Thomas (corey@world.std.com) - -This file is the documentation for the Raylink Wireless LAN card driver for -Linux. The Raylink wireless LAN card is a PCMCIA card which provides IEEE -802.11 compatible wireless network connectivity at 1 and 2 megabits/second. -See http://www.raytheon.com/micro/raylink/ for more information on the Raylink -card. This driver is in early development and does have bugs. See the known -bugs and limitations at the end of this document for more information. -This driver also works with WebGear's Aviator 2.4 and Aviator Pro -wireless LAN cards. - -As of kernel 2.3.18, the ray_cs driver is part of the Linux kernel -source. My web page for the development of ray_cs is at -http://web.ralinktech.com/ralink/Home/Support/Linux.html -and I can be emailed at corey@world.std.com - -The kernel driver is based on ray_cs-1.62.tgz - -The driver at my web page is intended to be used as an add on to -David Hinds pcmcia package. All the command line parameters are -available when compiled as a module. When built into the kernel, only -the essid= string parameter is available via the kernel command line. -This will change after the method of sorting out parameters for all -the PCMCIA drivers is agreed upon. If you must have a built in driver -with nondefault parameters, they can be edited in -/usr/src/linux/drivers/net/pcmcia/ray_cs.c. Searching for module_param -will find them all. - -Information on card services is available at: - - http://pcmcia-cs.sourceforge.net/ - - -Card services user programs are still required for PCMCIA devices. -pcmcia-cs-3.1.1 or greater is required for the kernel version of -the driver. - -Currently, ray_cs is not part of David Hinds card services package, -so the following magic is required. - -At the end of the /etc/pcmcia/config.opts file, add the line: -source ./ray_cs.opts -This will make card services read the ray_cs.opts file -when starting. Create the file /etc/pcmcia/ray_cs.opts containing the -following:: - - #### start of /etc/pcmcia/ray_cs.opts ################### - # Configuration options for Raylink Wireless LAN PCMCIA card - device "ray_cs" - class "network" module "misc/ray_cs" - - card "RayLink PC Card WLAN Adapter" - manfid 0x01a6, 0x0000 - bind "ray_cs" - - module "misc/ray_cs" opts "" - #### end of /etc/pcmcia/ray_cs.opts ##################### - - -To join an existing network with -different parameters, contact the network administrator for the -configuration information, and edit /etc/pcmcia/ray_cs.opts. -Add the parameters below between the empty quotes. - -Parameters for ray_cs driver which may be specified in ray_cs.opts: - -=============== =============== ============================================= -bc integer 0 = normal mode (802.11 timing), - 1 = slow down inter frame timing to allow - operation with older breezecom access - points. - -beacon_period integer beacon period in Kilo-microseconds, - - legal values = must be integer multiple - of hop dwell - - default = 256 - -country integer 1 = USA (default), - 2 = Europe, - 3 = Japan, - 4 = Korea, - 5 = Spain, - 6 = France, - 7 = Israel, - 8 = Australia - -essid string ESS ID - network name to join - - string with maximum length of 32 chars - default value = "ADHOC_ESSID" - -hop_dwell integer hop dwell time in Kilo-microseconds - - legal values = 16,32,64,128(default),256 - -irq_mask integer linux standard 16 bit value 1bit/IRQ - - lsb is IRQ 0, bit 1 is IRQ 1 etc. - Used to restrict choice of IRQ's to use. - Recommended method for controlling - interrupts is in /etc/pcmcia/config.opts - -net_type integer 0 (default) = adhoc network, - 1 = infrastructure - -phy_addr string string containing new MAC address in - hex, must start with x eg - x00008f123456 - -psm integer 0 = continuously active, - 1 = power save mode (not useful yet) - -pc_debug integer (0-5) larger values for more verbose - logging. Replaces ray_debug. - -ray_debug integer Replaced with pc_debug - -ray_mem_speed integer defaults to 500 - -sniffer integer 0 = not sniffer (default), - 1 = sniffer which can be used to record all - network traffic using tcpdump or similar, - but no normal network use is allowed. - -translate integer 0 = no translation (encapsulate frames), - 1 = translation (RFC1042/802.1) -=============== =============== ============================================= - -More on sniffer mode: - -tcpdump does not understand 802.11 headers, so it can't -interpret the contents, but it can record to a file. This is only -useful for debugging 802.11 lowlevel protocols that are not visible to -linux. If you want to watch ftp xfers, or do similar things, you -don't need to use sniffer mode. Also, some packet types are never -sent up by the card, so you will never see them (ack, rts, cts, probe -etc.) There is a simple program (showcap) included in the ray_cs -package which parses the 802.11 headers. - -Known Problems and missing features - - Does not work with non x86 - - Does not work with SMP - - Support for defragmenting frames is not yet debugged, and in - fact is known to not work. I have never encountered a net set - up to fragment, but still, it should be fixed. - - The ioctl support is incomplete. The hardware address cannot be set - using ifconfig yet. If a different hardware address is needed, it may - be set using the phy_addr parameter in ray_cs.opts. This requires - a card insertion to take effect. diff --git a/MAINTAINERS b/MAINTAINERS index 509281e9e1695..4b1c2077e9594 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2405,7 +2405,6 @@ F: drivers/memory/atmel* F: drivers/watchdog/sama5d4_wdt.c F: include/soc/at91/ X: drivers/input/touchscreen/atmel_mxt_ts.c -X: drivers/net/wireless/atmel/ N: at91 N: atmel @@ -3309,13 +3308,6 @@ T: git git://github.com/ndyer/linux.git F: Documentation/devicetree/bindings/input/atmel,maxtouch.yaml F: drivers/input/touchscreen/atmel_mxt_ts.c -ATMEL WIRELESS DRIVER -L: linux-wireless@vger.kernel.org -S: Orphan -W: http://www.thekelleys.org.uk/atmel -W: http://atmelwlandriver.sourceforge.net/ -F: drivers/net/wireless/atmel/atmel* - ATOMIC INFRASTRUCTURE M: Will Deacon M: Peter Zijlstra @@ -9709,11 +9701,6 @@ S: Maintained F: Documentation/devicetree/bindings/iio/pressure/honeywell,mprls0025pa.yaml F: drivers/iio/pressure/mprls0025pa.c -HOST AP DRIVER -L: linux-wireless@vger.kernel.org -S: Obsolete -F: drivers/net/wireless/intersil/hostap/ - HP BIOSCFG DRIVER M: Jorge Lopez L: platform-driver-x86@vger.kernel.org @@ -11017,6 +11004,7 @@ F: drivers/net/wireless/intel/iwlegacy/ INTEL WIRELESS WIFI LINK (iwlwifi) M: Gregory Greenman +M: Miri Korenblit L: linux-wireless@vger.kernel.org S: Supported W: https://wireless.wiki.kernel.org/en/users/drivers/iwlwifi @@ -16269,13 +16257,6 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/hubcap/linux.git F: Documentation/filesystems/orangefs.rst F: fs/orangefs/ -ORINOCO DRIVER -L: linux-wireless@vger.kernel.org -S: Orphan -W: https://wireless.wiki.kernel.org/en/users/Drivers/orinoco -W: http://www.nongnu.org/orinoco/ -F: drivers/net/wireless/intersil/orinoco/ - OV2659 OMNIVISION SENSOR DRIVER M: "Lad, Prabhakar" L: linux-media@vger.kernel.org @@ -18169,11 +18150,6 @@ F: drivers/ras/ F: include/linux/ras.h F: include/ras/ras_event.h -RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER -L: linux-wireless@vger.kernel.org -S: Orphan -F: drivers/net/wireless/legacy/ray* - RC-CORE / LIRC FRAMEWORK M: Sean Young L: linux-media@vger.kernel.org @@ -22680,11 +22656,6 @@ F: drivers/usb/gadget/function/*uvc* F: drivers/usb/gadget/legacy/webcam.c F: include/uapi/linux/usb/g_uvc.h -USB WIRELESS RNDIS DRIVER (rndis_wlan) -L: linux-wireless@vger.kernel.org -S: Orphan -F: drivers/net/wireless/legacy/rndis_wlan.c - USB XHCI DRIVER M: Mathias Nyman L: linux-usb@vger.kernel.org @@ -22692,12 +22663,6 @@ S: Supported F: drivers/usb/host/pci-quirks* F: drivers/usb/host/xhci* -USB ZD1201 DRIVER -L: linux-wireless@vger.kernel.org -S: Orphan -W: http://linux-lc100020.sourceforge.net -F: drivers/net/wireless/zydas/zd1201.* - USER DATAGRAM PROTOCOL (UDP) M: Willem de Bruijn S: Maintained @@ -23499,11 +23464,6 @@ M: Miloslav Trmac S: Maintained F: drivers/input/misc/wistron_btns.c -WL3501 WIRELESS PCMCIA CARD DRIVER -L: linux-wireless@vger.kernel.org -S: Orphan -F: drivers/net/wireless/legacy/wl3501* - WMI BINARY MOF DRIVER M: Armin Wolf R: Thomas Weißschuh diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 7555af5195ec3..c6599594dc995 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -22,7 +22,6 @@ source "drivers/net/wireless/admtek/Kconfig" source "drivers/net/wireless/ath/Kconfig" source "drivers/net/wireless/atmel/Kconfig" source "drivers/net/wireless/broadcom/Kconfig" -source "drivers/net/wireless/cisco/Kconfig" source "drivers/net/wireless/intel/Kconfig" source "drivers/net/wireless/intersil/Kconfig" source "drivers/net/wireless/marvell/Kconfig" @@ -38,8 +37,6 @@ source "drivers/net/wireless/ti/Kconfig" source "drivers/net/wireless/zydas/Kconfig" source "drivers/net/wireless/quantenna/Kconfig" -source "drivers/net/wireless/legacy/Kconfig" - source "drivers/net/wireless/virtual/Kconfig" endif # WLAN diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 4d7374d567d18..e1c4141c60044 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -7,7 +7,6 @@ obj-$(CONFIG_WLAN_VENDOR_ADMTEK) += admtek/ obj-$(CONFIG_WLAN_VENDOR_ATH) += ath/ obj-$(CONFIG_WLAN_VENDOR_ATMEL) += atmel/ obj-$(CONFIG_WLAN_VENDOR_BROADCOM) += broadcom/ -obj-$(CONFIG_WLAN_VENDOR_CISCO) += cisco/ obj-$(CONFIG_WLAN_VENDOR_INTEL) += intel/ obj-$(CONFIG_WLAN_VENDOR_INTERSIL) += intersil/ obj-$(CONFIG_WLAN_VENDOR_MARVELL) += marvell/ @@ -23,5 +22,4 @@ obj-$(CONFIG_WLAN_VENDOR_ST) += st/ obj-$(CONFIG_WLAN_VENDOR_TI) += ti/ obj-$(CONFIG_WLAN_VENDOR_ZYDAS) += zydas/ -obj-$(CONFIG_WLAN) += legacy/ obj-$(CONFIG_WLAN) += virtual/ diff --git a/drivers/net/wireless/atmel/Kconfig b/drivers/net/wireless/atmel/Kconfig index bafdd57b049a1..7a2bb7a58ab7e 100644 --- a/drivers/net/wireless/atmel/Kconfig +++ b/drivers/net/wireless/atmel/Kconfig @@ -12,41 +12,6 @@ config WLAN_VENDOR_ATMEL if WLAN_VENDOR_ATMEL -config ATMEL - tristate "Atmel at76c50x chipset 802.11b support" - depends on CFG80211 && (PCI || PCMCIA) && HAS_IOPORT - select WIRELESS_EXT - select WEXT_PRIV - select FW_LOADER - select CRC32 - help - A driver 802.11b wireless cards based on the Atmel fast-vnet - chips. This driver supports standard Linux wireless extensions. - - Many cards based on this chipset do not have flash memory - and need their firmware loaded at start-up. If yours is - one of these, you will need to provide a firmware image - to be loaded into the card by the driver. The Atmel - firmware package can be downloaded from - - -config PCI_ATMEL - tristate "Atmel at76c506 PCI cards" - depends on ATMEL && PCI - help - Enable support for PCI and mini-PCI cards containing the - Atmel at76c506 chip. - -config PCMCIA_ATMEL - tristate "Atmel at76c502/at76c504 PCMCIA cards" - depends on ATMEL && PCMCIA - select WIRELESS_EXT - select FW_LOADER - select CRC32 - help - Enable support for PCMCIA cards containing the - Atmel at76c502 and at76c504 chips. - config AT76C50X_USB tristate "Atmel at76c503/at76c505/at76c505a USB cards" depends on MAC80211 && USB diff --git a/drivers/net/wireless/atmel/Makefile b/drivers/net/wireless/atmel/Makefile index 17e62805677d4..8338d7098ba60 100644 --- a/drivers/net/wireless/atmel/Makefile +++ b/drivers/net/wireless/atmel/Makefile @@ -1,6 +1,2 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_ATMEL) += atmel.o -obj-$(CONFIG_PCI_ATMEL) += atmel_pci.o -obj-$(CONFIG_PCMCIA_ATMEL) += atmel_cs.o - obj-$(CONFIG_AT76C50X_USB) += at76c50x-usb.o diff --git a/drivers/net/wireless/atmel/atmel.c b/drivers/net/wireless/atmel/atmel.c deleted file mode 100644 index 461dce21de2b0..0000000000000 --- a/drivers/net/wireless/atmel/atmel.c +++ /dev/null @@ -1,4452 +0,0 @@ -/*** -*- linux-c -*- ********************************************************** - - Driver for Atmel at76c502 at76c504 and at76c506 wireless cards. - - Copyright 2000-2001 ATMEL Corporation. - Copyright 2003-2004 Simon Kelley. - - This code was developed from version 2.1.1 of the Atmel drivers, - released by Atmel corp. under the GPL in December 2002. It also - includes code from the Linux aironet drivers (C) Benjamin Reed, - and the Linux PCMCIA package, (C) David Hinds and the Linux wireless - extensions, (C) Jean Tourrilhes. - - The firmware module for reading the MAC address of the card comes from - net.russotto.AtmelMACFW, written by Matthew T. Russotto and copyright - by him. net.russotto.AtmelMACFW is used under the GPL license version 2. - This file contains the module in binary form and, under the terms - of the GPL, in source form. The source is located at the end of the file. - - 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 software 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 Atmel wireless lan drivers; if not, see - . - - For all queries about this code, please contact the current author, - Simon Kelley and not Atmel Corporation. - - Credit is due to HP UK and Cambridge Online Systems Ltd for supplying - hardware used during development of this driver. - -******************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "atmel.h" - -#define DRIVER_MAJOR 0 -#define DRIVER_MINOR 98 - -MODULE_AUTHOR("Simon Kelley"); -MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards."); -MODULE_LICENSE("GPL"); - -/* The name of the firmware file to be loaded - over-rides any automatic selection */ -static char *firmware = NULL; -module_param(firmware, charp, 0); - -/* table of firmware file names */ -static struct { - AtmelFWType fw_type; - const char *fw_file; - const char *fw_file_ext; -} fw_table[] = { - { ATMEL_FW_TYPE_502, "atmel_at76c502", "bin" }, - { ATMEL_FW_TYPE_502D, "atmel_at76c502d", "bin" }, - { ATMEL_FW_TYPE_502E, "atmel_at76c502e", "bin" }, - { ATMEL_FW_TYPE_502_3COM, "atmel_at76c502_3com", "bin" }, - { ATMEL_FW_TYPE_504, "atmel_at76c504", "bin" }, - { ATMEL_FW_TYPE_504_2958, "atmel_at76c504_2958", "bin" }, - { ATMEL_FW_TYPE_504A_2958, "atmel_at76c504a_2958", "bin" }, - { ATMEL_FW_TYPE_506, "atmel_at76c506", "bin" }, - { ATMEL_FW_TYPE_NONE, NULL, NULL } -}; -MODULE_FIRMWARE("atmel_at76c502-wpa.bin"); -MODULE_FIRMWARE("atmel_at76c502.bin"); -MODULE_FIRMWARE("atmel_at76c502d-wpa.bin"); -MODULE_FIRMWARE("atmel_at76c502d.bin"); -MODULE_FIRMWARE("atmel_at76c502e-wpa.bin"); -MODULE_FIRMWARE("atmel_at76c502e.bin"); -MODULE_FIRMWARE("atmel_at76c502_3com-wpa.bin"); -MODULE_FIRMWARE("atmel_at76c502_3com.bin"); -MODULE_FIRMWARE("atmel_at76c504-wpa.bin"); -MODULE_FIRMWARE("atmel_at76c504.bin"); -MODULE_FIRMWARE("atmel_at76c504_2958-wpa.bin"); -MODULE_FIRMWARE("atmel_at76c504_2958.bin"); -MODULE_FIRMWARE("atmel_at76c504a_2958-wpa.bin"); -MODULE_FIRMWARE("atmel_at76c504a_2958.bin"); -MODULE_FIRMWARE("atmel_at76c506-wpa.bin"); -MODULE_FIRMWARE("atmel_at76c506.bin"); - -#define MAX_SSID_LENGTH 32 -#define MGMT_JIFFIES (256 * HZ / 100) - -#define MAX_BSS_ENTRIES 64 - -/* registers */ -#define GCR 0x00 /* (SIR0) General Configuration Register */ -#define BSR 0x02 /* (SIR1) Bank Switching Select Register */ -#define AR 0x04 -#define DR 0x08 -#define MR1 0x12 /* Mirror Register 1 */ -#define MR2 0x14 /* Mirror Register 2 */ -#define MR3 0x16 /* Mirror Register 3 */ -#define MR4 0x18 /* Mirror Register 4 */ - -#define GPR1 0x0c -#define GPR2 0x0e -#define GPR3 0x10 -/* - * Constants for the GCR register. - */ -#define GCR_REMAP 0x0400 /* Remap internal SRAM to 0 */ -#define GCR_SWRES 0x0080 /* BIU reset (ARM and PAI are NOT reset) */ -#define GCR_CORES 0x0060 /* Core Reset (ARM and PAI are reset) */ -#define GCR_ENINT 0x0002 /* Enable Interrupts */ -#define GCR_ACKINT 0x0008 /* Acknowledge Interrupts */ - -#define BSS_SRAM 0x0200 /* AMBA module selection --> SRAM */ -#define BSS_IRAM 0x0100 /* AMBA module selection --> IRAM */ -/* - *Constants for the MR registers. - */ -#define MAC_INIT_COMPLETE 0x0001 /* MAC init has been completed */ -#define MAC_BOOT_COMPLETE 0x0010 /* MAC boot has been completed */ -#define MAC_INIT_OK 0x0002 /* MAC boot has been completed */ - -#define MIB_MAX_DATA_BYTES 212 -#define MIB_HEADER_SIZE 4 /* first four fields */ - -struct get_set_mib { - u8 type; - u8 size; - u8 index; - u8 reserved; - u8 data[MIB_MAX_DATA_BYTES]; -}; - -struct rx_desc { - u32 Next; - u16 MsduPos; - u16 MsduSize; - - u8 State; - u8 Status; - u8 Rate; - u8 Rssi; - u8 LinkQuality; - u8 PreambleType; - u16 Duration; - u32 RxTime; -}; - -#define RX_DESC_FLAG_VALID 0x80 -#define RX_DESC_FLAG_CONSUMED 0x40 -#define RX_DESC_FLAG_IDLE 0x00 - -#define RX_STATUS_SUCCESS 0x00 - -#define RX_DESC_MSDU_POS_OFFSET 4 -#define RX_DESC_MSDU_SIZE_OFFSET 6 -#define RX_DESC_FLAGS_OFFSET 8 -#define RX_DESC_STATUS_OFFSET 9 -#define RX_DESC_RSSI_OFFSET 11 -#define RX_DESC_LINK_QUALITY_OFFSET 12 -#define RX_DESC_PREAMBLE_TYPE_OFFSET 13 -#define RX_DESC_DURATION_OFFSET 14 -#define RX_DESC_RX_TIME_OFFSET 16 - -struct tx_desc { - u32 NextDescriptor; - u16 TxStartOfFrame; - u16 TxLength; - - u8 TxState; - u8 TxStatus; - u8 RetryCount; - - u8 TxRate; - - u8 KeyIndex; - u8 ChiperType; - u8 ChipreLength; - u8 Reserved1; - - u8 Reserved; - u8 PacketType; - u16 HostTxLength; -}; - -#define TX_DESC_NEXT_OFFSET 0 -#define TX_DESC_POS_OFFSET 4 -#define TX_DESC_SIZE_OFFSET 6 -#define TX_DESC_FLAGS_OFFSET 8 -#define TX_DESC_STATUS_OFFSET 9 -#define TX_DESC_RETRY_OFFSET 10 -#define TX_DESC_RATE_OFFSET 11 -#define TX_DESC_KEY_INDEX_OFFSET 12 -#define TX_DESC_CIPHER_TYPE_OFFSET 13 -#define TX_DESC_CIPHER_LENGTH_OFFSET 14 -#define TX_DESC_PACKET_TYPE_OFFSET 17 -#define TX_DESC_HOST_LENGTH_OFFSET 18 - -/* - * Host-MAC interface - */ - -#define TX_STATUS_SUCCESS 0x00 - -#define TX_FIRM_OWN 0x80 -#define TX_DONE 0x40 - -#define TX_ERROR 0x01 - -#define TX_PACKET_TYPE_DATA 0x01 -#define TX_PACKET_TYPE_MGMT 0x02 - -#define ISR_EMPTY 0x00 /* no bits set in ISR */ -#define ISR_TxCOMPLETE 0x01 /* packet transmitted */ -#define ISR_RxCOMPLETE 0x02 /* packet received */ -#define ISR_RxFRAMELOST 0x04 /* Rx Frame lost */ -#define ISR_FATAL_ERROR 0x08 /* Fatal error */ -#define ISR_COMMAND_COMPLETE 0x10 /* command completed */ -#define ISR_OUT_OF_RANGE 0x20 /* command completed */ -#define ISR_IBSS_MERGE 0x40 /* (4.1.2.30): IBSS merge */ -#define ISR_GENERIC_IRQ 0x80 - -#define Local_Mib_Type 0x01 -#define Mac_Address_Mib_Type 0x02 -#define Mac_Mib_Type 0x03 -#define Statistics_Mib_Type 0x04 -#define Mac_Mgmt_Mib_Type 0x05 -#define Mac_Wep_Mib_Type 0x06 -#define Phy_Mib_Type 0x07 -#define Multi_Domain_MIB 0x08 - -#define MAC_MGMT_MIB_CUR_BSSID_POS 14 -#define MAC_MIB_FRAG_THRESHOLD_POS 8 -#define MAC_MIB_RTS_THRESHOLD_POS 10 -#define MAC_MIB_SHORT_RETRY_POS 16 -#define MAC_MIB_LONG_RETRY_POS 17 -#define MAC_MIB_SHORT_RETRY_LIMIT_POS 16 -#define MAC_MGMT_MIB_BEACON_PER_POS 0 -#define MAC_MGMT_MIB_STATION_ID_POS 6 -#define MAC_MGMT_MIB_CUR_PRIVACY_POS 11 -#define MAC_MGMT_MIB_CUR_BSSID_POS 14 -#define MAC_MGMT_MIB_PS_MODE_POS 53 -#define MAC_MGMT_MIB_LISTEN_INTERVAL_POS 54 -#define MAC_MGMT_MIB_MULTI_DOMAIN_IMPLEMENTED 56 -#define MAC_MGMT_MIB_MULTI_DOMAIN_ENABLED 57 -#define PHY_MIB_CHANNEL_POS 14 -#define PHY_MIB_RATE_SET_POS 20 -#define PHY_MIB_REG_DOMAIN_POS 26 -#define LOCAL_MIB_AUTO_TX_RATE_POS 3 -#define LOCAL_MIB_SSID_SIZE 5 -#define LOCAL_MIB_TX_PROMISCUOUS_POS 6 -#define LOCAL_MIB_TX_MGMT_RATE_POS 7 -#define LOCAL_MIB_TX_CONTROL_RATE_POS 8 -#define LOCAL_MIB_PREAMBLE_TYPE 9 -#define MAC_ADDR_MIB_MAC_ADDR_POS 0 - -#define CMD_Set_MIB_Vars 0x01 -#define CMD_Get_MIB_Vars 0x02 -#define CMD_Scan 0x03 -#define CMD_Join 0x04 -#define CMD_Start 0x05 -#define CMD_EnableRadio 0x06 -#define CMD_DisableRadio 0x07 -#define CMD_SiteSurvey 0x0B - -#define CMD_STATUS_IDLE 0x00 -#define CMD_STATUS_COMPLETE 0x01 -#define CMD_STATUS_UNKNOWN 0x02 -#define CMD_STATUS_INVALID_PARAMETER 0x03 -#define CMD_STATUS_FUNCTION_NOT_SUPPORTED 0x04 -#define CMD_STATUS_TIME_OUT 0x07 -#define CMD_STATUS_IN_PROGRESS 0x08 -#define CMD_STATUS_REJECTED_RADIO_OFF 0x09 -#define CMD_STATUS_HOST_ERROR 0xFF -#define CMD_STATUS_BUSY 0xFE - -#define CMD_BLOCK_COMMAND_OFFSET 0 -#define CMD_BLOCK_STATUS_OFFSET 1 -#define CMD_BLOCK_PARAMETERS_OFFSET 4 - -#define SCAN_OPTIONS_SITE_SURVEY 0x80 - -#define MGMT_FRAME_BODY_OFFSET 24 -#define MAX_AUTHENTICATION_RETRIES 3 -#define MAX_ASSOCIATION_RETRIES 3 - -#define AUTHENTICATION_RESPONSE_TIME_OUT 1000 - -#define MAX_WIRELESS_BODY 2316 /* mtu is 2312, CRC is 4 */ -#define LOOP_RETRY_LIMIT 500000 - -#define ACTIVE_MODE 1 -#define PS_MODE 2 - -#define MAX_ENCRYPTION_KEYS 4 -#define MAX_ENCRYPTION_KEY_SIZE 40 - -/* - * 802.11 related definitions - */ - -/* - * Regulatory Domains - */ - -#define REG_DOMAIN_FCC 0x10 /* Channels 1-11 USA */ -#define REG_DOMAIN_DOC 0x20 /* Channel 1-11 Canada */ -#define REG_DOMAIN_ETSI 0x30 /* Channel 1-13 Europe (ex Spain/France) */ -#define REG_DOMAIN_SPAIN 0x31 /* Channel 10-11 Spain */ -#define REG_DOMAIN_FRANCE 0x32 /* Channel 10-13 France */ -#define REG_DOMAIN_MKK 0x40 /* Channel 14 Japan */ -#define REG_DOMAIN_MKK1 0x41 /* Channel 1-14 Japan(MKK1) */ -#define REG_DOMAIN_ISRAEL 0x50 /* Channel 3-9 ISRAEL */ - -#define BSS_TYPE_AD_HOC 1 -#define BSS_TYPE_INFRASTRUCTURE 2 - -#define SCAN_TYPE_ACTIVE 0 -#define SCAN_TYPE_PASSIVE 1 - -#define LONG_PREAMBLE 0 -#define SHORT_PREAMBLE 1 -#define AUTO_PREAMBLE 2 - -#define DATA_FRAME_WS_HEADER_SIZE 30 - -/* promiscuous mode control */ -#define PROM_MODE_OFF 0x0 -#define PROM_MODE_UNKNOWN 0x1 -#define PROM_MODE_CRC_FAILED 0x2 -#define PROM_MODE_DUPLICATED 0x4 -#define PROM_MODE_MGMT 0x8 -#define PROM_MODE_CTRL 0x10 -#define PROM_MODE_BAD_PROTOCOL 0x20 - -#define IFACE_INT_STATUS_OFFSET 0 -#define IFACE_INT_MASK_OFFSET 1 -#define IFACE_LOCKOUT_HOST_OFFSET 2 -#define IFACE_LOCKOUT_MAC_OFFSET 3 -#define IFACE_FUNC_CTRL_OFFSET 28 -#define IFACE_MAC_STAT_OFFSET 30 -#define IFACE_GENERIC_INT_TYPE_OFFSET 32 - -#define CIPHER_SUITE_NONE 0 -#define CIPHER_SUITE_WEP_64 1 -#define CIPHER_SUITE_TKIP 2 -#define CIPHER_SUITE_AES 3 -#define CIPHER_SUITE_CCX 4 -#define CIPHER_SUITE_WEP_128 5 - -/* - * IFACE MACROS & definitions - */ - -/* - * FuncCtrl field: - */ -#define FUNC_CTRL_TxENABLE 0x10 -#define FUNC_CTRL_RxENABLE 0x20 -#define FUNC_CTRL_INIT_COMPLETE 0x01 - -/* A stub firmware image which reads the MAC address from NVRAM on the card. - For copyright information and source see the end of this file. */ -static u8 mac_reader[] = { - 0x06, 0x00, 0x00, 0xea, 0x04, 0x00, 0x00, 0xea, 0x03, 0x00, 0x00, 0xea, 0x02, 0x00, 0x00, 0xea, - 0x01, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0xea, 0xff, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea, - 0xd3, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1, 0x0e, 0x04, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, - 0x81, 0x11, 0xa0, 0xe1, 0x00, 0x10, 0x81, 0xe3, 0x00, 0x10, 0x80, 0xe5, 0x1c, 0x10, 0x90, 0xe5, - 0x10, 0x10, 0xc1, 0xe3, 0x1c, 0x10, 0x80, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x08, 0x10, 0x80, 0xe5, - 0x02, 0x03, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, 0xb0, 0x10, 0xc0, 0xe1, 0xb4, 0x10, 0xc0, 0xe1, - 0xb8, 0x10, 0xc0, 0xe1, 0xbc, 0x10, 0xc0, 0xe1, 0x56, 0xdc, 0xa0, 0xe3, 0x21, 0x00, 0x00, 0xeb, - 0x0a, 0x00, 0xa0, 0xe3, 0x1a, 0x00, 0x00, 0xeb, 0x10, 0x00, 0x00, 0xeb, 0x07, 0x00, 0x00, 0xeb, - 0x02, 0x03, 0xa0, 0xe3, 0x02, 0x14, 0xa0, 0xe3, 0xb4, 0x10, 0xc0, 0xe1, 0x4c, 0x10, 0x9f, 0xe5, - 0xbc, 0x10, 0xc0, 0xe1, 0x10, 0x10, 0xa0, 0xe3, 0xb8, 0x10, 0xc0, 0xe1, 0xfe, 0xff, 0xff, 0xea, - 0x00, 0x40, 0x2d, 0xe9, 0x00, 0x20, 0xa0, 0xe3, 0x02, 0x3c, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, - 0x28, 0x00, 0x9f, 0xe5, 0x37, 0x00, 0x00, 0xeb, 0x00, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, - 0x00, 0x40, 0x2d, 0xe9, 0x12, 0x2e, 0xa0, 0xe3, 0x06, 0x30, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, - 0x02, 0x04, 0xa0, 0xe3, 0x2f, 0x00, 0x00, 0xeb, 0x00, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, - 0x00, 0x02, 0x00, 0x02, 0x80, 0x01, 0x90, 0xe0, 0x01, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x50, 0xe2, - 0xfc, 0xff, 0xff, 0xea, 0x1e, 0xff, 0x2f, 0xe1, 0x80, 0x10, 0xa0, 0xe3, 0xf3, 0x06, 0xa0, 0xe3, - 0x00, 0x10, 0x80, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x80, 0xe5, 0x01, 0x10, 0xa0, 0xe3, - 0x04, 0x10, 0x80, 0xe5, 0x00, 0x10, 0x80, 0xe5, 0x0e, 0x34, 0xa0, 0xe3, 0x1c, 0x10, 0x93, 0xe5, - 0x02, 0x1a, 0x81, 0xe3, 0x1c, 0x10, 0x83, 0xe5, 0x58, 0x11, 0x9f, 0xe5, 0x30, 0x10, 0x80, 0xe5, - 0x54, 0x11, 0x9f, 0xe5, 0x34, 0x10, 0x80, 0xe5, 0x38, 0x10, 0x80, 0xe5, 0x3c, 0x10, 0x80, 0xe5, - 0x10, 0x10, 0x90, 0xe5, 0x08, 0x00, 0x90, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0xf3, 0x16, 0xa0, 0xe3, - 0x08, 0x00, 0x91, 0xe5, 0x05, 0x00, 0xa0, 0xe3, 0x0c, 0x00, 0x81, 0xe5, 0x10, 0x00, 0x91, 0xe5, - 0x02, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0xff, 0x00, 0xa0, 0xe3, 0x0c, 0x00, 0x81, 0xe5, - 0x10, 0x00, 0x91, 0xe5, 0x02, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0x08, 0x00, 0x91, 0xe5, - 0x10, 0x00, 0x91, 0xe5, 0x01, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0x08, 0x00, 0x91, 0xe5, - 0xff, 0x00, 0x00, 0xe2, 0x1e, 0xff, 0x2f, 0xe1, 0x30, 0x40, 0x2d, 0xe9, 0x00, 0x50, 0xa0, 0xe1, - 0x03, 0x40, 0xa0, 0xe1, 0xa2, 0x02, 0xa0, 0xe1, 0x08, 0x00, 0x00, 0xe2, 0x03, 0x00, 0x80, 0xe2, - 0xd8, 0x10, 0x9f, 0xe5, 0x00, 0x00, 0xc1, 0xe5, 0x01, 0x20, 0xc1, 0xe5, 0xe2, 0xff, 0xff, 0xeb, - 0x01, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x1a, 0x14, 0x00, 0xa0, 0xe3, 0xc4, 0xff, 0xff, 0xeb, - 0x04, 0x20, 0xa0, 0xe1, 0x05, 0x10, 0xa0, 0xe1, 0x02, 0x00, 0xa0, 0xe3, 0x01, 0x00, 0x00, 0xeb, - 0x30, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 0x70, 0x40, 0x2d, 0xe9, 0xf3, 0x46, 0xa0, 0xe3, - 0x00, 0x30, 0xa0, 0xe3, 0x00, 0x00, 0x50, 0xe3, 0x08, 0x00, 0x00, 0x9a, 0x8c, 0x50, 0x9f, 0xe5, - 0x03, 0x60, 0xd5, 0xe7, 0x0c, 0x60, 0x84, 0xe5, 0x10, 0x60, 0x94, 0xe5, 0x02, 0x00, 0x16, 0xe3, - 0xfc, 0xff, 0xff, 0x0a, 0x01, 0x30, 0x83, 0xe2, 0x00, 0x00, 0x53, 0xe1, 0xf7, 0xff, 0xff, 0x3a, - 0xff, 0x30, 0xa0, 0xe3, 0x0c, 0x30, 0x84, 0xe5, 0x08, 0x00, 0x94, 0xe5, 0x10, 0x00, 0x94, 0xe5, - 0x01, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0x08, 0x00, 0x94, 0xe5, 0x00, 0x00, 0xa0, 0xe3, - 0x00, 0x00, 0x52, 0xe3, 0x0b, 0x00, 0x00, 0x9a, 0x10, 0x50, 0x94, 0xe5, 0x02, 0x00, 0x15, 0xe3, - 0xfc, 0xff, 0xff, 0x0a, 0x0c, 0x30, 0x84, 0xe5, 0x10, 0x50, 0x94, 0xe5, 0x01, 0x00, 0x15, 0xe3, - 0xfc, 0xff, 0xff, 0x0a, 0x08, 0x50, 0x94, 0xe5, 0x01, 0x50, 0xc1, 0xe4, 0x01, 0x00, 0x80, 0xe2, - 0x02, 0x00, 0x50, 0xe1, 0xf3, 0xff, 0xff, 0x3a, 0xc8, 0x00, 0xa0, 0xe3, 0x98, 0xff, 0xff, 0xeb, - 0x70, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 0x01, 0x0c, 0x00, 0x02, 0x01, 0x02, 0x00, 0x02, - 0x00, 0x01, 0x00, 0x02 -}; - -struct atmel_private { - void *card; /* Bus dependent structure varies for PCcard */ - int (*present_callback)(void *); /* And callback which uses it */ - char firmware_id[32]; - AtmelFWType firmware_type; - u8 *firmware; - int firmware_length; - struct timer_list management_timer; - struct net_device *dev; - struct device *sys_dev; - struct iw_statistics wstats; - spinlock_t irqlock, timerlock; /* spinlocks */ - enum { BUS_TYPE_PCCARD, BUS_TYPE_PCI } bus_type; - enum { - CARD_TYPE_PARALLEL_FLASH, - CARD_TYPE_SPI_FLASH, - CARD_TYPE_EEPROM - } card_type; - int do_rx_crc; /* If we need to CRC incoming packets */ - int probe_crc; /* set if we don't yet know */ - int crc_ok_cnt, crc_ko_cnt; /* counters for probing */ - u16 rx_desc_head; - u16 tx_desc_free, tx_desc_head, tx_desc_tail, tx_desc_previous; - u16 tx_free_mem, tx_buff_head, tx_buff_tail; - - u16 frag_seq, frag_len, frag_no; - u8 frag_source[6]; - - u8 wep_is_on, default_key, exclude_unencrypted, encryption_level; - u8 group_cipher_suite, pairwise_cipher_suite; - u8 wep_keys[MAX_ENCRYPTION_KEYS][MAX_ENCRYPTION_KEY_SIZE]; - int wep_key_len[MAX_ENCRYPTION_KEYS]; - int use_wpa, radio_on_broken; /* firmware dependent stuff. */ - - u16 host_info_base; - struct host_info_struct { - /* NB this is matched to the hardware, don't change. */ - u8 volatile int_status; - u8 volatile int_mask; - u8 volatile lockout_host; - u8 volatile lockout_mac; - - u16 tx_buff_pos; - u16 tx_buff_size; - u16 tx_desc_pos; - u16 tx_desc_count; - - u16 rx_buff_pos; - u16 rx_buff_size; - u16 rx_desc_pos; - u16 rx_desc_count; - - u16 build_version; - u16 command_pos; - - u16 major_version; - u16 minor_version; - - u16 func_ctrl; - u16 mac_status; - u16 generic_IRQ_type; - u8 reserved[2]; - } host_info; - - enum { - STATION_STATE_SCANNING, - STATION_STATE_JOINNING, - STATION_STATE_AUTHENTICATING, - STATION_STATE_ASSOCIATING, - STATION_STATE_READY, - STATION_STATE_REASSOCIATING, - STATION_STATE_DOWN, - STATION_STATE_MGMT_ERROR - } station_state; - - int operating_mode, power_mode; - unsigned long last_qual; - int beacons_this_sec; - int channel; - int reg_domain, config_reg_domain; - int tx_rate; - int auto_tx_rate; - int rts_threshold; - int frag_threshold; - int long_retry, short_retry; - int preamble; - int default_beacon_period, beacon_period, listen_interval; - int CurrentAuthentTransactionSeqNum, ExpectedAuthentTransactionSeqNum; - int AuthenticationRequestRetryCnt, AssociationRequestRetryCnt, ReAssociationRequestRetryCnt; - enum { - SITE_SURVEY_IDLE, - SITE_SURVEY_IN_PROGRESS, - SITE_SURVEY_COMPLETED - } site_survey_state; - unsigned long last_survey; - - int station_was_associated, station_is_associated; - int fast_scan; - - struct bss_info { - int channel; - int SSIDsize; - int RSSI; - int UsingWEP; - int preamble; - int beacon_period; - int BSStype; - u8 BSSID[6]; - u8 SSID[MAX_SSID_LENGTH]; - } BSSinfo[MAX_BSS_ENTRIES]; - int BSS_list_entries, current_BSS; - int connect_to_any_BSS; - int SSID_size, new_SSID_size; - u8 CurrentBSSID[6], BSSID[6]; - u8 SSID[MAX_SSID_LENGTH], new_SSID[MAX_SSID_LENGTH]; - u64 last_beacon_timestamp; - u8 rx_buf[MAX_WIRELESS_BODY]; -}; - -static u8 atmel_basic_rates[4] = {0x82, 0x84, 0x0b, 0x16}; - -static const struct { - int reg_domain; - int min, max; - char *name; -} channel_table[] = { { REG_DOMAIN_FCC, 1, 11, "USA" }, - { REG_DOMAIN_DOC, 1, 11, "Canada" }, - { REG_DOMAIN_ETSI, 1, 13, "Europe" }, - { REG_DOMAIN_SPAIN, 10, 11, "Spain" }, - { REG_DOMAIN_FRANCE, 10, 13, "France" }, - { REG_DOMAIN_MKK, 14, 14, "MKK" }, - { REG_DOMAIN_MKK1, 1, 14, "MKK1" }, - { REG_DOMAIN_ISRAEL, 3, 9, "Israel"} }; - -static void build_wpa_mib(struct atmel_private *priv); -static void atmel_copy_to_card(struct net_device *dev, u16 dest, - const unsigned char *src, u16 len); -static void atmel_copy_to_host(struct net_device *dev, unsigned char *dest, - u16 src, u16 len); -static void atmel_set_gcr(struct net_device *dev, u16 mask); -static void atmel_clear_gcr(struct net_device *dev, u16 mask); -static int atmel_lock_mac(struct atmel_private *priv); -static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data); -static void atmel_command_irq(struct atmel_private *priv); -static int atmel_validate_channel(struct atmel_private *priv, int channel); -static void atmel_management_frame(struct atmel_private *priv, - struct ieee80211_hdr *header, - u16 frame_len, u8 rssi); -static void atmel_management_timer(struct timer_list *t); -static void atmel_send_command(struct atmel_private *priv, int command, - void *cmd, int cmd_size); -static int atmel_send_command_wait(struct atmel_private *priv, int command, - void *cmd, int cmd_size); -static void atmel_transmit_management_frame(struct atmel_private *priv, - struct ieee80211_hdr *header, - u8 *body, int body_len); - -static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index); -static void atmel_set_mib8(struct atmel_private *priv, u8 type, u8 index, - u8 data); -static void atmel_set_mib16(struct atmel_private *priv, u8 type, u8 index, - u16 data); -static void atmel_set_mib(struct atmel_private *priv, u8 type, u8 index, - const u8 *data, int data_len); -static void atmel_get_mib(struct atmel_private *priv, u8 type, u8 index, - u8 *data, int data_len); -static void atmel_scan(struct atmel_private *priv, int specific_ssid); -static void atmel_join_bss(struct atmel_private *priv, int bss_index); -static void atmel_smooth_qual(struct atmel_private *priv); -static void atmel_writeAR(struct net_device *dev, u16 data); -static int probe_atmel_card(struct net_device *dev); -static int reset_atmel_card(struct net_device *dev); -static void atmel_enter_state(struct atmel_private *priv, int new_state); -int atmel_open (struct net_device *dev); - -static inline u16 atmel_hi(struct atmel_private *priv, u16 offset) -{ - return priv->host_info_base + offset; -} - -static inline u16 atmel_co(struct atmel_private *priv, u16 offset) -{ - return priv->host_info.command_pos + offset; -} - -static inline u16 atmel_rx(struct atmel_private *priv, u16 offset, u16 desc) -{ - return priv->host_info.rx_desc_pos + (sizeof(struct rx_desc) * desc) + offset; -} - -static inline u16 atmel_tx(struct atmel_private *priv, u16 offset, u16 desc) -{ - return priv->host_info.tx_desc_pos + (sizeof(struct tx_desc) * desc) + offset; -} - -static inline u8 atmel_read8(struct net_device *dev, u16 offset) -{ - return inb(dev->base_addr + offset); -} - -static inline void atmel_write8(struct net_device *dev, u16 offset, u8 data) -{ - outb(data, dev->base_addr + offset); -} - -static inline u16 atmel_read16(struct net_device *dev, u16 offset) -{ - return inw(dev->base_addr + offset); -} - -static inline void atmel_write16(struct net_device *dev, u16 offset, u16 data) -{ - outw(data, dev->base_addr + offset); -} - -static inline u8 atmel_rmem8(struct atmel_private *priv, u16 pos) -{ - atmel_writeAR(priv->dev, pos); - return atmel_read8(priv->dev, DR); -} - -static inline void atmel_wmem8(struct atmel_private *priv, u16 pos, u16 data) -{ - atmel_writeAR(priv->dev, pos); - atmel_write8(priv->dev, DR, data); -} - -static inline u16 atmel_rmem16(struct atmel_private *priv, u16 pos) -{ - atmel_writeAR(priv->dev, pos); - return atmel_read16(priv->dev, DR); -} - -static inline void atmel_wmem16(struct atmel_private *priv, u16 pos, u16 data) -{ - atmel_writeAR(priv->dev, pos); - atmel_write16(priv->dev, DR, data); -} - -static const struct iw_handler_def atmel_handler_def; - -static void tx_done_irq(struct atmel_private *priv) -{ - int i; - - for (i = 0; - atmel_rmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_head)) == TX_DONE && - i < priv->host_info.tx_desc_count; - i++) { - u8 status = atmel_rmem8(priv, atmel_tx(priv, TX_DESC_STATUS_OFFSET, priv->tx_desc_head)); - u16 msdu_size = atmel_rmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, priv->tx_desc_head)); - u8 type = atmel_rmem8(priv, atmel_tx(priv, TX_DESC_PACKET_TYPE_OFFSET, priv->tx_desc_head)); - - atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_head), 0); - - priv->tx_free_mem += msdu_size; - priv->tx_desc_free++; - - if (priv->tx_buff_head + msdu_size > (priv->host_info.tx_buff_pos + priv->host_info.tx_buff_size)) - priv->tx_buff_head = 0; - else - priv->tx_buff_head += msdu_size; - - if (priv->tx_desc_head < (priv->host_info.tx_desc_count - 1)) - priv->tx_desc_head++ ; - else - priv->tx_desc_head = 0; - - if (type == TX_PACKET_TYPE_DATA) { - if (status == TX_STATUS_SUCCESS) - priv->dev->stats.tx_packets++; - else - priv->dev->stats.tx_errors++; - netif_wake_queue(priv->dev); - } - } -} - -static u16 find_tx_buff(struct atmel_private *priv, u16 len) -{ - u16 bottom_free = priv->host_info.tx_buff_size - priv->tx_buff_tail; - - if (priv->tx_desc_free == 3 || priv->tx_free_mem < len) - return 0; - - if (bottom_free >= len) - return priv->host_info.tx_buff_pos + priv->tx_buff_tail; - - if (priv->tx_free_mem - bottom_free >= len) { - priv->tx_buff_tail = 0; - return priv->host_info.tx_buff_pos; - } - - return 0; -} - -static void tx_update_descriptor(struct atmel_private *priv, int is_bcast, - u16 len, u16 buff, u8 type) -{ - atmel_wmem16(priv, atmel_tx(priv, TX_DESC_POS_OFFSET, priv->tx_desc_tail), buff); - atmel_wmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, priv->tx_desc_tail), len); - if (!priv->use_wpa) - atmel_wmem16(priv, atmel_tx(priv, TX_DESC_HOST_LENGTH_OFFSET, priv->tx_desc_tail), len); - atmel_wmem8(priv, atmel_tx(priv, TX_DESC_PACKET_TYPE_OFFSET, priv->tx_desc_tail), type); - atmel_wmem8(priv, atmel_tx(priv, TX_DESC_RATE_OFFSET, priv->tx_desc_tail), priv->tx_rate); - atmel_wmem8(priv, atmel_tx(priv, TX_DESC_RETRY_OFFSET, priv->tx_desc_tail), 0); - if (priv->use_wpa) { - int cipher_type, cipher_length; - if (is_bcast) { - cipher_type = priv->group_cipher_suite; - if (cipher_type == CIPHER_SUITE_WEP_64 || - cipher_type == CIPHER_SUITE_WEP_128) - cipher_length = 8; - else if (cipher_type == CIPHER_SUITE_TKIP) - cipher_length = 12; - else if (priv->pairwise_cipher_suite == CIPHER_SUITE_WEP_64 || - priv->pairwise_cipher_suite == CIPHER_SUITE_WEP_128) { - cipher_type = priv->pairwise_cipher_suite; - cipher_length = 8; - } else { - cipher_type = CIPHER_SUITE_NONE; - cipher_length = 0; - } - } else { - cipher_type = priv->pairwise_cipher_suite; - if (cipher_type == CIPHER_SUITE_WEP_64 || - cipher_type == CIPHER_SUITE_WEP_128) - cipher_length = 8; - else if (cipher_type == CIPHER_SUITE_TKIP) - cipher_length = 12; - else if (priv->group_cipher_suite == CIPHER_SUITE_WEP_64 || - priv->group_cipher_suite == CIPHER_SUITE_WEP_128) { - cipher_type = priv->group_cipher_suite; - cipher_length = 8; - } else { - cipher_type = CIPHER_SUITE_NONE; - cipher_length = 0; - } - } - - atmel_wmem8(priv, atmel_tx(priv, TX_DESC_CIPHER_TYPE_OFFSET, priv->tx_desc_tail), - cipher_type); - atmel_wmem8(priv, atmel_tx(priv, TX_DESC_CIPHER_LENGTH_OFFSET, priv->tx_desc_tail), - cipher_length); - } - atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, priv->tx_desc_tail), 0x80000000L); - atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_tail), TX_FIRM_OWN); - if (priv->tx_desc_previous != priv->tx_desc_tail) - atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, priv->tx_desc_previous), 0); - priv->tx_desc_previous = priv->tx_desc_tail; - if (priv->tx_desc_tail < (priv->host_info.tx_desc_count - 1)) - priv->tx_desc_tail++; - else - priv->tx_desc_tail = 0; - priv->tx_desc_free--; - priv->tx_free_mem -= len; -} - -static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev) -{ - struct atmel_private *priv = netdev_priv(dev); - struct ieee80211_hdr header; - unsigned long flags; - u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; - - if (priv->card && priv->present_callback && - !(*priv->present_callback)(priv->card)) { - dev->stats.tx_errors++; - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - - if (priv->station_state != STATION_STATE_READY) { - dev->stats.tx_errors++; - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - - /* first ensure the timer func cannot run */ - spin_lock_bh(&priv->timerlock); - /* then stop the hardware ISR */ - spin_lock_irqsave(&priv->irqlock, flags); - /* nb doing the above in the opposite order will deadlock */ - - /* The Wireless Header is 30 bytes. In the Ethernet packet we "cut" the - 12 first bytes (containing DA/SA) and put them in the appropriate - fields of the Wireless Header. Thus the packet length is then the - initial + 18 (+30-12) */ - - if (!(buff = find_tx_buff(priv, len + 18))) { - dev->stats.tx_dropped++; - spin_unlock_irqrestore(&priv->irqlock, flags); - spin_unlock_bh(&priv->timerlock); - netif_stop_queue(dev); - return NETDEV_TX_BUSY; - } - - frame_ctl = IEEE80211_FTYPE_DATA; - header.duration_id = 0; - header.seq_ctrl = 0; - if (priv->wep_is_on) - frame_ctl |= IEEE80211_FCTL_PROTECTED; - if (priv->operating_mode == IW_MODE_ADHOC) { - skb_copy_from_linear_data(skb, &header.addr1, ETH_ALEN); - memcpy(&header.addr2, dev->dev_addr, ETH_ALEN); - memcpy(&header.addr3, priv->BSSID, ETH_ALEN); - } else { - frame_ctl |= IEEE80211_FCTL_TODS; - memcpy(&header.addr1, priv->CurrentBSSID, ETH_ALEN); - memcpy(&header.addr2, dev->dev_addr, ETH_ALEN); - skb_copy_from_linear_data(skb, &header.addr3, ETH_ALEN); - } - - if (priv->use_wpa) - memcpy(&header.addr4, rfc1042_header, ETH_ALEN); - - header.frame_control = cpu_to_le16(frame_ctl); - /* Copy the wireless header into the card */ - atmel_copy_to_card(dev, buff, (unsigned char *)&header, DATA_FRAME_WS_HEADER_SIZE); - /* Copy the packet sans its 802.3 header addresses which have been replaced */ - atmel_copy_to_card(dev, buff + DATA_FRAME_WS_HEADER_SIZE, skb->data + 12, len - 12); - priv->tx_buff_tail += len - 12 + DATA_FRAME_WS_HEADER_SIZE; - - /* low bit of first byte of destination tells us if broadcast */ - tx_update_descriptor(priv, *(skb->data) & 0x01, len + 18, buff, TX_PACKET_TYPE_DATA); - dev->stats.tx_bytes += len; - - spin_unlock_irqrestore(&priv->irqlock, flags); - spin_unlock_bh(&priv->timerlock); - dev_kfree_skb(skb); - - return NETDEV_TX_OK; -} - -static void atmel_transmit_management_frame(struct atmel_private *priv, - struct ieee80211_hdr *header, - u8 *body, int body_len) -{ - u16 buff; - int len = MGMT_FRAME_BODY_OFFSET + body_len; - - if (!(buff = find_tx_buff(priv, len))) - return; - - atmel_copy_to_card(priv->dev, buff, (u8 *)header, MGMT_FRAME_BODY_OFFSET); - atmel_copy_to_card(priv->dev, buff + MGMT_FRAME_BODY_OFFSET, body, body_len); - priv->tx_buff_tail += len; - tx_update_descriptor(priv, header->addr1[0] & 0x01, len, buff, TX_PACKET_TYPE_MGMT); -} - -static void fast_rx_path(struct atmel_private *priv, - struct ieee80211_hdr *header, - u16 msdu_size, u16 rx_packet_loc, u32 crc) -{ - /* fast path: unfragmented packet copy directly into skbuf */ - u8 mac4[6]; - struct sk_buff *skb; - unsigned char *skbp; - - /* get the final, mac 4 header field, this tells us encapsulation */ - atmel_copy_to_host(priv->dev, mac4, rx_packet_loc + 24, 6); - msdu_size -= 6; - - if (priv->do_rx_crc) { - crc = crc32_le(crc, mac4, 6); - msdu_size -= 4; - } - - if (!(skb = dev_alloc_skb(msdu_size + 14))) { - priv->dev->stats.rx_dropped++; - return; - } - - skb_reserve(skb, 2); - skbp = skb_put(skb, msdu_size + 12); - atmel_copy_to_host(priv->dev, skbp + 12, rx_packet_loc + 30, msdu_size); - - if (priv->do_rx_crc) { - u32 netcrc; - crc = crc32_le(crc, skbp + 12, msdu_size); - atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + 30 + msdu_size, 4); - if ((crc ^ 0xffffffff) != netcrc) { - priv->dev->stats.rx_crc_errors++; - dev_kfree_skb(skb); - return; - } - } - - memcpy(skbp, header->addr1, ETH_ALEN); /* destination address */ - if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS) - memcpy(&skbp[ETH_ALEN], header->addr3, ETH_ALEN); - else - memcpy(&skbp[ETH_ALEN], header->addr2, ETH_ALEN); /* source address */ - - skb->protocol = eth_type_trans(skb, priv->dev); - skb->ip_summed = CHECKSUM_NONE; - netif_rx(skb); - priv->dev->stats.rx_bytes += 12 + msdu_size; - priv->dev->stats.rx_packets++; -} - -/* Test to see if the packet in card memory at packet_loc has a valid CRC - It doesn't matter that this is slow: it is only used to proble the first few - packets. */ -static int probe_crc(struct atmel_private *priv, u16 packet_loc, u16 msdu_size) -{ - int i = msdu_size - 4; - u32 netcrc, crc = 0xffffffff; - - if (msdu_size < 4) - return 0; - - atmel_copy_to_host(priv->dev, (void *)&netcrc, packet_loc + i, 4); - - atmel_writeAR(priv->dev, packet_loc); - while (i--) { - u8 octet = atmel_read8(priv->dev, DR); - crc = crc32_le(crc, &octet, 1); - } - - return (crc ^ 0xffffffff) == netcrc; -} - -static void frag_rx_path(struct atmel_private *priv, - struct ieee80211_hdr *header, - u16 msdu_size, u16 rx_packet_loc, u32 crc, u16 seq_no, - u8 frag_no, int more_frags) -{ - u8 mac4[ETH_ALEN]; - u8 source[ETH_ALEN]; - struct sk_buff *skb; - - if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS) - memcpy(source, header->addr3, ETH_ALEN); - else - memcpy(source, header->addr2, ETH_ALEN); - - rx_packet_loc += 24; /* skip header */ - - if (priv->do_rx_crc) - msdu_size -= 4; - - if (frag_no == 0) { /* first fragment */ - atmel_copy_to_host(priv->dev, mac4, rx_packet_loc, ETH_ALEN); - msdu_size -= ETH_ALEN; - rx_packet_loc += ETH_ALEN; - - if (priv->do_rx_crc) - crc = crc32_le(crc, mac4, 6); - - priv->frag_seq = seq_no; - priv->frag_no = 1; - priv->frag_len = msdu_size; - memcpy(priv->frag_source, source, ETH_ALEN); - memcpy(&priv->rx_buf[ETH_ALEN], source, ETH_ALEN); - memcpy(priv->rx_buf, header->addr1, ETH_ALEN); - - atmel_copy_to_host(priv->dev, &priv->rx_buf[12], rx_packet_loc, msdu_size); - - if (priv->do_rx_crc) { - u32 netcrc; - crc = crc32_le(crc, &priv->rx_buf[12], msdu_size); - atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4); - if ((crc ^ 0xffffffff) != netcrc) { - priv->dev->stats.rx_crc_errors++; - eth_broadcast_addr(priv->frag_source); - } - } - - } else if (priv->frag_no == frag_no && - priv->frag_seq == seq_no && - memcmp(priv->frag_source, source, ETH_ALEN) == 0) { - - atmel_copy_to_host(priv->dev, &priv->rx_buf[12 + priv->frag_len], - rx_packet_loc, msdu_size); - if (priv->do_rx_crc) { - u32 netcrc; - crc = crc32_le(crc, - &priv->rx_buf[12 + priv->frag_len], - msdu_size); - atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4); - if ((crc ^ 0xffffffff) != netcrc) { - priv->dev->stats.rx_crc_errors++; - eth_broadcast_addr(priv->frag_source); - more_frags = 1; /* don't send broken assembly */ - } - } - - priv->frag_len += msdu_size; - priv->frag_no++; - - if (!more_frags) { /* last one */ - eth_broadcast_addr(priv->frag_source); - if (!(skb = dev_alloc_skb(priv->frag_len + 14))) { - priv->dev->stats.rx_dropped++; - } else { - skb_reserve(skb, 2); - skb_put_data(skb, priv->rx_buf, - priv->frag_len + 12); - skb->protocol = eth_type_trans(skb, priv->dev); - skb->ip_summed = CHECKSUM_NONE; - netif_rx(skb); - priv->dev->stats.rx_bytes += priv->frag_len + 12; - priv->dev->stats.rx_packets++; - } - } - } else - priv->wstats.discard.fragment++; -} - -static void rx_done_irq(struct atmel_private *priv) -{ - int i; - struct ieee80211_hdr header; - - for (i = 0; - atmel_rmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head)) == RX_DESC_FLAG_VALID && - i < priv->host_info.rx_desc_count; - i++) { - - u16 msdu_size, rx_packet_loc, frame_ctl, seq_control; - u8 status = atmel_rmem8(priv, atmel_rx(priv, RX_DESC_STATUS_OFFSET, priv->rx_desc_head)); - u32 crc = 0xffffffff; - - if (status != RX_STATUS_SUCCESS) { - if (status == 0xc1) /* determined by experiment */ - priv->wstats.discard.nwid++; - else - priv->dev->stats.rx_errors++; - goto next; - } - - msdu_size = atmel_rmem16(priv, atmel_rx(priv, RX_DESC_MSDU_SIZE_OFFSET, priv->rx_desc_head)); - rx_packet_loc = atmel_rmem16(priv, atmel_rx(priv, RX_DESC_MSDU_POS_OFFSET, priv->rx_desc_head)); - - if (msdu_size < 30) { - priv->dev->stats.rx_errors++; - goto next; - } - - /* Get header as far as end of seq_ctrl */ - atmel_copy_to_host(priv->dev, (char *)&header, rx_packet_loc, 24); - frame_ctl = le16_to_cpu(header.frame_control); - seq_control = le16_to_cpu(header.seq_ctrl); - - /* probe for CRC use here if needed once five packets have - arrived with the same crc status, we assume we know what's - happening and stop probing */ - if (priv->probe_crc) { - if (!priv->wep_is_on || !(frame_ctl & IEEE80211_FCTL_PROTECTED)) { - priv->do_rx_crc = probe_crc(priv, rx_packet_loc, msdu_size); - } else { - priv->do_rx_crc = probe_crc(priv, rx_packet_loc + 24, msdu_size - 24); - } - if (priv->do_rx_crc) { - if (priv->crc_ok_cnt++ > 5) - priv->probe_crc = 0; - } else { - if (priv->crc_ko_cnt++ > 5) - priv->probe_crc = 0; - } - } - - /* don't CRC header when WEP in use */ - if (priv->do_rx_crc && (!priv->wep_is_on || !(frame_ctl & IEEE80211_FCTL_PROTECTED))) { - crc = crc32_le(0xffffffff, (unsigned char *)&header, 24); - } - msdu_size -= 24; /* header */ - - if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) { - int more_fragments = frame_ctl & IEEE80211_FCTL_MOREFRAGS; - u8 packet_fragment_no = seq_control & IEEE80211_SCTL_FRAG; - u16 packet_sequence_no = (seq_control & IEEE80211_SCTL_SEQ) >> 4; - - if (!more_fragments && packet_fragment_no == 0) { - fast_rx_path(priv, &header, msdu_size, rx_packet_loc, crc); - } else { - frag_rx_path(priv, &header, msdu_size, rx_packet_loc, crc, - packet_sequence_no, packet_fragment_no, more_fragments); - } - } - - if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { - /* copy rest of packet into buffer */ - atmel_copy_to_host(priv->dev, (unsigned char *)&priv->rx_buf, rx_packet_loc + 24, msdu_size); - - /* we use the same buffer for frag reassembly and control packets */ - eth_broadcast_addr(priv->frag_source); - - if (priv->do_rx_crc) { - /* last 4 octets is crc */ - msdu_size -= 4; - crc = crc32_le(crc, (unsigned char *)&priv->rx_buf, msdu_size); - if ((crc ^ 0xffffffff) != (*((u32 *)&priv->rx_buf[msdu_size]))) { - priv->dev->stats.rx_crc_errors++; - goto next; - } - } - - atmel_management_frame(priv, &header, msdu_size, - atmel_rmem8(priv, atmel_rx(priv, RX_DESC_RSSI_OFFSET, priv->rx_desc_head))); - } - -next: - /* release descriptor */ - atmel_wmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head), RX_DESC_FLAG_CONSUMED); - - if (priv->rx_desc_head < (priv->host_info.rx_desc_count - 1)) - priv->rx_desc_head++; - else - priv->rx_desc_head = 0; - } -} - -static irqreturn_t service_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = (struct net_device *) dev_id; - struct atmel_private *priv = netdev_priv(dev); - u8 isr; - int i = -1; - static const u8 irq_order[] = { - ISR_OUT_OF_RANGE, - ISR_RxCOMPLETE, - ISR_TxCOMPLETE, - ISR_RxFRAMELOST, - ISR_FATAL_ERROR, - ISR_COMMAND_COMPLETE, - ISR_IBSS_MERGE, - ISR_GENERIC_IRQ - }; - - if (priv->card && priv->present_callback && - !(*priv->present_callback)(priv->card)) - return IRQ_HANDLED; - - /* In this state upper-level code assumes it can mess with - the card unhampered by interrupts which may change register state. - Note that even though the card shouldn't generate interrupts - the inturrupt line may be shared. This allows card setup - to go on without disabling interrupts for a long time. */ - if (priv->station_state == STATION_STATE_DOWN) - return IRQ_NONE; - - atmel_clear_gcr(dev, GCR_ENINT); /* disable interrupts */ - - while (1) { - if (!atmel_lock_mac(priv)) { - /* failed to contact card */ - printk(KERN_ALERT "%s: failed to contact MAC.\n", dev->name); - return IRQ_HANDLED; - } - - isr = atmel_rmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET)); - atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); - - if (!isr) { - atmel_set_gcr(dev, GCR_ENINT); /* enable interrupts */ - return i == -1 ? IRQ_NONE : IRQ_HANDLED; - } - - atmel_set_gcr(dev, GCR_ACKINT); /* acknowledge interrupt */ - - for (i = 0; i < ARRAY_SIZE(irq_order); i++) - if (isr & irq_order[i]) - break; - - if (!atmel_lock_mac(priv)) { - /* failed to contact card */ - printk(KERN_ALERT "%s: failed to contact MAC.\n", dev->name); - return IRQ_HANDLED; - } - - isr = atmel_rmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET)); - isr ^= irq_order[i]; - atmel_wmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET), isr); - atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); - - switch (irq_order[i]) { - - case ISR_OUT_OF_RANGE: - if (priv->operating_mode == IW_MODE_INFRA && - priv->station_state == STATION_STATE_READY) { - priv->station_is_associated = 0; - atmel_scan(priv, 1); - } - break; - - case ISR_RxFRAMELOST: - priv->wstats.discard.misc++; - fallthrough; - case ISR_RxCOMPLETE: - rx_done_irq(priv); - break; - - case ISR_TxCOMPLETE: - tx_done_irq(priv); - break; - - case ISR_FATAL_ERROR: - printk(KERN_ALERT "%s: *** FATAL error interrupt ***\n", dev->name); - atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); - break; - - case ISR_COMMAND_COMPLETE: - atmel_command_irq(priv); - break; - - case ISR_IBSS_MERGE: - atmel_get_mib(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_BSSID_POS, - priv->CurrentBSSID, 6); - /* The WPA stuff cares about the current AP address */ - if (priv->use_wpa) - build_wpa_mib(priv); - break; - case ISR_GENERIC_IRQ: - printk(KERN_INFO "%s: Generic_irq received.\n", dev->name); - break; - } - } -} - -static struct iw_statistics *atmel_get_wireless_stats(struct net_device *dev) -{ - struct atmel_private *priv = netdev_priv(dev); - - /* update the link quality here in case we are seeing no beacons - at all to drive the process */ - atmel_smooth_qual(priv); - - priv->wstats.status = priv->station_state; - - if (priv->operating_mode == IW_MODE_INFRA) { - if (priv->station_state != STATION_STATE_READY) { - priv->wstats.qual.qual = 0; - priv->wstats.qual.level = 0; - priv->wstats.qual.updated = (IW_QUAL_QUAL_INVALID - | IW_QUAL_LEVEL_INVALID); - } - priv->wstats.qual.noise = 0; - priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID; - } else { - /* Quality levels cannot be determined in ad-hoc mode, - because we can 'hear' more that one remote station. */ - priv->wstats.qual.qual = 0; - priv->wstats.qual.level = 0; - priv->wstats.qual.noise = 0; - priv->wstats.qual.updated = IW_QUAL_QUAL_INVALID - | IW_QUAL_LEVEL_INVALID - | IW_QUAL_NOISE_INVALID; - priv->wstats.miss.beacon = 0; - } - - return &priv->wstats; -} - -static int atmel_set_mac_address(struct net_device *dev, void *p) -{ - struct sockaddr *addr = p; - - eth_hw_addr_set(dev, addr->sa_data); - return atmel_open(dev); -} - -EXPORT_SYMBOL(atmel_open); - -int atmel_open(struct net_device *dev) -{ - struct atmel_private *priv = netdev_priv(dev); - int i, channel, err; - - /* any scheduled timer is no longer needed and might screw things up.. */ - del_timer_sync(&priv->management_timer); - - /* Interrupts will not touch the card once in this state... */ - priv->station_state = STATION_STATE_DOWN; - - if (priv->new_SSID_size) { - memcpy(priv->SSID, priv->new_SSID, priv->new_SSID_size); - priv->SSID_size = priv->new_SSID_size; - priv->new_SSID_size = 0; - } - priv->BSS_list_entries = 0; - - priv->AuthenticationRequestRetryCnt = 0; - priv->AssociationRequestRetryCnt = 0; - priv->ReAssociationRequestRetryCnt = 0; - priv->CurrentAuthentTransactionSeqNum = 0x0001; - priv->ExpectedAuthentTransactionSeqNum = 0x0002; - - priv->site_survey_state = SITE_SURVEY_IDLE; - priv->station_is_associated = 0; - - err = reset_atmel_card(dev); - if (err) - return err; - - if (priv->config_reg_domain) { - priv->reg_domain = priv->config_reg_domain; - atmel_set_mib8(priv, Phy_Mib_Type, PHY_MIB_REG_DOMAIN_POS, priv->reg_domain); - } else { - priv->reg_domain = atmel_get_mib8(priv, Phy_Mib_Type, PHY_MIB_REG_DOMAIN_POS); - for (i = 0; i < ARRAY_SIZE(channel_table); i++) - if (priv->reg_domain == channel_table[i].reg_domain) - break; - if (i == ARRAY_SIZE(channel_table)) { - priv->reg_domain = REG_DOMAIN_MKK1; - printk(KERN_ALERT "%s: failed to get regulatory domain: assuming MKK1.\n", dev->name); - } - } - - if ((channel = atmel_validate_channel(priv, priv->channel))) - priv->channel = channel; - - /* this moves station_state on.... */ - atmel_scan(priv, 1); - - atmel_set_gcr(priv->dev, GCR_ENINT); /* enable interrupts */ - return 0; -} - -static int atmel_close(struct net_device *dev) -{ - struct atmel_private *priv = netdev_priv(dev); - - /* Send event to userspace that we are disassociating */ - if (priv->station_state == STATION_STATE_READY) { - union iwreq_data wrqu; - - wrqu.data.length = 0; - wrqu.data.flags = 0; - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - eth_zero_addr(wrqu.ap_addr.sa_data); - wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); - } - - atmel_enter_state(priv, STATION_STATE_DOWN); - - if (priv->bus_type == BUS_TYPE_PCCARD) - atmel_write16(dev, GCR, 0x0060); - atmel_write16(dev, GCR, 0x0040); - return 0; -} - -static int atmel_validate_channel(struct atmel_private *priv, int channel) -{ - /* check that channel is OK, if so return zero, - else return suitable default channel */ - int i; - - for (i = 0; i < ARRAY_SIZE(channel_table); i++) - if (priv->reg_domain == channel_table[i].reg_domain) { - if (channel >= channel_table[i].min && - channel <= channel_table[i].max) - return 0; - else - return channel_table[i].min; - } - return 0; -} - -#ifdef CONFIG_PROC_FS -static int atmel_proc_show(struct seq_file *m, void *v) -{ - struct atmel_private *priv = m->private; - int i; - char *s, *r, *c; - - seq_printf(m, "Driver version:\t\t%d.%d\n", DRIVER_MAJOR, DRIVER_MINOR); - - if (priv->station_state != STATION_STATE_DOWN) { - seq_printf(m, - "Firmware version:\t%d.%d build %d\n" - "Firmware location:\t", - priv->host_info.major_version, - priv->host_info.minor_version, - priv->host_info.build_version); - - if (priv->card_type != CARD_TYPE_EEPROM) - seq_puts(m, "on card\n"); - else if (priv->firmware) - seq_printf(m, "%s loaded by host\n", priv->firmware_id); - else - seq_printf(m, "%s loaded by hotplug\n", priv->firmware_id); - - switch (priv->card_type) { - case CARD_TYPE_PARALLEL_FLASH: - c = "Parallel flash"; - break; - case CARD_TYPE_SPI_FLASH: - c = "SPI flash\n"; - break; - case CARD_TYPE_EEPROM: - c = "EEPROM"; - break; - default: - c = ""; - } - - r = ""; - for (i = 0; i < ARRAY_SIZE(channel_table); i++) - if (priv->reg_domain == channel_table[i].reg_domain) - r = channel_table[i].name; - - seq_printf(m, "MAC memory type:\t%s\n", c); - seq_printf(m, "Regulatory domain:\t%s\n", r); - seq_printf(m, "Host CRC checking:\t%s\n", - priv->do_rx_crc ? "On" : "Off"); - seq_printf(m, "WPA-capable firmware:\t%s\n", - priv->use_wpa ? "Yes" : "No"); - } - - switch (priv->station_state) { - case STATION_STATE_SCANNING: - s = "Scanning"; - break; - case STATION_STATE_JOINNING: - s = "Joining"; - break; - case STATION_STATE_AUTHENTICATING: - s = "Authenticating"; - break; - case STATION_STATE_ASSOCIATING: - s = "Associating"; - break; - case STATION_STATE_READY: - s = "Ready"; - break; - case STATION_STATE_REASSOCIATING: - s = "Reassociating"; - break; - case STATION_STATE_MGMT_ERROR: - s = "Management error"; - break; - case STATION_STATE_DOWN: - s = "Down"; - break; - default: - s = ""; - } - - seq_printf(m, "Current state:\t\t%s\n", s); - return 0; -} -#endif - -static const struct net_device_ops atmel_netdev_ops = { - .ndo_open = atmel_open, - .ndo_stop = atmel_close, - .ndo_set_mac_address = atmel_set_mac_address, - .ndo_start_xmit = start_tx, - .ndo_validate_addr = eth_validate_addr, -}; - -struct net_device *init_atmel_card(unsigned short irq, unsigned long port, - const AtmelFWType fw_type, - struct device *sys_dev, - int (*card_present)(void *), void *card) -{ - struct net_device *dev; - struct atmel_private *priv; - int rc; - - /* Create the network device object. */ - dev = alloc_etherdev(sizeof(*priv)); - if (!dev) - return NULL; - - if (dev_alloc_name(dev, dev->name) < 0) { - printk(KERN_ERR "atmel: Couldn't get name!\n"); - goto err_out_free; - } - - priv = netdev_priv(dev); - priv->dev = dev; - priv->sys_dev = sys_dev; - priv->present_callback = card_present; - priv->card = card; - priv->firmware = NULL; - priv->firmware_type = fw_type; - if (firmware) /* module parameter */ - strscpy(priv->firmware_id, firmware, sizeof(priv->firmware_id)); - priv->bus_type = card_present ? BUS_TYPE_PCCARD : BUS_TYPE_PCI; - priv->station_state = STATION_STATE_DOWN; - priv->do_rx_crc = 0; - /* For PCMCIA cards, some chips need CRC, some don't - so we have to probe. */ - if (priv->bus_type == BUS_TYPE_PCCARD) { - priv->probe_crc = 1; - priv->crc_ok_cnt = priv->crc_ko_cnt = 0; - } else - priv->probe_crc = 0; - priv->last_qual = jiffies; - priv->last_beacon_timestamp = 0; - memset(priv->frag_source, 0xff, sizeof(priv->frag_source)); - eth_zero_addr(priv->BSSID); - priv->CurrentBSSID[0] = 0xFF; /* Initialize to something invalid.... */ - priv->station_was_associated = 0; - - priv->last_survey = jiffies; - priv->preamble = LONG_PREAMBLE; - priv->operating_mode = IW_MODE_INFRA; - priv->connect_to_any_BSS = 0; - priv->config_reg_domain = 0; - priv->reg_domain = 0; - priv->tx_rate = 3; - priv->auto_tx_rate = 1; - priv->channel = 4; - priv->power_mode = 0; - priv->SSID[0] = '\0'; - priv->SSID_size = 0; - priv->new_SSID_size = 0; - priv->frag_threshold = 2346; - priv->rts_threshold = 2347; - priv->short_retry = 7; - priv->long_retry = 4; - - priv->wep_is_on = 0; - priv->default_key = 0; - priv->encryption_level = 0; - priv->exclude_unencrypted = 0; - priv->group_cipher_suite = priv->pairwise_cipher_suite = CIPHER_SUITE_NONE; - priv->use_wpa = 0; - memset(priv->wep_keys, 0, sizeof(priv->wep_keys)); - memset(priv->wep_key_len, 0, sizeof(priv->wep_key_len)); - - priv->default_beacon_period = priv->beacon_period = 100; - priv->listen_interval = 1; - - timer_setup(&priv->management_timer, atmel_management_timer, 0); - spin_lock_init(&priv->irqlock); - spin_lock_init(&priv->timerlock); - - dev->netdev_ops = &atmel_netdev_ops; - dev->wireless_handlers = &atmel_handler_def; - dev->irq = irq; - dev->base_addr = port; - - /* MTU range: 68 - 2312 */ - dev->min_mtu = 68; - dev->max_mtu = MAX_WIRELESS_BODY - ETH_FCS_LEN; - - SET_NETDEV_DEV(dev, sys_dev); - - if ((rc = request_irq(dev->irq, service_interrupt, IRQF_SHARED, dev->name, dev))) { - printk(KERN_ERR "%s: register interrupt %d failed, rc %d\n", dev->name, irq, rc); - goto err_out_free; - } - - if (!request_region(dev->base_addr, 32, - priv->bus_type == BUS_TYPE_PCCARD ? "atmel_cs" : "atmel_pci")) { - goto err_out_irq; - } - - if (register_netdev(dev)) - goto err_out_res; - - if (!probe_atmel_card(dev)) { - unregister_netdev(dev); - goto err_out_res; - } - - netif_carrier_off(dev); - - if (!proc_create_single_data("driver/atmel", 0, NULL, atmel_proc_show, - priv)) - printk(KERN_WARNING "atmel: unable to create /proc entry.\n"); - - printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %pM\n", - dev->name, DRIVER_MAJOR, DRIVER_MINOR, dev->dev_addr); - - return dev; - -err_out_res: - release_region(dev->base_addr, 32); -err_out_irq: - free_irq(dev->irq, dev); -err_out_free: - free_netdev(dev); - return NULL; -} - -EXPORT_SYMBOL(init_atmel_card); - -void stop_atmel_card(struct net_device *dev) -{ - struct atmel_private *priv = netdev_priv(dev); - - /* put a brick on it... */ - if (priv->bus_type == BUS_TYPE_PCCARD) - atmel_write16(dev, GCR, 0x0060); - atmel_write16(dev, GCR, 0x0040); - - del_timer_sync(&priv->management_timer); - unregister_netdev(dev); - remove_proc_entry("driver/atmel", NULL); - free_irq(dev->irq, dev); - kfree(priv->firmware); - release_region(dev->base_addr, 32); - free_netdev(dev); -} - -EXPORT_SYMBOL(stop_atmel_card); - -static int atmel_set_essid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->essid; - struct atmel_private *priv = netdev_priv(dev); - - /* Check if we asked for `any' */ - if (dwrq->flags == 0) { - priv->connect_to_any_BSS = 1; - } else { - int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; - - priv->connect_to_any_BSS = 0; - - /* Check the size of the string */ - if (dwrq->length > MAX_SSID_LENGTH) - return -E2BIG; - if (index != 0) - return -EINVAL; - - memcpy(priv->new_SSID, extra, dwrq->length); - priv->new_SSID_size = dwrq->length; - } - - return -EINPROGRESS; -} - -static int atmel_get_essid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->essid; - struct atmel_private *priv = netdev_priv(dev); - - /* Get the current SSID */ - if (priv->new_SSID_size != 0) { - memcpy(extra, priv->new_SSID, priv->new_SSID_size); - dwrq->length = priv->new_SSID_size; - } else { - memcpy(extra, priv->SSID, priv->SSID_size); - dwrq->length = priv->SSID_size; - } - - dwrq->flags = !priv->connect_to_any_BSS; /* active */ - - return 0; -} - -static int atmel_get_wap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct sockaddr *awrq = &wrqu->ap_addr; - struct atmel_private *priv = netdev_priv(dev); - memcpy(awrq->sa_data, priv->CurrentBSSID, ETH_ALEN); - awrq->sa_family = ARPHRD_ETHER; - - return 0; -} - -static int atmel_set_encode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->encoding; - struct atmel_private *priv = netdev_priv(dev); - - /* Basic checking: do we have a key to set ? - * Note : with the new API, it's impossible to get a NULL pointer. - * Therefore, we need to check a key size == 0 instead. - * New version of iwconfig properly set the IW_ENCODE_NOKEY flag - * when no key is present (only change flags), but older versions - * don't do it. - Jean II */ - if (dwrq->length > 0) { - int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; - int current_index = priv->default_key; - /* Check the size of the key */ - if (dwrq->length > 13) { - return -EINVAL; - } - /* Check the index (none -> use current) */ - if (index < 0 || index >= 4) - index = current_index; - else - priv->default_key = index; - /* Set the length */ - if (dwrq->length > 5) - priv->wep_key_len[index] = 13; - else - if (dwrq->length > 0) - priv->wep_key_len[index] = 5; - else - /* Disable the key */ - priv->wep_key_len[index] = 0; - /* Check if the key is not marked as invalid */ - if (!(dwrq->flags & IW_ENCODE_NOKEY)) { - /* Cleanup */ - memset(priv->wep_keys[index], 0, 13); - /* Copy the key in the driver */ - memcpy(priv->wep_keys[index], extra, dwrq->length); - } - /* WE specify that if a valid key is set, encryption - * should be enabled (user may turn it off later) - * This is also how "iwconfig ethX key on" works */ - if (index == current_index && - priv->wep_key_len[index] > 0) { - priv->wep_is_on = 1; - priv->exclude_unencrypted = 1; - if (priv->wep_key_len[index] > 5) { - priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128; - priv->encryption_level = 2; - } else { - priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64; - priv->encryption_level = 1; - } - } - } else { - /* Do we want to just set the transmit key index ? */ - int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; - if (index >= 0 && index < 4) { - priv->default_key = index; - } else - /* Don't complain if only change the mode */ - if (!(dwrq->flags & IW_ENCODE_MODE)) - return -EINVAL; - } - /* Read the flags */ - if (dwrq->flags & IW_ENCODE_DISABLED) { - priv->wep_is_on = 0; - priv->encryption_level = 0; - priv->pairwise_cipher_suite = CIPHER_SUITE_NONE; - } else { - priv->wep_is_on = 1; - if (priv->wep_key_len[priv->default_key] > 5) { - priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128; - priv->encryption_level = 2; - } else { - priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64; - priv->encryption_level = 1; - } - } - if (dwrq->flags & IW_ENCODE_RESTRICTED) - priv->exclude_unencrypted = 1; - if (dwrq->flags & IW_ENCODE_OPEN) - priv->exclude_unencrypted = 0; - - return -EINPROGRESS; /* Call commit handler */ -} - -static int atmel_get_encode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->encoding; - struct atmel_private *priv = netdev_priv(dev); - int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; - - if (!priv->wep_is_on) - dwrq->flags = IW_ENCODE_DISABLED; - else { - if (priv->exclude_unencrypted) - dwrq->flags = IW_ENCODE_RESTRICTED; - else - dwrq->flags = IW_ENCODE_OPEN; - } - /* Which key do we want ? -1 -> tx index */ - if (index < 0 || index >= 4) - index = priv->default_key; - dwrq->flags |= index + 1; - /* Copy the key to the user buffer */ - dwrq->length = priv->wep_key_len[index]; - if (dwrq->length > 16) { - dwrq->length = 0; - } else { - memset(extra, 0, 16); - memcpy(extra, priv->wep_keys[index], dwrq->length); - } - - return 0; -} - -static int atmel_set_encodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct atmel_private *priv = netdev_priv(dev); - struct iw_point *encoding = &wrqu->encoding; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - int idx, key_len, alg = ext->alg, set_key = 1; - - /* Determine and validate the key index */ - idx = encoding->flags & IW_ENCODE_INDEX; - if (idx) { - if (idx < 1 || idx > 4) - return -EINVAL; - idx--; - } else - idx = priv->default_key; - - if (encoding->flags & IW_ENCODE_DISABLED) - alg = IW_ENCODE_ALG_NONE; - - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { - priv->default_key = idx; - set_key = ext->key_len > 0 ? 1 : 0; - } - - if (set_key) { - /* Set the requested key first */ - switch (alg) { - case IW_ENCODE_ALG_NONE: - priv->wep_is_on = 0; - priv->encryption_level = 0; - priv->pairwise_cipher_suite = CIPHER_SUITE_NONE; - break; - case IW_ENCODE_ALG_WEP: - if (ext->key_len > 5) { - priv->wep_key_len[idx] = 13; - priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128; - priv->encryption_level = 2; - } else if (ext->key_len > 0) { - priv->wep_key_len[idx] = 5; - priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64; - priv->encryption_level = 1; - } else { - return -EINVAL; - } - priv->wep_is_on = 1; - memset(priv->wep_keys[idx], 0, 13); - key_len = min ((int)ext->key_len, priv->wep_key_len[idx]); - memcpy(priv->wep_keys[idx], ext->key, key_len); - break; - default: - return -EINVAL; - } - } - - return -EINPROGRESS; -} - -static int atmel_get_encodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct atmel_private *priv = netdev_priv(dev); - struct iw_point *encoding = &wrqu->encoding; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - int idx, max_key_len; - - max_key_len = encoding->length - sizeof(*ext); - if (max_key_len < 0) - return -EINVAL; - - idx = encoding->flags & IW_ENCODE_INDEX; - if (idx) { - if (idx < 1 || idx > 4) - return -EINVAL; - idx--; - } else - idx = priv->default_key; - - encoding->flags = idx + 1; - memset(ext, 0, sizeof(*ext)); - - if (!priv->wep_is_on) { - ext->alg = IW_ENCODE_ALG_NONE; - ext->key_len = 0; - encoding->flags |= IW_ENCODE_DISABLED; - } else { - if (priv->encryption_level > 0) - ext->alg = IW_ENCODE_ALG_WEP; - else - return -EINVAL; - - ext->key_len = priv->wep_key_len[idx]; - memcpy(ext->key, priv->wep_keys[idx], ext->key_len); - encoding->flags |= IW_ENCODE_ENABLED; - } - - return 0; -} - -static int atmel_set_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct atmel_private *priv = netdev_priv(dev); - struct iw_param *param = &wrqu->param; - - switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - case IW_AUTH_CIPHER_PAIRWISE: - case IW_AUTH_CIPHER_GROUP: - case IW_AUTH_KEY_MGMT: - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - case IW_AUTH_PRIVACY_INVOKED: - /* - * atmel does not use these parameters - */ - break; - - case IW_AUTH_DROP_UNENCRYPTED: - priv->exclude_unencrypted = param->value ? 1 : 0; - break; - - case IW_AUTH_80211_AUTH_ALG: { - if (param->value & IW_AUTH_ALG_SHARED_KEY) { - priv->exclude_unencrypted = 1; - } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) { - priv->exclude_unencrypted = 0; - } else - return -EINVAL; - break; - } - - case IW_AUTH_WPA_ENABLED: - /* Silently accept disable of WPA */ - if (param->value > 0) - return -EOPNOTSUPP; - break; - - default: - return -EOPNOTSUPP; - } - return -EINPROGRESS; -} - -static int atmel_get_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct atmel_private *priv = netdev_priv(dev); - struct iw_param *param = &wrqu->param; - - switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_DROP_UNENCRYPTED: - param->value = priv->exclude_unencrypted; - break; - - case IW_AUTH_80211_AUTH_ALG: - if (priv->exclude_unencrypted == 1) - param->value = IW_AUTH_ALG_SHARED_KEY; - else - param->value = IW_AUTH_ALG_OPEN_SYSTEM; - break; - - case IW_AUTH_WPA_ENABLED: - param->value = 0; - break; - - default: - return -EOPNOTSUPP; - } - return 0; -} - - -static int atmel_get_name(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - strcpy(wrqu->name, "IEEE 802.11-DS"); - return 0; -} - -static int atmel_set_rate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->bitrate; - struct atmel_private *priv = netdev_priv(dev); - - if (vwrq->fixed == 0) { - priv->tx_rate = 3; - priv->auto_tx_rate = 1; - } else { - priv->auto_tx_rate = 0; - - /* Which type of value ? */ - if ((vwrq->value < 4) && (vwrq->value >= 0)) { - /* Setting by rate index */ - priv->tx_rate = vwrq->value; - } else { - /* Setting by frequency value */ - switch (vwrq->value) { - case 1000000: - priv->tx_rate = 0; - break; - case 2000000: - priv->tx_rate = 1; - break; - case 5500000: - priv->tx_rate = 2; - break; - case 11000000: - priv->tx_rate = 3; - break; - default: - return -EINVAL; - } - } - } - - return -EINPROGRESS; -} - -static int atmel_set_mode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - __u32 *uwrq = &wrqu->mode; - struct atmel_private *priv = netdev_priv(dev); - - if (*uwrq != IW_MODE_ADHOC && *uwrq != IW_MODE_INFRA) - return -EINVAL; - - priv->operating_mode = *uwrq; - return -EINPROGRESS; -} - -static int atmel_get_mode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - __u32 *uwrq = &wrqu->mode; - struct atmel_private *priv = netdev_priv(dev); - - *uwrq = priv->operating_mode; - return 0; -} - -static int atmel_get_rate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->bitrate; - struct atmel_private *priv = netdev_priv(dev); - - if (priv->auto_tx_rate) { - vwrq->fixed = 0; - vwrq->value = 11000000; - } else { - vwrq->fixed = 1; - switch (priv->tx_rate) { - case 0: - vwrq->value = 1000000; - break; - case 1: - vwrq->value = 2000000; - break; - case 2: - vwrq->value = 5500000; - break; - case 3: - vwrq->value = 11000000; - break; - } - } - return 0; -} - -static int atmel_set_power(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->power; - struct atmel_private *priv = netdev_priv(dev); - priv->power_mode = vwrq->disabled ? 0 : 1; - return -EINPROGRESS; -} - -static int atmel_get_power(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->power; - struct atmel_private *priv = netdev_priv(dev); - vwrq->disabled = priv->power_mode ? 0 : 1; - vwrq->flags = IW_POWER_ON; - return 0; -} - -static int atmel_set_retry(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->retry; - struct atmel_private *priv = netdev_priv(dev); - - if (!vwrq->disabled && (vwrq->flags & IW_RETRY_LIMIT)) { - if (vwrq->flags & IW_RETRY_LONG) - priv->long_retry = vwrq->value; - else if (vwrq->flags & IW_RETRY_SHORT) - priv->short_retry = vwrq->value; - else { - /* No modifier : set both */ - priv->long_retry = vwrq->value; - priv->short_retry = vwrq->value; - } - return -EINPROGRESS; - } - - return -EINVAL; -} - -static int atmel_get_retry(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->retry; - struct atmel_private *priv = netdev_priv(dev); - - vwrq->disabled = 0; /* Can't be disabled */ - - /* Note : by default, display the short retry number */ - if (vwrq->flags & IW_RETRY_LONG) { - vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; - vwrq->value = priv->long_retry; - } else { - vwrq->flags = IW_RETRY_LIMIT; - vwrq->value = priv->short_retry; - if (priv->long_retry != priv->short_retry) - vwrq->flags |= IW_RETRY_SHORT; - } - - return 0; -} - -static int atmel_set_rts(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->rts; - struct atmel_private *priv = netdev_priv(dev); - int rthr = vwrq->value; - - if (vwrq->disabled) - rthr = 2347; - if ((rthr < 0) || (rthr > 2347)) { - return -EINVAL; - } - priv->rts_threshold = rthr; - - return -EINPROGRESS; /* Call commit handler */ -} - -static int atmel_get_rts(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->rts; - struct atmel_private *priv = netdev_priv(dev); - - vwrq->value = priv->rts_threshold; - vwrq->disabled = (vwrq->value >= 2347); - vwrq->fixed = 1; - - return 0; -} - -static int atmel_set_frag(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->frag; - struct atmel_private *priv = netdev_priv(dev); - int fthr = vwrq->value; - - if (vwrq->disabled) - fthr = 2346; - if ((fthr < 256) || (fthr > 2346)) { - return -EINVAL; - } - fthr &= ~0x1; /* Get an even value - is it really needed ??? */ - priv->frag_threshold = fthr; - - return -EINPROGRESS; /* Call commit handler */ -} - -static int atmel_get_frag(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->frag; - struct atmel_private *priv = netdev_priv(dev); - - vwrq->value = priv->frag_threshold; - vwrq->disabled = (vwrq->value >= 2346); - vwrq->fixed = 1; - - return 0; -} - -static int atmel_set_freq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_freq *fwrq = &wrqu->freq; - struct atmel_private *priv = netdev_priv(dev); - int rc = -EINPROGRESS; /* Call commit handler */ - - /* If setting by frequency, convert to a channel */ - if (fwrq->e == 1) { - int f = fwrq->m / 100000; - - /* Hack to fall through... */ - fwrq->e = 0; - fwrq->m = ieee80211_frequency_to_channel(f); - } - /* Setting by channel number */ - if (fwrq->m < 0 || fwrq->m > 1000 || fwrq->e > 0) - rc = -EOPNOTSUPP; - else { - int channel = fwrq->m; - if (atmel_validate_channel(priv, channel) == 0) { - priv->channel = channel; - } else { - rc = -EINVAL; - } - } - return rc; -} - -static int atmel_get_freq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_freq *fwrq = &wrqu->freq; - struct atmel_private *priv = netdev_priv(dev); - - fwrq->m = priv->channel; - fwrq->e = 0; - return 0; -} - -static int atmel_set_scan(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *dwrq, - char *extra) -{ - struct atmel_private *priv = netdev_priv(dev); - unsigned long flags; - - /* Note : you may have realised that, as this is a SET operation, - * this is privileged and therefore a normal user can't - * perform scanning. - * This is not an error, while the device perform scanning, - * traffic doesn't flow, so it's a perfect DoS... - * Jean II */ - - if (priv->station_state == STATION_STATE_DOWN) - return -EAGAIN; - - /* Timeout old surveys. */ - if (time_after(jiffies, priv->last_survey + 20 * HZ)) - priv->site_survey_state = SITE_SURVEY_IDLE; - priv->last_survey = jiffies; - - /* Initiate a scan command */ - if (priv->site_survey_state == SITE_SURVEY_IN_PROGRESS) - return -EBUSY; - - del_timer_sync(&priv->management_timer); - spin_lock_irqsave(&priv->irqlock, flags); - - priv->site_survey_state = SITE_SURVEY_IN_PROGRESS; - priv->fast_scan = 0; - atmel_scan(priv, 0); - spin_unlock_irqrestore(&priv->irqlock, flags); - - return 0; -} - -static int atmel_get_scan(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->data; - struct atmel_private *priv = netdev_priv(dev); - int i; - char *current_ev = extra; - struct iw_event iwe; - - if (priv->site_survey_state != SITE_SURVEY_COMPLETED) - return -EAGAIN; - - for (i = 0; i < priv->BSS_list_entries; i++) { - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, priv->BSSinfo[i].BSSID, ETH_ALEN); - current_ev = iwe_stream_add_event(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, IW_EV_ADDR_LEN); - - iwe.u.data.length = priv->BSSinfo[i].SSIDsize; - if (iwe.u.data.length > 32) - iwe.u.data.length = 32; - iwe.cmd = SIOCGIWESSID; - iwe.u.data.flags = 1; - current_ev = iwe_stream_add_point(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, priv->BSSinfo[i].SSID); - - iwe.cmd = SIOCGIWMODE; - iwe.u.mode = priv->BSSinfo[i].BSStype; - current_ev = iwe_stream_add_event(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, IW_EV_UINT_LEN); - - iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = priv->BSSinfo[i].channel; - iwe.u.freq.e = 0; - current_ev = iwe_stream_add_event(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, IW_EV_FREQ_LEN); - - /* Add quality statistics */ - iwe.cmd = IWEVQUAL; - iwe.u.qual.level = priv->BSSinfo[i].RSSI; - iwe.u.qual.qual = iwe.u.qual.level; - /* iwe.u.qual.noise = SOMETHING */ - current_ev = iwe_stream_add_event(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, IW_EV_QUAL_LEN); - - - iwe.cmd = SIOCGIWENCODE; - if (priv->BSSinfo[i].UsingWEP) - iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - iwe.u.data.length = 0; - current_ev = iwe_stream_add_point(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, NULL); - } - - /* Length of data */ - dwrq->length = (current_ev - extra); - dwrq->flags = 0; - - return 0; -} - -static int atmel_get_range(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->data; - struct atmel_private *priv = netdev_priv(dev); - struct iw_range *range = (struct iw_range *) extra; - int k, i, j; - - dwrq->length = sizeof(struct iw_range); - memset(range, 0, sizeof(struct iw_range)); - range->min_nwid = 0x0000; - range->max_nwid = 0x0000; - range->num_channels = 0; - for (j = 0; j < ARRAY_SIZE(channel_table); j++) - if (priv->reg_domain == channel_table[j].reg_domain) { - range->num_channels = channel_table[j].max - channel_table[j].min + 1; - break; - } - if (range->num_channels != 0) { - for (k = 0, i = channel_table[j].min; i <= channel_table[j].max; i++) { - range->freq[k].i = i; /* List index */ - - /* Values in MHz -> * 10^5 * 10 */ - range->freq[k].m = 100000 * - ieee80211_channel_to_frequency(i, NL80211_BAND_2GHZ); - range->freq[k++].e = 1; - } - range->num_frequency = k; - } - - range->max_qual.qual = 100; - range->max_qual.level = 100; - range->max_qual.noise = 0; - range->max_qual.updated = IW_QUAL_NOISE_INVALID; - - range->avg_qual.qual = 50; - range->avg_qual.level = 50; - range->avg_qual.noise = 0; - range->avg_qual.updated = IW_QUAL_NOISE_INVALID; - - range->sensitivity = 0; - - range->bitrate[0] = 1000000; - range->bitrate[1] = 2000000; - range->bitrate[2] = 5500000; - range->bitrate[3] = 11000000; - range->num_bitrates = 4; - - range->min_rts = 0; - range->max_rts = 2347; - range->min_frag = 256; - range->max_frag = 2346; - - range->encoding_size[0] = 5; - range->encoding_size[1] = 13; - range->num_encoding_sizes = 2; - range->max_encoding_tokens = 4; - - range->pmp_flags = IW_POWER_ON; - range->pmt_flags = IW_POWER_ON; - range->pm_capa = 0; - - range->we_version_source = WIRELESS_EXT; - range->we_version_compiled = WIRELESS_EXT; - range->retry_capa = IW_RETRY_LIMIT ; - range->retry_flags = IW_RETRY_LIMIT; - range->r_time_flags = 0; - range->min_retry = 1; - range->max_retry = 65535; - - return 0; -} - -static int atmel_set_wap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct sockaddr *awrq = &wrqu->ap_addr; - struct atmel_private *priv = netdev_priv(dev); - int i; - static const u8 any[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; - static const u8 off[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - unsigned long flags; - - if (awrq->sa_family != ARPHRD_ETHER) - return -EINVAL; - - if (!memcmp(any, awrq->sa_data, 6) || - !memcmp(off, awrq->sa_data, 6)) { - del_timer_sync(&priv->management_timer); - spin_lock_irqsave(&priv->irqlock, flags); - atmel_scan(priv, 1); - spin_unlock_irqrestore(&priv->irqlock, flags); - return 0; - } - - for (i = 0; i < priv->BSS_list_entries; i++) { - if (memcmp(priv->BSSinfo[i].BSSID, awrq->sa_data, 6) == 0) { - if (!priv->wep_is_on && priv->BSSinfo[i].UsingWEP) { - return -EINVAL; - } else if (priv->wep_is_on && !priv->BSSinfo[i].UsingWEP) { - return -EINVAL; - } else { - del_timer_sync(&priv->management_timer); - spin_lock_irqsave(&priv->irqlock, flags); - atmel_join_bss(priv, i); - spin_unlock_irqrestore(&priv->irqlock, flags); - return 0; - } - } - } - - return -EINVAL; -} - -static int atmel_config_commit(struct net_device *dev, - struct iw_request_info *info, /* NULL */ - union iwreq_data *zwrq, /* NULL */ - char *extra) /* NULL */ -{ - return atmel_open(dev); -} - -static const iw_handler atmel_handler[] = -{ - IW_HANDLER(SIOCSIWCOMMIT, atmel_config_commit), - IW_HANDLER(SIOCGIWNAME, atmel_get_name), - IW_HANDLER(SIOCSIWFREQ, atmel_set_freq), - IW_HANDLER(SIOCGIWFREQ, atmel_get_freq), - IW_HANDLER(SIOCSIWMODE, atmel_set_mode), - IW_HANDLER(SIOCGIWMODE, atmel_get_mode), - IW_HANDLER(SIOCGIWRANGE, atmel_get_range), - IW_HANDLER(SIOCSIWAP, atmel_set_wap), - IW_HANDLER(SIOCGIWAP, atmel_get_wap), - IW_HANDLER(SIOCSIWSCAN, atmel_set_scan), - IW_HANDLER(SIOCGIWSCAN, atmel_get_scan), - IW_HANDLER(SIOCSIWESSID, atmel_set_essid), - IW_HANDLER(SIOCGIWESSID, atmel_get_essid), - IW_HANDLER(SIOCSIWRATE, atmel_set_rate), - IW_HANDLER(SIOCGIWRATE, atmel_get_rate), - IW_HANDLER(SIOCSIWRTS, atmel_set_rts), - IW_HANDLER(SIOCGIWRTS, atmel_get_rts), - IW_HANDLER(SIOCSIWFRAG, atmel_set_frag), - IW_HANDLER(SIOCGIWFRAG, atmel_get_frag), - IW_HANDLER(SIOCSIWRETRY, atmel_set_retry), - IW_HANDLER(SIOCGIWRETRY, atmel_get_retry), - IW_HANDLER(SIOCSIWENCODE, atmel_set_encode), - IW_HANDLER(SIOCGIWENCODE, atmel_get_encode), - IW_HANDLER(SIOCSIWPOWER, atmel_set_power), - IW_HANDLER(SIOCGIWPOWER, atmel_get_power), - IW_HANDLER(SIOCSIWAUTH, atmel_set_auth), - IW_HANDLER(SIOCGIWAUTH, atmel_get_auth), - IW_HANDLER(SIOCSIWENCODEEXT, atmel_set_encodeext), - IW_HANDLER(SIOCGIWENCODEEXT, atmel_get_encodeext), -}; - -static const iw_handler atmel_private_handler[] = -{ - NULL, /* SIOCIWFIRSTPRIV */ -}; - -struct atmel_priv_ioctl { - char id[32]; - unsigned char __user *data; - unsigned short len; -}; - -#define ATMELFWL SIOCIWFIRSTPRIV -#define ATMELIDIFC ATMELFWL + 1 -#define ATMELRD ATMELFWL + 2 -#define ATMELMAGIC 0x51807 -#define REGDOMAINSZ 20 - -static const struct iw_priv_args atmel_private_args[] = { - { - .cmd = ATMELFWL, - .set_args = IW_PRIV_TYPE_BYTE - | IW_PRIV_SIZE_FIXED - | sizeof(struct atmel_priv_ioctl), - .get_args = IW_PRIV_TYPE_NONE, - .name = "atmelfwl" - }, { - .cmd = ATMELIDIFC, - .set_args = IW_PRIV_TYPE_NONE, - .get_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - .name = "atmelidifc" - }, { - .cmd = ATMELRD, - .set_args = IW_PRIV_TYPE_CHAR | REGDOMAINSZ, - .get_args = IW_PRIV_TYPE_NONE, - .name = "regdomain" - }, -}; - -static const struct iw_handler_def atmel_handler_def = { - .num_standard = ARRAY_SIZE(atmel_handler), - .num_private = ARRAY_SIZE(atmel_private_handler), - .num_private_args = ARRAY_SIZE(atmel_private_args), - .standard = atmel_handler, - .private = atmel_private_handler, - .private_args = (struct iw_priv_args *) atmel_private_args, - .get_wireless_stats = atmel_get_wireless_stats -}; - -struct auth_body { - __le16 alg; - __le16 trans_seq; - __le16 status; - u8 el_id; - u8 chall_text_len; - u8 chall_text[253]; -}; - -static void atmel_enter_state(struct atmel_private *priv, int new_state) -{ - int old_state = priv->station_state; - - if (new_state == old_state) - return; - - priv->station_state = new_state; - - if (new_state == STATION_STATE_READY) { - netif_start_queue(priv->dev); - netif_carrier_on(priv->dev); - } - - if (old_state == STATION_STATE_READY) { - netif_carrier_off(priv->dev); - if (netif_running(priv->dev)) - netif_stop_queue(priv->dev); - priv->last_beacon_timestamp = 0; - } -} - -static void atmel_scan(struct atmel_private *priv, int specific_ssid) -{ - struct { - u8 BSSID[ETH_ALEN]; - u8 SSID[MAX_SSID_LENGTH]; - u8 scan_type; - u8 channel; - __le16 BSS_type; - __le16 min_channel_time; - __le16 max_channel_time; - u8 options; - u8 SSID_size; - } cmd; - - eth_broadcast_addr(cmd.BSSID); - - if (priv->fast_scan) { - cmd.SSID_size = priv->SSID_size; - memcpy(cmd.SSID, priv->SSID, priv->SSID_size); - cmd.min_channel_time = cpu_to_le16(10); - cmd.max_channel_time = cpu_to_le16(50); - } else { - priv->BSS_list_entries = 0; - cmd.SSID_size = 0; - cmd.min_channel_time = cpu_to_le16(10); - cmd.max_channel_time = cpu_to_le16(120); - } - - cmd.options = 0; - - if (!specific_ssid) - cmd.options |= SCAN_OPTIONS_SITE_SURVEY; - - cmd.channel = (priv->channel & 0x7f); - cmd.scan_type = SCAN_TYPE_ACTIVE; - cmd.BSS_type = cpu_to_le16(priv->operating_mode == IW_MODE_ADHOC ? - BSS_TYPE_AD_HOC : BSS_TYPE_INFRASTRUCTURE); - - atmel_send_command(priv, CMD_Scan, &cmd, sizeof(cmd)); - - /* This must come after all hardware access to avoid being messed up - by stuff happening in interrupt context after we leave STATE_DOWN */ - atmel_enter_state(priv, STATION_STATE_SCANNING); -} - -static void join(struct atmel_private *priv, int type) -{ - struct { - u8 BSSID[6]; - u8 SSID[MAX_SSID_LENGTH]; - u8 BSS_type; /* this is a short in a scan command - weird */ - u8 channel; - __le16 timeout; - u8 SSID_size; - u8 reserved; - } cmd; - - cmd.SSID_size = priv->SSID_size; - memcpy(cmd.SSID, priv->SSID, priv->SSID_size); - memcpy(cmd.BSSID, priv->CurrentBSSID, ETH_ALEN); - cmd.channel = (priv->channel & 0x7f); - cmd.BSS_type = type; - cmd.timeout = cpu_to_le16(2000); - - atmel_send_command(priv, CMD_Join, &cmd, sizeof(cmd)); -} - -static void start(struct atmel_private *priv, int type) -{ - struct { - u8 BSSID[6]; - u8 SSID[MAX_SSID_LENGTH]; - u8 BSS_type; - u8 channel; - u8 SSID_size; - u8 reserved[3]; - } cmd; - - cmd.SSID_size = priv->SSID_size; - memcpy(cmd.SSID, priv->SSID, priv->SSID_size); - memcpy(cmd.BSSID, priv->BSSID, ETH_ALEN); - cmd.BSS_type = type; - cmd.channel = (priv->channel & 0x7f); - - atmel_send_command(priv, CMD_Start, &cmd, sizeof(cmd)); -} - -static void handle_beacon_probe(struct atmel_private *priv, u16 capability, - u8 channel) -{ - int rejoin = 0; - int new = capability & WLAN_CAPABILITY_SHORT_PREAMBLE ? - SHORT_PREAMBLE : LONG_PREAMBLE; - - if (priv->preamble != new) { - priv->preamble = new; - rejoin = 1; - atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_PREAMBLE_TYPE, new); - } - - if (priv->channel != channel) { - priv->channel = channel; - rejoin = 1; - atmel_set_mib8(priv, Phy_Mib_Type, PHY_MIB_CHANNEL_POS, channel); - } - - if (rejoin) { - priv->station_is_associated = 0; - atmel_enter_state(priv, STATION_STATE_JOINNING); - - if (priv->operating_mode == IW_MODE_INFRA) - join(priv, BSS_TYPE_INFRASTRUCTURE); - else - join(priv, BSS_TYPE_AD_HOC); - } -} - -static void send_authentication_request(struct atmel_private *priv, u16 system, - u8 *challenge, int challenge_len) -{ - struct ieee80211_hdr header; - struct auth_body auth; - - header.frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH); - header.duration_id = cpu_to_le16(0x8000); - header.seq_ctrl = 0; - memcpy(header.addr1, priv->CurrentBSSID, ETH_ALEN); - memcpy(header.addr2, priv->dev->dev_addr, ETH_ALEN); - memcpy(header.addr3, priv->CurrentBSSID, ETH_ALEN); - - if (priv->wep_is_on && priv->CurrentAuthentTransactionSeqNum != 1) - /* no WEP for authentication frames with TrSeqNo 1 */ - header.frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); - - auth.alg = cpu_to_le16(system); - - auth.status = 0; - auth.trans_seq = cpu_to_le16(priv->CurrentAuthentTransactionSeqNum); - priv->ExpectedAuthentTransactionSeqNum = priv->CurrentAuthentTransactionSeqNum+1; - priv->CurrentAuthentTransactionSeqNum += 2; - - if (challenge_len != 0) { - auth.el_id = 16; /* challenge_text */ - auth.chall_text_len = challenge_len; - memcpy(auth.chall_text, challenge, challenge_len); - atmel_transmit_management_frame(priv, &header, (u8 *)&auth, 8 + challenge_len); - } else { - atmel_transmit_management_frame(priv, &header, (u8 *)&auth, 6); - } -} - -static void send_association_request(struct atmel_private *priv, int is_reassoc) -{ - u8 *ssid_el_p; - int bodysize; - struct ieee80211_hdr header; - struct ass_req_format { - __le16 capability; - __le16 listen_interval; - u8 ap[ETH_ALEN]; /* nothing after here directly accessible */ - u8 ssid_el_id; - u8 ssid_len; - u8 ssid[MAX_SSID_LENGTH]; - u8 sup_rates_el_id; - u8 sup_rates_len; - u8 rates[4]; - } body; - - header.frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | - (is_reassoc ? IEEE80211_STYPE_REASSOC_REQ : IEEE80211_STYPE_ASSOC_REQ)); - header.duration_id = cpu_to_le16(0x8000); - header.seq_ctrl = 0; - - memcpy(header.addr1, priv->CurrentBSSID, ETH_ALEN); - memcpy(header.addr2, priv->dev->dev_addr, ETH_ALEN); - memcpy(header.addr3, priv->CurrentBSSID, ETH_ALEN); - - body.capability = cpu_to_le16(WLAN_CAPABILITY_ESS); - if (priv->wep_is_on) - body.capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); - if (priv->preamble == SHORT_PREAMBLE) - body.capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE); - - body.listen_interval = cpu_to_le16(priv->listen_interval * priv->beacon_period); - - /* current AP address - only in reassoc frame */ - if (is_reassoc) { - memcpy(body.ap, priv->CurrentBSSID, ETH_ALEN); - ssid_el_p = &body.ssid_el_id; - bodysize = 18 + priv->SSID_size; - } else { - ssid_el_p = &body.ap[0]; - bodysize = 12 + priv->SSID_size; - } - - ssid_el_p[0] = WLAN_EID_SSID; - ssid_el_p[1] = priv->SSID_size; - memcpy(ssid_el_p + 2, priv->SSID, priv->SSID_size); - ssid_el_p[2 + priv->SSID_size] = WLAN_EID_SUPP_RATES; - ssid_el_p[3 + priv->SSID_size] = 4; /* len of supported rates */ - memcpy(ssid_el_p + 4 + priv->SSID_size, atmel_basic_rates, 4); - - atmel_transmit_management_frame(priv, &header, (void *)&body, bodysize); -} - -static int is_frame_from_current_bss(struct atmel_private *priv, - struct ieee80211_hdr *header) -{ - if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS) - return memcmp(header->addr3, priv->CurrentBSSID, 6) == 0; - else - return memcmp(header->addr2, priv->CurrentBSSID, 6) == 0; -} - -static int retrieve_bss(struct atmel_private *priv) -{ - int i; - int max_rssi = -128; - int max_index = -1; - - if (priv->BSS_list_entries == 0) - return -1; - - if (priv->connect_to_any_BSS) { - /* Select a BSS with the max-RSSI but of the same type and of - the same WEP mode and that it is not marked as 'bad' (i.e. - we had previously failed to connect to this BSS with the - settings that we currently use) */ - priv->current_BSS = 0; - for (i = 0; i < priv->BSS_list_entries; i++) { - if (priv->operating_mode == priv->BSSinfo[i].BSStype && - ((!priv->wep_is_on && !priv->BSSinfo[i].UsingWEP) || - (priv->wep_is_on && priv->BSSinfo[i].UsingWEP)) && - !(priv->BSSinfo[i].channel & 0x80)) { - max_rssi = priv->BSSinfo[i].RSSI; - priv->current_BSS = max_index = i; - } - } - return max_index; - } - - for (i = 0; i < priv->BSS_list_entries; i++) { - if (priv->SSID_size == priv->BSSinfo[i].SSIDsize && - memcmp(priv->SSID, priv->BSSinfo[i].SSID, priv->SSID_size) == 0 && - priv->operating_mode == priv->BSSinfo[i].BSStype && - atmel_validate_channel(priv, priv->BSSinfo[i].channel) == 0) { - if (priv->BSSinfo[i].RSSI >= max_rssi) { - max_rssi = priv->BSSinfo[i].RSSI; - max_index = i; - } - } - } - return max_index; -} - -static void store_bss_info(struct atmel_private *priv, - struct ieee80211_hdr *header, u16 capability, - u16 beacon_period, u8 channel, u8 rssi, u8 ssid_len, - u8 *ssid, int is_beacon) -{ - u8 *bss = capability & WLAN_CAPABILITY_ESS ? header->addr2 : header->addr3; - int i, index; - - for (index = -1, i = 0; i < priv->BSS_list_entries; i++) - if (memcmp(bss, priv->BSSinfo[i].BSSID, ETH_ALEN) == 0) - index = i; - - /* If we process a probe and an entry from this BSS exists - we will update the BSS entry with the info from this BSS. - If we process a beacon we will only update RSSI */ - - if (index == -1) { - if (priv->BSS_list_entries == MAX_BSS_ENTRIES) - return; - index = priv->BSS_list_entries++; - memcpy(priv->BSSinfo[index].BSSID, bss, ETH_ALEN); - priv->BSSinfo[index].RSSI = rssi; - } else { - if (rssi > priv->BSSinfo[index].RSSI) - priv->BSSinfo[index].RSSI = rssi; - if (is_beacon) - return; - } - - priv->BSSinfo[index].channel = channel; - priv->BSSinfo[index].beacon_period = beacon_period; - priv->BSSinfo[index].UsingWEP = capability & WLAN_CAPABILITY_PRIVACY; - memcpy(priv->BSSinfo[index].SSID, ssid, ssid_len); - priv->BSSinfo[index].SSIDsize = ssid_len; - - if (capability & WLAN_CAPABILITY_IBSS) - priv->BSSinfo[index].BSStype = IW_MODE_ADHOC; - else if (capability & WLAN_CAPABILITY_ESS) - priv->BSSinfo[index].BSStype = IW_MODE_INFRA; - - priv->BSSinfo[index].preamble = capability & WLAN_CAPABILITY_SHORT_PREAMBLE ? - SHORT_PREAMBLE : LONG_PREAMBLE; -} - -static void authenticate(struct atmel_private *priv, u16 frame_len) -{ - struct auth_body *auth = (struct auth_body *)priv->rx_buf; - u16 status = le16_to_cpu(auth->status); - u16 trans_seq_no = le16_to_cpu(auth->trans_seq); - u16 system = le16_to_cpu(auth->alg); - - if (status == WLAN_STATUS_SUCCESS && !priv->wep_is_on) { - /* no WEP */ - if (priv->station_was_associated) { - atmel_enter_state(priv, STATION_STATE_REASSOCIATING); - send_association_request(priv, 1); - return; - } else { - atmel_enter_state(priv, STATION_STATE_ASSOCIATING); - send_association_request(priv, 0); - return; - } - } - - if (status == WLAN_STATUS_SUCCESS && priv->wep_is_on) { - int should_associate = 0; - /* WEP */ - if (trans_seq_no != priv->ExpectedAuthentTransactionSeqNum) - return; - - if (system == WLAN_AUTH_OPEN) { - if (trans_seq_no == 0x0002) { - should_associate = 1; - } - } else if (system == WLAN_AUTH_SHARED_KEY) { - if (trans_seq_no == 0x0002 && - auth->el_id == WLAN_EID_CHALLENGE) { - send_authentication_request(priv, system, auth->chall_text, auth->chall_text_len); - return; - } else if (trans_seq_no == 0x0004) { - should_associate = 1; - } - } - - if (should_associate) { - if (priv->station_was_associated) { - atmel_enter_state(priv, STATION_STATE_REASSOCIATING); - send_association_request(priv, 1); - return; - } else { - atmel_enter_state(priv, STATION_STATE_ASSOCIATING); - send_association_request(priv, 0); - return; - } - } - } - - if (status == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) { - /* Flip back and forth between WEP auth modes until the max - * authentication tries has been exceeded. - */ - if (system == WLAN_AUTH_OPEN) { - priv->CurrentAuthentTransactionSeqNum = 0x001; - priv->exclude_unencrypted = 1; - send_authentication_request(priv, WLAN_AUTH_SHARED_KEY, NULL, 0); - return; - } else if (system == WLAN_AUTH_SHARED_KEY - && priv->wep_is_on) { - priv->CurrentAuthentTransactionSeqNum = 0x001; - priv->exclude_unencrypted = 0; - send_authentication_request(priv, WLAN_AUTH_OPEN, NULL, 0); - return; - } else if (priv->connect_to_any_BSS) { - int bss_index; - - priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80; - - if ((bss_index = retrieve_bss(priv)) != -1) { - atmel_join_bss(priv, bss_index); - return; - } - } - } - - priv->AuthenticationRequestRetryCnt = 0; - atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); - priv->station_is_associated = 0; -} - -static void associate(struct atmel_private *priv, u16 frame_len, u16 subtype) -{ - struct ass_resp_format { - __le16 capability; - __le16 status; - __le16 ass_id; - u8 el_id; - u8 length; - u8 rates[4]; - } *ass_resp = (struct ass_resp_format *)priv->rx_buf; - - u16 status = le16_to_cpu(ass_resp->status); - u16 ass_id = le16_to_cpu(ass_resp->ass_id); - u16 rates_len = ass_resp->length > 4 ? 4 : ass_resp->length; - - union iwreq_data wrqu; - - if (frame_len < 8 + rates_len) - return; - - if (status == WLAN_STATUS_SUCCESS) { - if (subtype == IEEE80211_STYPE_ASSOC_RESP) - priv->AssociationRequestRetryCnt = 0; - else - priv->ReAssociationRequestRetryCnt = 0; - - atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, - MAC_MGMT_MIB_STATION_ID_POS, ass_id & 0x3fff); - atmel_set_mib(priv, Phy_Mib_Type, - PHY_MIB_RATE_SET_POS, ass_resp->rates, rates_len); - if (priv->power_mode == 0) { - priv->listen_interval = 1; - atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, - MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE); - atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, - MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1); - } else { - priv->listen_interval = 2; - atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, - MAC_MGMT_MIB_PS_MODE_POS, PS_MODE); - atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, - MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 2); - } - - priv->station_is_associated = 1; - priv->station_was_associated = 1; - atmel_enter_state(priv, STATION_STATE_READY); - - /* Send association event to userspace */ - wrqu.data.length = 0; - wrqu.data.flags = 0; - memcpy(wrqu.ap_addr.sa_data, priv->CurrentBSSID, ETH_ALEN); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); - - return; - } - - if (subtype == IEEE80211_STYPE_ASSOC_RESP && - status != WLAN_STATUS_ASSOC_DENIED_RATES && - status != WLAN_STATUS_CAPS_UNSUPPORTED && - priv->AssociationRequestRetryCnt < MAX_ASSOCIATION_RETRIES) { - mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); - priv->AssociationRequestRetryCnt++; - send_association_request(priv, 0); - return; - } - - if (subtype == IEEE80211_STYPE_REASSOC_RESP && - status != WLAN_STATUS_ASSOC_DENIED_RATES && - status != WLAN_STATUS_CAPS_UNSUPPORTED && - priv->ReAssociationRequestRetryCnt < MAX_ASSOCIATION_RETRIES) { - mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); - priv->ReAssociationRequestRetryCnt++; - send_association_request(priv, 1); - return; - } - - atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); - priv->station_is_associated = 0; - - if (priv->connect_to_any_BSS) { - int bss_index; - priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80; - - if ((bss_index = retrieve_bss(priv)) != -1) - atmel_join_bss(priv, bss_index); - } -} - -static void atmel_join_bss(struct atmel_private *priv, int bss_index) -{ - struct bss_info *bss = &priv->BSSinfo[bss_index]; - - memcpy(priv->CurrentBSSID, bss->BSSID, ETH_ALEN); - memcpy(priv->SSID, bss->SSID, priv->SSID_size = bss->SSIDsize); - - /* The WPA stuff cares about the current AP address */ - if (priv->use_wpa) - build_wpa_mib(priv); - - /* When switching to AdHoc turn OFF Power Save if needed */ - - if (bss->BSStype == IW_MODE_ADHOC && - priv->operating_mode != IW_MODE_ADHOC && - priv->power_mode) { - priv->power_mode = 0; - priv->listen_interval = 1; - atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, - MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE); - atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, - MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1); - } - - priv->operating_mode = bss->BSStype; - priv->channel = bss->channel & 0x7f; - priv->beacon_period = bss->beacon_period; - - if (priv->preamble != bss->preamble) { - priv->preamble = bss->preamble; - atmel_set_mib8(priv, Local_Mib_Type, - LOCAL_MIB_PREAMBLE_TYPE, bss->preamble); - } - - if (!priv->wep_is_on && bss->UsingWEP) { - atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); - priv->station_is_associated = 0; - return; - } - - if (priv->wep_is_on && !bss->UsingWEP) { - atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); - priv->station_is_associated = 0; - return; - } - - atmel_enter_state(priv, STATION_STATE_JOINNING); - - if (priv->operating_mode == IW_MODE_INFRA) - join(priv, BSS_TYPE_INFRASTRUCTURE); - else - join(priv, BSS_TYPE_AD_HOC); -} - -static void restart_search(struct atmel_private *priv) -{ - int bss_index; - - if (!priv->connect_to_any_BSS) { - atmel_scan(priv, 1); - } else { - priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80; - - if ((bss_index = retrieve_bss(priv)) != -1) - atmel_join_bss(priv, bss_index); - else - atmel_scan(priv, 0); - } -} - -static void smooth_rssi(struct atmel_private *priv, u8 rssi) -{ - u8 old = priv->wstats.qual.level; - u8 max_rssi = 42; /* 502-rmfd-revd max by experiment, default for now */ - - switch (priv->firmware_type) { - case ATMEL_FW_TYPE_502E: - max_rssi = 63; /* 502-rmfd-reve max by experiment */ - break; - default: - break; - } - - rssi = rssi * 100 / max_rssi; - if ((rssi + old) % 2) - priv->wstats.qual.level = (rssi + old) / 2 + 1; - else - priv->wstats.qual.level = (rssi + old) / 2; - priv->wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED; - priv->wstats.qual.updated &= ~IW_QUAL_LEVEL_INVALID; -} - -static void atmel_smooth_qual(struct atmel_private *priv) -{ - unsigned long time_diff = (jiffies - priv->last_qual) / HZ; - while (time_diff--) { - priv->last_qual += HZ; - priv->wstats.qual.qual = priv->wstats.qual.qual / 2; - priv->wstats.qual.qual += - priv->beacons_this_sec * priv->beacon_period * (priv->wstats.qual.level + 100) / 4000; - priv->beacons_this_sec = 0; - } - priv->wstats.qual.updated |= IW_QUAL_QUAL_UPDATED; - priv->wstats.qual.updated &= ~IW_QUAL_QUAL_INVALID; -} - -/* deals with incoming management frames. */ -static void atmel_management_frame(struct atmel_private *priv, - struct ieee80211_hdr *header, - u16 frame_len, u8 rssi) -{ - u16 subtype; - - subtype = le16_to_cpu(header->frame_control) & IEEE80211_FCTL_STYPE; - switch (subtype) { - case IEEE80211_STYPE_BEACON: - case IEEE80211_STYPE_PROBE_RESP: - - /* beacon frame has multiple variable-length fields - - never let an engineer loose with a data structure design. */ - { - struct beacon_format { - __le64 timestamp; - __le16 interval; - __le16 capability; - u8 ssid_el_id; - u8 ssid_length; - /* ssid here */ - u8 rates_el_id; - u8 rates_length; - /* rates here */ - u8 ds_el_id; - u8 ds_length; - /* ds here */ - } *beacon = (struct beacon_format *)priv->rx_buf; - - u8 channel, rates_length, ssid_length; - u64 timestamp = le64_to_cpu(beacon->timestamp); - u16 beacon_interval = le16_to_cpu(beacon->interval); - u16 capability = le16_to_cpu(beacon->capability); - u8 *beaconp = priv->rx_buf; - ssid_length = beacon->ssid_length; - /* this blows chunks. */ - if (frame_len < 14 || frame_len < ssid_length + 15) - return; - rates_length = beaconp[beacon->ssid_length + 15]; - if (frame_len < ssid_length + rates_length + 18) - return; - if (ssid_length > MAX_SSID_LENGTH) - return; - channel = beaconp[ssid_length + rates_length + 18]; - - if (priv->station_state == STATION_STATE_READY) { - smooth_rssi(priv, rssi); - if (is_frame_from_current_bss(priv, header)) { - priv->beacons_this_sec++; - atmel_smooth_qual(priv); - if (priv->last_beacon_timestamp) { - /* Note truncate this to 32 bits - kernel can't divide a long */ - u32 beacon_delay = timestamp - priv->last_beacon_timestamp; - int beacons = beacon_delay / (beacon_interval * 1000); - if (beacons > 1) - priv->wstats.miss.beacon += beacons - 1; - } - priv->last_beacon_timestamp = timestamp; - handle_beacon_probe(priv, capability, channel); - } - } - - if (priv->station_state == STATION_STATE_SCANNING) - store_bss_info(priv, header, capability, - beacon_interval, channel, rssi, - ssid_length, - &beacon->rates_el_id, - subtype == IEEE80211_STYPE_BEACON); - } - break; - - case IEEE80211_STYPE_AUTH: - - if (priv->station_state == STATION_STATE_AUTHENTICATING) - authenticate(priv, frame_len); - - break; - - case IEEE80211_STYPE_ASSOC_RESP: - case IEEE80211_STYPE_REASSOC_RESP: - - if (priv->station_state == STATION_STATE_ASSOCIATING || - priv->station_state == STATION_STATE_REASSOCIATING) - associate(priv, frame_len, subtype); - - break; - - case IEEE80211_STYPE_DISASSOC: - if (priv->station_is_associated && - priv->operating_mode == IW_MODE_INFRA && - is_frame_from_current_bss(priv, header)) { - priv->station_was_associated = 0; - priv->station_is_associated = 0; - - atmel_enter_state(priv, STATION_STATE_JOINNING); - join(priv, BSS_TYPE_INFRASTRUCTURE); - } - - break; - - case IEEE80211_STYPE_DEAUTH: - if (priv->operating_mode == IW_MODE_INFRA && - is_frame_from_current_bss(priv, header)) { - priv->station_was_associated = 0; - - atmel_enter_state(priv, STATION_STATE_JOINNING); - join(priv, BSS_TYPE_INFRASTRUCTURE); - } - - break; - } -} - -/* run when timer expires */ -static void atmel_management_timer(struct timer_list *t) -{ - struct atmel_private *priv = from_timer(priv, t, management_timer); - unsigned long flags; - - /* Check if the card has been yanked. */ - if (priv->card && priv->present_callback && - !(*priv->present_callback)(priv->card)) - return; - - spin_lock_irqsave(&priv->irqlock, flags); - - switch (priv->station_state) { - - case STATION_STATE_AUTHENTICATING: - if (priv->AuthenticationRequestRetryCnt >= MAX_AUTHENTICATION_RETRIES) { - atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); - priv->station_is_associated = 0; - priv->AuthenticationRequestRetryCnt = 0; - restart_search(priv); - } else { - int auth = WLAN_AUTH_OPEN; - priv->AuthenticationRequestRetryCnt++; - priv->CurrentAuthentTransactionSeqNum = 0x0001; - mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); - if (priv->wep_is_on && priv->exclude_unencrypted) - auth = WLAN_AUTH_SHARED_KEY; - send_authentication_request(priv, auth, NULL, 0); - } - break; - - case STATION_STATE_ASSOCIATING: - if (priv->AssociationRequestRetryCnt == MAX_ASSOCIATION_RETRIES) { - atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); - priv->station_is_associated = 0; - priv->AssociationRequestRetryCnt = 0; - restart_search(priv); - } else { - priv->AssociationRequestRetryCnt++; - mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); - send_association_request(priv, 0); - } - break; - - case STATION_STATE_REASSOCIATING: - if (priv->ReAssociationRequestRetryCnt == MAX_ASSOCIATION_RETRIES) { - atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); - priv->station_is_associated = 0; - priv->ReAssociationRequestRetryCnt = 0; - restart_search(priv); - } else { - priv->ReAssociationRequestRetryCnt++; - mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); - send_association_request(priv, 1); - } - break; - - default: - break; - } - - spin_unlock_irqrestore(&priv->irqlock, flags); -} - -static void atmel_command_irq(struct atmel_private *priv) -{ - u8 status = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET)); - u8 command = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_COMMAND_OFFSET)); - int fast_scan; - union iwreq_data wrqu; - - if (status == CMD_STATUS_IDLE || - status == CMD_STATUS_IN_PROGRESS) - return; - - switch (command) { - case CMD_Start: - if (status == CMD_STATUS_COMPLETE) { - priv->station_was_associated = priv->station_is_associated; - atmel_get_mib(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_BSSID_POS, - (u8 *)priv->CurrentBSSID, 6); - atmel_enter_state(priv, STATION_STATE_READY); - } - break; - - case CMD_Scan: - fast_scan = priv->fast_scan; - priv->fast_scan = 0; - - if (status != CMD_STATUS_COMPLETE) { - atmel_scan(priv, 1); - } else { - int bss_index = retrieve_bss(priv); - int notify_scan_complete = 1; - if (bss_index != -1) { - atmel_join_bss(priv, bss_index); - } else if (priv->operating_mode == IW_MODE_ADHOC && - priv->SSID_size != 0) { - start(priv, BSS_TYPE_AD_HOC); - } else { - priv->fast_scan = !fast_scan; - atmel_scan(priv, 1); - notify_scan_complete = 0; - } - priv->site_survey_state = SITE_SURVEY_COMPLETED; - if (notify_scan_complete) { - wrqu.data.length = 0; - wrqu.data.flags = 0; - wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL); - } - } - break; - - case CMD_SiteSurvey: - priv->fast_scan = 0; - - if (status != CMD_STATUS_COMPLETE) - return; - - priv->site_survey_state = SITE_SURVEY_COMPLETED; - if (priv->station_is_associated) { - atmel_enter_state(priv, STATION_STATE_READY); - wrqu.data.length = 0; - wrqu.data.flags = 0; - wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL); - } else { - atmel_scan(priv, 1); - } - break; - - case CMD_Join: - if (status == CMD_STATUS_COMPLETE) { - if (priv->operating_mode == IW_MODE_ADHOC) { - priv->station_was_associated = priv->station_is_associated; - atmel_enter_state(priv, STATION_STATE_READY); - } else { - int auth = WLAN_AUTH_OPEN; - priv->AuthenticationRequestRetryCnt = 0; - atmel_enter_state(priv, STATION_STATE_AUTHENTICATING); - - mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); - priv->CurrentAuthentTransactionSeqNum = 0x0001; - if (priv->wep_is_on && priv->exclude_unencrypted) - auth = WLAN_AUTH_SHARED_KEY; - send_authentication_request(priv, auth, NULL, 0); - } - return; - } - - atmel_scan(priv, 1); - } -} - -static int atmel_wakeup_firmware(struct atmel_private *priv) -{ - struct host_info_struct *iface = &priv->host_info; - u16 mr1, mr3; - int i; - - if (priv->card_type == CARD_TYPE_SPI_FLASH) - atmel_set_gcr(priv->dev, GCR_REMAP); - - /* wake up on-board processor */ - atmel_clear_gcr(priv->dev, 0x0040); - atmel_write16(priv->dev, BSR, BSS_SRAM); - - if (priv->card_type == CARD_TYPE_SPI_FLASH) - mdelay(100); - - /* and wait for it */ - for (i = LOOP_RETRY_LIMIT; i; i--) { - mr1 = atmel_read16(priv->dev, MR1); - mr3 = atmel_read16(priv->dev, MR3); - - if (mr3 & MAC_BOOT_COMPLETE) - break; - if (mr1 & MAC_BOOT_COMPLETE && - priv->bus_type == BUS_TYPE_PCCARD) - break; - } - - if (i == 0) { - printk(KERN_ALERT "%s: MAC failed to boot.\n", priv->dev->name); - return -EIO; - } - - if ((priv->host_info_base = atmel_read16(priv->dev, MR2)) == 0xffff) { - printk(KERN_ALERT "%s: card missing.\n", priv->dev->name); - return -ENODEV; - } - - /* now check for completion of MAC initialization through - the FunCtrl field of the IFACE, poll MR1 to detect completion of - MAC initialization, check completion status, set interrupt mask, - enables interrupts and calls Tx and Rx initialization functions */ - - atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET), FUNC_CTRL_INIT_COMPLETE); - - for (i = LOOP_RETRY_LIMIT; i; i--) { - mr1 = atmel_read16(priv->dev, MR1); - mr3 = atmel_read16(priv->dev, MR3); - - if (mr3 & MAC_INIT_COMPLETE) - break; - if (mr1 & MAC_INIT_COMPLETE && - priv->bus_type == BUS_TYPE_PCCARD) - break; - } - - if (i == 0) { - printk(KERN_ALERT "%s: MAC failed to initialise.\n", - priv->dev->name); - return -EIO; - } - - /* Check for MAC_INIT_OK only on the register that the MAC_INIT_OK was set */ - if ((mr3 & MAC_INIT_COMPLETE) && - !(atmel_read16(priv->dev, MR3) & MAC_INIT_OK)) { - printk(KERN_ALERT "%s: MAC failed MR3 self-test.\n", priv->dev->name); - return -EIO; - } - if ((mr1 & MAC_INIT_COMPLETE) && - !(atmel_read16(priv->dev, MR1) & MAC_INIT_OK)) { - printk(KERN_ALERT "%s: MAC failed MR1 self-test.\n", priv->dev->name); - return -EIO; - } - - atmel_copy_to_host(priv->dev, (unsigned char *)iface, - priv->host_info_base, sizeof(*iface)); - - iface->tx_buff_pos = le16_to_cpu(iface->tx_buff_pos); - iface->tx_buff_size = le16_to_cpu(iface->tx_buff_size); - iface->tx_desc_pos = le16_to_cpu(iface->tx_desc_pos); - iface->tx_desc_count = le16_to_cpu(iface->tx_desc_count); - iface->rx_buff_pos = le16_to_cpu(iface->rx_buff_pos); - iface->rx_buff_size = le16_to_cpu(iface->rx_buff_size); - iface->rx_desc_pos = le16_to_cpu(iface->rx_desc_pos); - iface->rx_desc_count = le16_to_cpu(iface->rx_desc_count); - iface->build_version = le16_to_cpu(iface->build_version); - iface->command_pos = le16_to_cpu(iface->command_pos); - iface->major_version = le16_to_cpu(iface->major_version); - iface->minor_version = le16_to_cpu(iface->minor_version); - iface->func_ctrl = le16_to_cpu(iface->func_ctrl); - iface->mac_status = le16_to_cpu(iface->mac_status); - - return 0; -} - -/* determine type of memory and MAC address */ -static int probe_atmel_card(struct net_device *dev) -{ - int rc = 0; - struct atmel_private *priv = netdev_priv(dev); - u8 addr[ETH_ALEN] = {}; - - /* reset pccard */ - if (priv->bus_type == BUS_TYPE_PCCARD) - atmel_write16(dev, GCR, 0x0060); - - atmel_write16(dev, GCR, 0x0040); - msleep(500); - - if (atmel_read16(dev, MR2) == 0) { - /* No stored firmware so load a small stub which just - tells us the MAC address */ - int i; - priv->card_type = CARD_TYPE_EEPROM; - atmel_write16(dev, BSR, BSS_IRAM); - atmel_copy_to_card(dev, 0, mac_reader, sizeof(mac_reader)); - atmel_set_gcr(dev, GCR_REMAP); - atmel_clear_gcr(priv->dev, 0x0040); - atmel_write16(dev, BSR, BSS_SRAM); - for (i = LOOP_RETRY_LIMIT; i; i--) - if (atmel_read16(dev, MR3) & MAC_BOOT_COMPLETE) - break; - if (i == 0) { - printk(KERN_ALERT "%s: MAC failed to boot MAC address reader.\n", dev->name); - } else { - - atmel_copy_to_host(dev, addr, atmel_read16(dev, MR2), 6); - eth_hw_addr_set(dev, addr); - /* got address, now squash it again until the network - interface is opened */ - if (priv->bus_type == BUS_TYPE_PCCARD) - atmel_write16(dev, GCR, 0x0060); - atmel_write16(dev, GCR, 0x0040); - rc = 1; - } - } else if (atmel_read16(dev, MR4) == 0) { - /* Mac address easy in this case. */ - priv->card_type = CARD_TYPE_PARALLEL_FLASH; - atmel_write16(dev, BSR, 1); - atmel_copy_to_host(dev, addr, 0xc000, 6); - eth_hw_addr_set(dev, addr); - atmel_write16(dev, BSR, 0x200); - rc = 1; - } else { - /* Standard firmware in flash, boot it up and ask - for the Mac Address */ - priv->card_type = CARD_TYPE_SPI_FLASH; - if (atmel_wakeup_firmware(priv) == 0) { - atmel_get_mib(priv, Mac_Address_Mib_Type, 0, addr, 6); - eth_hw_addr_set(dev, addr); - - /* got address, now squash it again until the network - interface is opened */ - if (priv->bus_type == BUS_TYPE_PCCARD) - atmel_write16(dev, GCR, 0x0060); - atmel_write16(dev, GCR, 0x0040); - rc = 1; - } - } - - if (rc) { - if (dev->dev_addr[0] == 0xFF) { - static const u8 default_mac[] = { - 0x00, 0x04, 0x25, 0x00, 0x00, 0x00 - }; - printk(KERN_ALERT "%s: *** Invalid MAC address. UPGRADE Firmware ****\n", dev->name); - eth_hw_addr_set(dev, default_mac); - } - } - - return rc; -} - -/* Move the encyption information on the MIB structure. - This routine is for the pre-WPA firmware: later firmware has - a different format MIB and a different routine. */ -static void build_wep_mib(struct atmel_private *priv) -{ - struct { /* NB this is matched to the hardware, don't change. */ - u8 wep_is_on; - u8 default_key; /* 0..3 */ - u8 reserved; - u8 exclude_unencrypted; - - u32 WEPICV_error_count; - u32 WEP_excluded_count; - - u8 wep_keys[MAX_ENCRYPTION_KEYS][13]; - u8 encryption_level; /* 0, 1, 2 */ - u8 reserved2[3]; - } mib; - int i; - - mib.wep_is_on = priv->wep_is_on; - if (priv->wep_is_on) { - if (priv->wep_key_len[priv->default_key] > 5) - mib.encryption_level = 2; - else - mib.encryption_level = 1; - } else { - mib.encryption_level = 0; - } - - mib.default_key = priv->default_key; - mib.exclude_unencrypted = priv->exclude_unencrypted; - - for (i = 0; i < MAX_ENCRYPTION_KEYS; i++) - memcpy(mib.wep_keys[i], priv->wep_keys[i], 13); - - atmel_set_mib(priv, Mac_Wep_Mib_Type, 0, (u8 *)&mib, sizeof(mib)); -} - -static void build_wpa_mib(struct atmel_private *priv) -{ - /* This is for the later (WPA enabled) firmware. */ - - struct { /* NB this is matched to the hardware, don't change. */ - u8 cipher_default_key_value[MAX_ENCRYPTION_KEYS][MAX_ENCRYPTION_KEY_SIZE]; - u8 receiver_address[ETH_ALEN]; - u8 wep_is_on; - u8 default_key; /* 0..3 */ - u8 group_key; - u8 exclude_unencrypted; - u8 encryption_type; - u8 reserved; - - u32 WEPICV_error_count; - u32 WEP_excluded_count; - - u8 key_RSC[4][8]; - } mib; - - int i; - - mib.wep_is_on = priv->wep_is_on; - mib.exclude_unencrypted = priv->exclude_unencrypted; - memcpy(mib.receiver_address, priv->CurrentBSSID, ETH_ALEN); - - /* zero all the keys before adding in valid ones. */ - memset(mib.cipher_default_key_value, 0, sizeof(mib.cipher_default_key_value)); - - if (priv->wep_is_on) { - /* There's a comment in the Atmel code to the effect that this - is only valid when still using WEP, it may need to be set to - something to use WPA */ - memset(mib.key_RSC, 0, sizeof(mib.key_RSC)); - - mib.default_key = mib.group_key = 255; - for (i = 0; i < MAX_ENCRYPTION_KEYS; i++) { - if (priv->wep_key_len[i] > 0) { - memcpy(mib.cipher_default_key_value[i], priv->wep_keys[i], MAX_ENCRYPTION_KEY_SIZE); - if (i == priv->default_key) { - mib.default_key = i; - mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-1] = 7; - mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-2] = priv->pairwise_cipher_suite; - } else { - mib.group_key = i; - priv->group_cipher_suite = priv->pairwise_cipher_suite; - mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-1] = 1; - mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-2] = priv->group_cipher_suite; - } - } - } - if (mib.default_key == 255) - mib.default_key = mib.group_key != 255 ? mib.group_key : 0; - if (mib.group_key == 255) - mib.group_key = mib.default_key; - - } - - atmel_set_mib(priv, Mac_Wep_Mib_Type, 0, (u8 *)&mib, sizeof(mib)); -} - -static int reset_atmel_card(struct net_device *dev) -{ - /* do everything necessary to wake up the hardware, including - waiting for the lightning strike and throwing the knife switch.... - - set all the Mib values which matter in the card to match - their settings in the atmel_private structure. Some of these - can be altered on the fly, but many (WEP, infrastructure or ad-hoc) - can only be changed by tearing down the world and coming back through - here. - - This routine is also responsible for initialising some - hardware-specific fields in the atmel_private structure, - including a copy of the firmware's hostinfo structure - which is the route into the rest of the firmware datastructures. */ - - struct atmel_private *priv = netdev_priv(dev); - u8 configuration; - int old_state = priv->station_state; - int err = 0; - - /* data to add to the firmware names, in priority order - this implemenents firmware versioning */ - - static char *firmware_modifier[] = { - "-wpa", - "", - NULL - }; - - /* reset pccard */ - if (priv->bus_type == BUS_TYPE_PCCARD) - atmel_write16(priv->dev, GCR, 0x0060); - - /* stop card , disable interrupts */ - atmel_write16(priv->dev, GCR, 0x0040); - - if (priv->card_type == CARD_TYPE_EEPROM) { - /* copy in firmware if needed */ - const struct firmware *fw_entry = NULL; - const unsigned char *fw; - int len = priv->firmware_length; - if (!(fw = priv->firmware)) { - if (priv->firmware_type == ATMEL_FW_TYPE_NONE) { - if (strlen(priv->firmware_id) == 0) { - printk(KERN_INFO - "%s: card type is unknown: assuming at76c502 firmware is OK.\n", - dev->name); - printk(KERN_INFO - "%s: if not, use the firmware= module parameter.\n", - dev->name); - strcpy(priv->firmware_id, "atmel_at76c502.bin"); - } - err = request_firmware(&fw_entry, priv->firmware_id, priv->sys_dev); - if (err != 0) { - printk(KERN_ALERT - "%s: firmware %s is missing, cannot continue.\n", - dev->name, priv->firmware_id); - return err; - } - } else { - int fw_index = 0; - int success = 0; - - /* get firmware filename entry based on firmware type ID */ - while (fw_table[fw_index].fw_type != priv->firmware_type - && fw_table[fw_index].fw_type != ATMEL_FW_TYPE_NONE) - fw_index++; - - /* construct the actual firmware file name */ - if (fw_table[fw_index].fw_type != ATMEL_FW_TYPE_NONE) { - int i; - for (i = 0; firmware_modifier[i]; i++) { - snprintf(priv->firmware_id, 32, "%s%s.%s", fw_table[fw_index].fw_file, - firmware_modifier[i], fw_table[fw_index].fw_file_ext); - priv->firmware_id[31] = '\0'; - if (request_firmware(&fw_entry, priv->firmware_id, priv->sys_dev) == 0) { - success = 1; - break; - } - } - } - if (!success) { - printk(KERN_ALERT - "%s: firmware %s is missing, cannot start.\n", - dev->name, priv->firmware_id); - priv->firmware_id[0] = '\0'; - return -ENOENT; - } - } - - fw = fw_entry->data; - len = fw_entry->size; - } - - if (len <= 0x6000) { - atmel_write16(priv->dev, BSR, BSS_IRAM); - atmel_copy_to_card(priv->dev, 0, fw, len); - atmel_set_gcr(priv->dev, GCR_REMAP); - } else { - /* Remap */ - atmel_set_gcr(priv->dev, GCR_REMAP); - atmel_write16(priv->dev, BSR, BSS_IRAM); - atmel_copy_to_card(priv->dev, 0, fw, 0x6000); - atmel_write16(priv->dev, BSR, 0x2ff); - atmel_copy_to_card(priv->dev, 0x8000, &fw[0x6000], len - 0x6000); - } - - release_firmware(fw_entry); - } - - err = atmel_wakeup_firmware(priv); - if (err != 0) - return err; - - /* Check the version and set the correct flag for wpa stuff, - old and new firmware is incompatible. - The pre-wpa 3com firmware reports major version 5, - the wpa 3com firmware is major version 4 and doesn't need - the 3com broken-ness filter. */ - priv->use_wpa = (priv->host_info.major_version == 4); - priv->radio_on_broken = (priv->host_info.major_version == 5); - - /* unmask all irq sources */ - atmel_wmem8(priv, atmel_hi(priv, IFACE_INT_MASK_OFFSET), 0xff); - - /* int Tx system and enable Tx */ - atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, 0), 0); - atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, 0), 0x80000000L); - atmel_wmem16(priv, atmel_tx(priv, TX_DESC_POS_OFFSET, 0), 0); - atmel_wmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, 0), 0); - - priv->tx_desc_free = priv->host_info.tx_desc_count; - priv->tx_desc_head = 0; - priv->tx_desc_tail = 0; - priv->tx_desc_previous = 0; - priv->tx_free_mem = priv->host_info.tx_buff_size; - priv->tx_buff_head = 0; - priv->tx_buff_tail = 0; - - configuration = atmel_rmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET)); - atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET), - configuration | FUNC_CTRL_TxENABLE); - - /* init Rx system and enable */ - priv->rx_desc_head = 0; - - configuration = atmel_rmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET)); - atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET), - configuration | FUNC_CTRL_RxENABLE); - - if (!priv->radio_on_broken) { - if (atmel_send_command_wait(priv, CMD_EnableRadio, NULL, 0) == - CMD_STATUS_REJECTED_RADIO_OFF) { - printk(KERN_INFO "%s: cannot turn the radio on.\n", - dev->name); - return -EIO; - } - } - - /* set up enough MIB values to run. */ - atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_AUTO_TX_RATE_POS, priv->auto_tx_rate); - atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_TX_PROMISCUOUS_POS, PROM_MODE_OFF); - atmel_set_mib16(priv, Mac_Mib_Type, MAC_MIB_RTS_THRESHOLD_POS, priv->rts_threshold); - atmel_set_mib16(priv, Mac_Mib_Type, MAC_MIB_FRAG_THRESHOLD_POS, priv->frag_threshold); - atmel_set_mib8(priv, Mac_Mib_Type, MAC_MIB_SHORT_RETRY_POS, priv->short_retry); - atmel_set_mib8(priv, Mac_Mib_Type, MAC_MIB_LONG_RETRY_POS, priv->long_retry); - atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_PREAMBLE_TYPE, priv->preamble); - atmel_set_mib(priv, Mac_Address_Mib_Type, MAC_ADDR_MIB_MAC_ADDR_POS, - priv->dev->dev_addr, 6); - atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE); - atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1); - atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_BEACON_PER_POS, priv->default_beacon_period); - atmel_set_mib(priv, Phy_Mib_Type, PHY_MIB_RATE_SET_POS, atmel_basic_rates, 4); - atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_PRIVACY_POS, priv->wep_is_on); - if (priv->use_wpa) - build_wpa_mib(priv); - else - build_wep_mib(priv); - - if (old_state == STATION_STATE_READY) { - union iwreq_data wrqu; - - wrqu.data.length = 0; - wrqu.data.flags = 0; - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - eth_zero_addr(wrqu.ap_addr.sa_data); - wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); - } - - return 0; -} - -static void atmel_send_command(struct atmel_private *priv, int command, - void *cmd, int cmd_size) -{ - if (cmd) - atmel_copy_to_card(priv->dev, atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET), - cmd, cmd_size); - - atmel_wmem8(priv, atmel_co(priv, CMD_BLOCK_COMMAND_OFFSET), command); - atmel_wmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET), 0); -} - -static int atmel_send_command_wait(struct atmel_private *priv, int command, - void *cmd, int cmd_size) -{ - int i, status; - - atmel_send_command(priv, command, cmd, cmd_size); - - for (i = 5000; i; i--) { - status = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET)); - if (status != CMD_STATUS_IDLE && - status != CMD_STATUS_IN_PROGRESS) - break; - udelay(20); - } - - if (i == 0) { - printk(KERN_ALERT "%s: failed to contact MAC.\n", priv->dev->name); - status = CMD_STATUS_HOST_ERROR; - } else { - if (command != CMD_EnableRadio) - status = CMD_STATUS_COMPLETE; - } - - return status; -} - -static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index) -{ - struct get_set_mib m; - m.type = type; - m.size = 1; - m.index = index; - - atmel_send_command_wait(priv, CMD_Get_MIB_Vars, &m, MIB_HEADER_SIZE + 1); - return atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET + MIB_HEADER_SIZE)); -} - -static void atmel_set_mib8(struct atmel_private *priv, u8 type, u8 index, u8 data) -{ - struct get_set_mib m; - m.type = type; - m.size = 1; - m.index = index; - m.data[0] = data; - - atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, MIB_HEADER_SIZE + 1); -} - -static void atmel_set_mib16(struct atmel_private *priv, u8 type, u8 index, - u16 data) -{ - struct get_set_mib m; - m.type = type; - m.size = 2; - m.index = index; - m.data[0] = data; - m.data[1] = data >> 8; - - atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, MIB_HEADER_SIZE + 2); -} - -static void atmel_set_mib(struct atmel_private *priv, u8 type, u8 index, - const u8 *data, int data_len) -{ - struct get_set_mib m; - m.type = type; - m.size = data_len; - m.index = index; - - if (data_len > MIB_MAX_DATA_BYTES) - printk(KERN_ALERT "%s: MIB buffer too small.\n", priv->dev->name); - - memcpy(m.data, data, data_len); - atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, MIB_HEADER_SIZE + data_len); -} - -static void atmel_get_mib(struct atmel_private *priv, u8 type, u8 index, - u8 *data, int data_len) -{ - struct get_set_mib m; - m.type = type; - m.size = data_len; - m.index = index; - - if (data_len > MIB_MAX_DATA_BYTES) - printk(KERN_ALERT "%s: MIB buffer too small.\n", priv->dev->name); - - atmel_send_command_wait(priv, CMD_Get_MIB_Vars, &m, MIB_HEADER_SIZE + data_len); - atmel_copy_to_host(priv->dev, data, - atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET + MIB_HEADER_SIZE), data_len); -} - -static void atmel_writeAR(struct net_device *dev, u16 data) -{ - int i; - outw(data, dev->base_addr + AR); - /* Address register appears to need some convincing..... */ - for (i = 0; data != inw(dev->base_addr + AR) && i < 10; i++) - outw(data, dev->base_addr + AR); -} - -static void atmel_copy_to_card(struct net_device *dev, u16 dest, - const unsigned char *src, u16 len) -{ - int i; - atmel_writeAR(dev, dest); - if (dest % 2) { - atmel_write8(dev, DR, *src); - src++; len--; - } - for (i = len; i > 1 ; i -= 2) { - u8 lb = *src++; - u8 hb = *src++; - atmel_write16(dev, DR, lb | (hb << 8)); - } - if (i) - atmel_write8(dev, DR, *src); -} - -static void atmel_copy_to_host(struct net_device *dev, unsigned char *dest, - u16 src, u16 len) -{ - int i; - atmel_writeAR(dev, src); - if (src % 2) { - *dest = atmel_read8(dev, DR); - dest++; len--; - } - for (i = len; i > 1 ; i -= 2) { - u16 hw = atmel_read16(dev, DR); - *dest++ = hw; - *dest++ = hw >> 8; - } - if (i) - *dest = atmel_read8(dev, DR); -} - -static void atmel_set_gcr(struct net_device *dev, u16 mask) -{ - outw(inw(dev->base_addr + GCR) | mask, dev->base_addr + GCR); -} - -static void atmel_clear_gcr(struct net_device *dev, u16 mask) -{ - outw(inw(dev->base_addr + GCR) & ~mask, dev->base_addr + GCR); -} - -static int atmel_lock_mac(struct atmel_private *priv) -{ - int i, j = 20; - retry: - for (i = 5000; i; i--) { - if (!atmel_rmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_HOST_OFFSET))) - break; - udelay(20); - } - - if (!i) - return 0; /* timed out */ - - atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 1); - if (atmel_rmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_HOST_OFFSET))) { - atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); - if (!j--) - return 0; /* timed out */ - goto retry; - } - - return 1; -} - -static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data) -{ - atmel_writeAR(priv->dev, pos); - atmel_write16(priv->dev, DR, data); /* card is little-endian */ - atmel_write16(priv->dev, DR, data >> 16); -} - -/***************************************************************************/ -/* There follows the source form of the MAC address reading firmware */ -/***************************************************************************/ -#if 0 - -/* Copyright 2003 Matthew T. Russotto */ -/* But derived from the Atmel 76C502 firmware written by Atmel and */ -/* included in "atmel wireless lan drivers" package */ -/* - This file is part of net.russotto.AtmelMACFW, hereto referred to - as AtmelMACFW - - AtmelMACFW 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. - - AtmelMACFW 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 AtmelMACFW; if not, see . - -****************************************************************************/ -/* This firmware should work on the 76C502 RFMD, RFMD_D, and RFMD_E */ -/* It will probably work on the 76C504 and 76C502 RFMD_3COM */ -/* It only works on SPI EEPROM versions of the card. */ - -/* This firmware initializes the SPI controller and clock, reads the MAC */ -/* address from the EEPROM into SRAM, and puts the SRAM offset of the MAC */ -/* address in MR2, and sets MR3 to 0x10 to indicate it is done */ -/* It also puts a complete copy of the EEPROM in SRAM with the offset in */ -/* MR4, for investigational purposes (maybe we can determine chip type */ -/* from that?) */ - - .org 0 - .set MRBASE, 0x8000000 - .set CPSR_INITIAL, 0xD3 /* IRQ/FIQ disabled, ARM mode, Supervisor state */ - .set CPSR_USER, 0xD1 /* IRQ/FIQ disabled, ARM mode, USER state */ - .set SRAM_BASE, 0x02000000 - .set SP_BASE, 0x0F300000 - .set UNK_BASE, 0x0F000000 /* Some internal device, but which one? */ - .set SPI_CGEN_BASE, 0x0E000000 /* Some internal device, but which one? */ - .set UNK3_BASE, 0x02014000 /* Some internal device, but which one? */ - .set STACK_BASE, 0x5600 - .set SP_SR, 0x10 - .set SP_TDRE, 2 /* status register bit -- TDR empty */ - .set SP_RDRF, 1 /* status register bit -- RDR full */ - .set SP_SWRST, 0x80 - .set SP_SPIEN, 0x1 - .set SP_CR, 0 /* control register */ - .set SP_MR, 4 /* mode register */ - .set SP_RDR, 0x08 /* Read Data Register */ - .set SP_TDR, 0x0C /* Transmit Data Register */ - .set SP_CSR0, 0x30 /* chip select registers */ - .set SP_CSR1, 0x34 - .set SP_CSR2, 0x38 - .set SP_CSR3, 0x3C - .set NVRAM_CMD_RDSR, 5 /* read status register */ - .set NVRAM_CMD_READ, 3 /* read data */ - .set NVRAM_SR_RDY, 1 /* RDY bit. This bit is inverted */ - .set SPI_8CLOCKS, 0xFF /* Writing this to the TDR doesn't do anything to the - serial output, since SO is normally high. But it - does cause 8 clock cycles and thus 8 bits to be - clocked in to the chip. See Atmel's SPI - controller (e.g. AT91M55800) timing and 4K - SPI EEPROM manuals */ - - .set NVRAM_SCRATCH, 0x02000100 /* arbitrary area for scratchpad memory */ - .set NVRAM_IMAGE, 0x02000200 - .set NVRAM_LENGTH, 0x0200 - .set MAC_ADDRESS_MIB, SRAM_BASE - .set MAC_ADDRESS_LENGTH, 6 - .set MAC_BOOT_FLAG, 0x10 - .set MR1, 0 - .set MR2, 4 - .set MR3, 8 - .set MR4, 0xC -RESET_VECTOR: - b RESET_HANDLER -UNDEF_VECTOR: - b HALT1 -SWI_VECTOR: - b HALT1 -IABORT_VECTOR: - b HALT1 -DABORT_VECTOR: -RESERVED_VECTOR: - b HALT1 -IRQ_VECTOR: - b HALT1 -FIQ_VECTOR: - b HALT1 -HALT1: b HALT1 -RESET_HANDLER: - mov r0, #CPSR_INITIAL - msr CPSR_c, r0 /* This is probably unnecessary */ - -/* I'm guessing this is initializing clock generator electronics for SPI */ - ldr r0, =SPI_CGEN_BASE - mov r1, #0 - mov r1, r1, lsl #3 - orr r1, r1, #0 - str r1, [r0] - ldr r1, [r0, #28] - bic r1, r1, #16 - str r1, [r0, #28] - mov r1, #1 - str r1, [r0, #8] - - ldr r0, =MRBASE - mov r1, #0 - strh r1, [r0, #MR1] - strh r1, [r0, #MR2] - strh r1, [r0, #MR3] - strh r1, [r0, #MR4] - - mov sp, #STACK_BASE - bl SP_INIT - mov r0, #10 - bl DELAY9 - bl GET_MAC_ADDR - bl GET_WHOLE_NVRAM - ldr r0, =MRBASE - ldr r1, =MAC_ADDRESS_MIB - strh r1, [r0, #MR2] - ldr r1, =NVRAM_IMAGE - strh r1, [r0, #MR4] - mov r1, #MAC_BOOT_FLAG - strh r1, [r0, #MR3] -HALT2: b HALT2 -.func Get_Whole_NVRAM, GET_WHOLE_NVRAM -GET_WHOLE_NVRAM: - stmdb sp!, {lr} - mov r2, #0 /* 0th bytes of NVRAM */ - mov r3, #NVRAM_LENGTH - mov r1, #0 /* not used in routine */ - ldr r0, =NVRAM_IMAGE - bl NVRAM_XFER - ldmia sp!, {lr} - bx lr -.endfunc - -.func Get_MAC_Addr, GET_MAC_ADDR -GET_MAC_ADDR: - stmdb sp!, {lr} - mov r2, #0x120 /* address of MAC Address within NVRAM */ - mov r3, #MAC_ADDRESS_LENGTH - mov r1, #0 /* not used in routine */ - ldr r0, =MAC_ADDRESS_MIB - bl NVRAM_XFER - ldmia sp!, {lr} - bx lr -.endfunc -.ltorg -.func Delay9, DELAY9 -DELAY9: - adds r0, r0, r0, LSL #3 /* r0 = r0 * 9 */ -DELAYLOOP: - beq DELAY9_done - subs r0, r0, #1 - b DELAYLOOP -DELAY9_done: - bx lr -.endfunc - -.func SP_Init, SP_INIT -SP_INIT: - mov r1, #SP_SWRST - ldr r0, =SP_BASE - str r1, [r0, #SP_CR] /* reset the SPI */ - mov r1, #0 - str r1, [r0, #SP_CR] /* release SPI from reset state */ - mov r1, #SP_SPIEN - str r1, [r0, #SP_MR] /* set the SPI to MASTER mode*/ - str r1, [r0, #SP_CR] /* enable the SPI */ - -/* My guess would be this turns on the SPI clock */ - ldr r3, =SPI_CGEN_BASE - ldr r1, [r3, #28] - orr r1, r1, #0x2000 - str r1, [r3, #28] - - ldr r1, =0x2000c01 - str r1, [r0, #SP_CSR0] - ldr r1, =0x2000201 - str r1, [r0, #SP_CSR1] - str r1, [r0, #SP_CSR2] - str r1, [r0, #SP_CSR3] - ldr r1, [r0, #SP_SR] - ldr r0, [r0, #SP_RDR] - bx lr -.endfunc -.func NVRAM_Init, NVRAM_INIT -NVRAM_INIT: - ldr r1, =SP_BASE - ldr r0, [r1, #SP_RDR] - mov r0, #NVRAM_CMD_RDSR - str r0, [r1, #SP_TDR] -SP_loop1: - ldr r0, [r1, #SP_SR] - tst r0, #SP_TDRE - beq SP_loop1 - - mov r0, #SPI_8CLOCKS - str r0, [r1, #SP_TDR] -SP_loop2: - ldr r0, [r1, #SP_SR] - tst r0, #SP_TDRE - beq SP_loop2 - - ldr r0, [r1, #SP_RDR] -SP_loop3: - ldr r0, [r1, #SP_SR] - tst r0, #SP_RDRF - beq SP_loop3 - - ldr r0, [r1, #SP_RDR] - and r0, r0, #255 - bx lr -.endfunc - -.func NVRAM_Xfer, NVRAM_XFER - /* r0 = dest address */ - /* r1 = not used */ - /* r2 = src address within NVRAM */ - /* r3 = length */ -NVRAM_XFER: - stmdb sp!, {r4, r5, lr} - mov r5, r0 /* save r0 (dest address) */ - mov r4, r3 /* save r3 (length) */ - mov r0, r2, LSR #5 /* SPI memories put A8 in the command field */ - and r0, r0, #8 - add r0, r0, #NVRAM_CMD_READ - ldr r1, =NVRAM_SCRATCH - strb r0, [r1, #0] /* save command in NVRAM_SCRATCH[0] */ - strb r2, [r1, #1] /* save low byte of source address in NVRAM_SCRATCH[1] */ -_local1: - bl NVRAM_INIT - tst r0, #NVRAM_SR_RDY - bne _local1 - mov r0, #20 - bl DELAY9 - mov r2, r4 /* length */ - mov r1, r5 /* dest address */ - mov r0, #2 /* bytes to transfer in command */ - bl NVRAM_XFER2 - ldmia sp!, {r4, r5, lr} - bx lr -.endfunc - -.func NVRAM_Xfer2, NVRAM_XFER2 -NVRAM_XFER2: - stmdb sp!, {r4, r5, r6, lr} - ldr r4, =SP_BASE - mov r3, #0 - cmp r0, #0 - bls _local2 - ldr r5, =NVRAM_SCRATCH -_local4: - ldrb r6, [r5, r3] - str r6, [r4, #SP_TDR] -_local3: - ldr r6, [r4, #SP_SR] - tst r6, #SP_TDRE - beq _local3 - add r3, r3, #1 - cmp r3, r0 /* r0 is # of bytes to send out (command+addr) */ - blo _local4 -_local2: - mov r3, #SPI_8CLOCKS - str r3, [r4, #SP_TDR] - ldr r0, [r4, #SP_RDR] -_local5: - ldr r0, [r4, #SP_SR] - tst r0, #SP_RDRF - beq _local5 - ldr r0, [r4, #SP_RDR] /* what's this byte? It's the byte read while writing the TDR -- nonsense, because the NVRAM doesn't read and write at the same time */ - mov r0, #0 - cmp r2, #0 /* r2 is # of bytes to copy in */ - bls _local6 -_local7: - ldr r5, [r4, #SP_SR] - tst r5, #SP_TDRE - beq _local7 - str r3, [r4, #SP_TDR] /* r3 has SPI_8CLOCKS */ -_local8: - ldr r5, [r4, #SP_SR] - tst r5, #SP_RDRF - beq _local8 - ldr r5, [r4, #SP_RDR] /* but didn't we read this byte above? */ - strb r5, [r1], #1 /* postindexed */ - add r0, r0, #1 - cmp r0, r2 - blo _local7 /* since we don't send another address, the NVRAM must be capable of sequential reads */ -_local6: - mov r0, #200 - bl DELAY9 - ldmia sp!, {r4, r5, r6, lr} - bx lr -#endif diff --git a/drivers/net/wireless/atmel/atmel.h b/drivers/net/wireless/atmel/atmel.h deleted file mode 100644 index d2aa52cf6e8b1..0000000000000 --- a/drivers/net/wireless/atmel/atmel.h +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/*** -*- linux-c -*- ********************************************************** - - Driver for Atmel at76c502 at76c504 and at76c506 wireless cards. - - Copyright 2005 Dan Williams and Red Hat, Inc. - - -******************************************************************************/ - -#ifndef _ATMEL_H -#define _ATMEL_H - -typedef enum { - ATMEL_FW_TYPE_NONE = 0, - ATMEL_FW_TYPE_502, - ATMEL_FW_TYPE_502D, - ATMEL_FW_TYPE_502E, - ATMEL_FW_TYPE_502_3COM, - ATMEL_FW_TYPE_504, - ATMEL_FW_TYPE_504_2958, - ATMEL_FW_TYPE_504A_2958, - ATMEL_FW_TYPE_506 -} AtmelFWType; - -struct net_device *init_atmel_card(unsigned short, unsigned long, const AtmelFWType, struct device *, - int (*present_func)(void *), void * ); -void stop_atmel_card( struct net_device *); -int atmel_open( struct net_device * ); - -#endif diff --git a/drivers/net/wireless/atmel/atmel_cs.c b/drivers/net/wireless/atmel/atmel_cs.c deleted file mode 100644 index 58bba9875d366..0000000000000 --- a/drivers/net/wireless/atmel/atmel_cs.c +++ /dev/null @@ -1,292 +0,0 @@ -/*** -*- linux-c -*- ********************************************************** - - Driver for Atmel at76c502 at76c504 and at76c506 wireless cards. - - Copyright 2000-2001 ATMEL Corporation. - Copyright 2003 Simon Kelley. - - This code was developed from version 2.1.1 of the Atmel drivers, - released by Atmel corp. under the GPL in December 2002. It also - includes code from the Linux aironet drivers (C) Benjamin Reed, - and the Linux PCMCIA package, (C) David Hinds. - - For all queries about this code, please contact the current author, - Simon Kelley and not Atmel Corporation. - - 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 software 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 Atmel wireless lan drivers; if not, see - . - -******************************************************************************/ - -#ifdef __IN_PCMCIA_PACKAGE__ -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include "atmel.h" - - -/*====================================================================*/ - -MODULE_AUTHOR("Simon Kelley"); -MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards."); -MODULE_LICENSE("GPL"); - -/*====================================================================*/ - -static int atmel_config(struct pcmcia_device *link); -static void atmel_release(struct pcmcia_device *link); - -static void atmel_detach(struct pcmcia_device *p_dev); - -struct local_info { - struct net_device *eth_dev; -}; - -static int atmel_probe(struct pcmcia_device *p_dev) -{ - struct local_info *local; - int ret; - - dev_dbg(&p_dev->dev, "atmel_attach()\n"); - - /* Allocate space for private device-specific data */ - local = kzalloc(sizeof(*local), GFP_KERNEL); - if (!local) - return -ENOMEM; - - p_dev->priv = local; - - ret = atmel_config(p_dev); - if (ret) - goto err_free_priv; - - return 0; - -err_free_priv: - kfree(p_dev->priv); - return ret; -} - -static void atmel_detach(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "atmel_detach\n"); - - atmel_release(link); - - kfree(link->priv); -} - -/* Call-back function to interrogate PCMCIA-specific information - about the current existence of the card */ -static int card_present(void *arg) -{ - struct pcmcia_device *link = (struct pcmcia_device *)arg; - - if (pcmcia_dev_present(link)) - return 1; - - return 0; -} - -static int atmel_config_check(struct pcmcia_device *p_dev, void *priv_data) -{ - if (p_dev->config_index == 0) - return -EINVAL; - - return pcmcia_request_io(p_dev); -} - -static int atmel_config(struct pcmcia_device *link) -{ - int ret; - const struct pcmcia_device_id *did; - - did = dev_get_drvdata(&link->dev); - - dev_dbg(&link->dev, "atmel_config\n"); - - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP | - CONF_AUTO_AUDIO | CONF_AUTO_SET_IO; - - if (pcmcia_loop_config(link, atmel_config_check, NULL)) - goto failed; - - if (!link->irq) { - dev_err(&link->dev, "atmel: cannot assign IRQ: check that CONFIG_ISA is set in kernel config."); - goto failed; - } - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - ((struct local_info *)link->priv)->eth_dev = - init_atmel_card(link->irq, - link->resource[0]->start, - did ? did->driver_info : ATMEL_FW_TYPE_NONE, - &link->dev, - card_present, - link); - if (!((struct local_info *)link->priv)->eth_dev) - goto failed; - - - return 0; - - failed: - atmel_release(link); - return -ENODEV; -} - -static void atmel_release(struct pcmcia_device *link) -{ - struct net_device *dev = ((struct local_info *)link->priv)->eth_dev; - - dev_dbg(&link->dev, "atmel_release\n"); - - if (dev) - stop_atmel_card(dev); - ((struct local_info *)link->priv)->eth_dev = NULL; - - pcmcia_disable_device(link); -} - -static int atmel_suspend(struct pcmcia_device *link) -{ - struct local_info *local = link->priv; - - netif_device_detach(local->eth_dev); - - return 0; -} - -static int atmel_resume(struct pcmcia_device *link) -{ - struct local_info *local = link->priv; - - atmel_open(local->eth_dev); - netif_device_attach(local->eth_dev); - - return 0; -} - -/*====================================================================*/ -/* We use the driver_info field to store the correct firmware type for a card. */ - -#define PCMCIA_DEVICE_MANF_CARD_INFO(manf, card, info) { \ - .match_flags = PCMCIA_DEV_ID_MATCH_MANF_ID| \ - PCMCIA_DEV_ID_MATCH_CARD_ID, \ - .manf_id = (manf), \ - .card_id = (card), \ - .driver_info = (kernel_ulong_t)(info), } - -#define PCMCIA_DEVICE_PROD_ID12_INFO(v1, v2, vh1, vh2, info) { \ - .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \ - PCMCIA_DEV_ID_MATCH_PROD_ID2, \ - .prod_id = { (v1), (v2), NULL, NULL }, \ - .prod_id_hash = { (vh1), (vh2), 0, 0 }, \ - .driver_info = (kernel_ulong_t)(info), } - -static const struct pcmcia_device_id atmel_ids[] = { - PCMCIA_DEVICE_MANF_CARD_INFO(0x0101, 0x0620, ATMEL_FW_TYPE_502_3COM), - PCMCIA_DEVICE_MANF_CARD_INFO(0x0101, 0x0696, ATMEL_FW_TYPE_502_3COM), - PCMCIA_DEVICE_MANF_CARD_INFO(0x01bf, 0x3302, ATMEL_FW_TYPE_502E), - PCMCIA_DEVICE_MANF_CARD_INFO(0xd601, 0x0007, ATMEL_FW_TYPE_502), - PCMCIA_DEVICE_PROD_ID12_INFO("11WAVE", "11WP611AL-E", 0x9eb2da1f, 0xc9a0d3f9, ATMEL_FW_TYPE_502E), - PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C502AR", 0xabda4164, 0x41b37e1f, ATMEL_FW_TYPE_502), - PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C502AR_D", 0xabda4164, 0x3675d704, ATMEL_FW_TYPE_502D), - PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C502AR_E", 0xabda4164, 0x4172e792, ATMEL_FW_TYPE_502E), - PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C504_R", 0xabda4164, 0x917f3d72, ATMEL_FW_TYPE_504_2958), - PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C504", 0xabda4164, 0x5040670a, ATMEL_FW_TYPE_504), - PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C504A", 0xabda4164, 0xe15ed87f, ATMEL_FW_TYPE_504A_2958), - PCMCIA_DEVICE_PROD_ID12_INFO("BT", "Voyager 1020 Laptop Adapter", 0xae49b86a, 0x1e957cd5, ATMEL_FW_TYPE_502), - PCMCIA_DEVICE_PROD_ID12_INFO("CNet", "CNWLC 11Mbps Wireless PC Card V-5", 0xbc477dde, 0x502fae6b, ATMEL_FW_TYPE_502E), - PCMCIA_DEVICE_PROD_ID12_INFO("IEEE 802.11b", "Wireless LAN PC Card", 0x5b878724, 0x122f1df6, ATMEL_FW_TYPE_502), - PCMCIA_DEVICE_PROD_ID12_INFO("IEEE 802.11b", "Wireless LAN Card S", 0x5b878724, 0x5fba533a, ATMEL_FW_TYPE_504_2958), - PCMCIA_DEVICE_PROD_ID12_INFO("OEM", "11Mbps Wireless LAN PC Card V-3", 0xfea54c90, 0x1c5b0f68, ATMEL_FW_TYPE_502), - PCMCIA_DEVICE_PROD_ID12_INFO("SMC", "2632W", 0xc4f8b18b, 0x30f38774, ATMEL_FW_TYPE_502D), - PCMCIA_DEVICE_PROD_ID12_INFO("SMC", "2632W-V2", 0xc4f8b18b, 0x172d1377, ATMEL_FW_TYPE_502), - PCMCIA_DEVICE_PROD_ID12_INFO("Wireless", "PC_CARD", 0xa407ecdd, 0x119f6314, ATMEL_FW_TYPE_502D), - PCMCIA_DEVICE_PROD_ID12_INFO("WLAN", "802.11b PC CARD", 0x575c516c, 0xb1f6dbc4, ATMEL_FW_TYPE_502D), - PCMCIA_DEVICE_PROD_ID12_INFO("LG", "LW2100N", 0xb474d43a, 0x6b1fec94, ATMEL_FW_TYPE_502E), - PCMCIA_DEVICE_NULL -}; - -MODULE_DEVICE_TABLE(pcmcia, atmel_ids); - -static struct pcmcia_driver atmel_driver = { - .owner = THIS_MODULE, - .name = "atmel_cs", - .probe = atmel_probe, - .remove = atmel_detach, - .id_table = atmel_ids, - .suspend = atmel_suspend, - .resume = atmel_resume, -}; -module_pcmcia_driver(atmel_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. - - In addition: - - 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. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -*/ diff --git a/drivers/net/wireless/atmel/atmel_pci.c b/drivers/net/wireless/atmel/atmel_pci.c deleted file mode 100644 index f428dc79d9161..0000000000000 --- a/drivers/net/wireless/atmel/atmel_pci.c +++ /dev/null @@ -1,65 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/*** -*- linux-c -*- ********************************************************** - - Driver for Atmel at76c502 at76c504 and at76c506 wireless cards. - - Copyright 2004 Simon Kelley. - - -******************************************************************************/ -#include -#include -#include -#include -#include "atmel.h" - -MODULE_AUTHOR("Simon Kelley"); -MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards."); -MODULE_LICENSE("GPL"); - -static const struct pci_device_id card_ids[] = { - { 0x1114, 0x0506, PCI_ANY_ID, PCI_ANY_ID }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, card_ids); - -static int atmel_pci_probe(struct pci_dev *, const struct pci_device_id *); -static void atmel_pci_remove(struct pci_dev *); - -static struct pci_driver atmel_driver = { - .name = "atmel", - .id_table = card_ids, - .probe = atmel_pci_probe, - .remove = atmel_pci_remove, -}; - - -static int atmel_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *pent) -{ - struct net_device *dev; - - if (pci_enable_device(pdev)) - return -ENODEV; - - pci_set_master(pdev); - - dev = init_atmel_card(pdev->irq, pdev->resource[1].start, - ATMEL_FW_TYPE_506, - &pdev->dev, NULL, NULL); - if (!dev) { - pci_disable_device(pdev); - return -ENODEV; - } - - pci_set_drvdata(pdev, dev); - return 0; -} - -static void atmel_pci_remove(struct pci_dev *pdev) -{ - stop_atmel_card(pci_get_drvdata(pdev)); -} - -module_pci_driver(atmel_driver); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 667462369a32f..133c5ea6429cd 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -866,7 +866,7 @@ struct wireless_dev *brcmf_apsta_add_vif(struct wiphy *wiphy, const char *name, goto fail; } - strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1); + strscpy(ifp->ndev->name, name, sizeof(ifp->ndev->name)); err = brcmf_net_attach(ifp, true); if (err) { bphy_err(drvr, "Registering netdevice failed\n"); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c index d4492d02e4ea1..6e0c90f4718b5 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c @@ -2334,7 +2334,7 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, goto fail; } - strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1); + strscpy(ifp->ndev->name, name, sizeof(ifp->ndev->name)); ifp->ndev->name_assign_type = name_assign_type; err = brcmf_net_attach(ifp, true); if (err) { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c index 5a6d9c86552a1..f6962e558d7c7 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c @@ -341,7 +341,7 @@ struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc) /* store the country code for passing up as a regulatory hint */ wlc_cm->world_regd = brcms_world_regd(ccode, ccode_len); if (brcms_c_country_valid(ccode)) - strncpy(wlc->pub->srom_ccode, ccode, ccode_len); + memcpy(wlc->pub->srom_ccode, ccode, ccode_len); /* * If no custom world domain is found in the SROM, use the @@ -354,10 +354,10 @@ struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc) } /* save default country for exiting 11d regulatory mode */ - strncpy(wlc->country_default, ccode, ccode_len); + memcpy(wlc->country_default, ccode, ccode_len); /* initialize autocountry_default to driver default */ - strncpy(wlc->autocountry_default, ccode, ccode_len); + memcpy(wlc->autocountry_default, ccode, ccode_len); brcms_c_set_country(wlc_cm, wlc_cm->world_regd); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c index b7df576bb84d9..3d5c1ef8f7f25 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c @@ -584,8 +584,7 @@ struct dma_pub *dma_attach(char *name, struct brcms_c_info *wlc, rxextheadroom, nrxpost, rxoffset, txregbase, rxregbase); /* make a private copy of our callers name */ - strncpy(di->name, name, MAXNAMEL); - di->name[MAXNAMEL - 1] = '\0'; + strscpy(di->name, name, sizeof(di->name)); di->dmadev = core->dma_dev; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c index b3663c5ef3827..34460b5815d02 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c @@ -5551,8 +5551,8 @@ int brcms_c_module_register(struct brcms_pub *pub, /* find an empty entry and just add, no duplication check! */ for (i = 0; i < BRCMS_MAXMODULES; i++) { if (wlc->modulecb[i].name[0] == '\0') { - strncpy(wlc->modulecb[i].name, name, - sizeof(wlc->modulecb[i].name) - 1); + strscpy(wlc->modulecb[i].name, name, + sizeof(wlc->modulecb[i].name)); wlc->modulecb[i].hdl = hdl; wlc->modulecb[i].down_fn = d_fn; return 0; diff --git a/drivers/net/wireless/cisco/Kconfig b/drivers/net/wireless/cisco/Kconfig deleted file mode 100644 index b40ee25aca995..0000000000000 --- a/drivers/net/wireless/cisco/Kconfig +++ /dev/null @@ -1,59 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config WLAN_VENDOR_CISCO - bool "Cisco devices" - default y - help - If you have a wireless card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all the - questions about these cards. If you say Y, you will be asked for - your specific card in the following questions. - -if WLAN_VENDOR_CISCO - -config AIRO - tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards" - depends on CFG80211 && (PCI || BROKEN) - select WIRELESS_EXT - select CRYPTO - select CRYPTO_SKCIPHER - select WEXT_SPY - select WEXT_PRIV - help - This is the standard Linux driver to support Cisco/Aironet ISA and - PCI 802.11 wireless cards. - It supports the new 802.11b cards from Cisco (Cisco 34X, Cisco 35X - - with or without encryption) as well as card before the Cisco - acquisition (Aironet 4500, Aironet 4800, Aironet 4800B). - - This driver support both the standard Linux Wireless Extensions - and Cisco proprietary API, so both the Linux Wireless Tools and the - Cisco Linux utilities can be used to configure the card. - - The driver can be compiled as a module and will be named "airo". - -config AIRO_CS - tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards" - depends on CFG80211 && PCMCIA - select WIRELESS_EXT - select WEXT_SPY - select WEXT_PRIV - select CRYPTO - select CRYPTO_AES - select CRYPTO_CTR - help - This is the standard Linux driver to support Cisco/Aironet PCMCIA - 802.11 wireless cards. This driver is the same as the Aironet - driver part of the Linux Pcmcia package. - It supports the new 802.11b cards from Cisco (Cisco 34X, Cisco 35X - - with or without encryption) as well as card before the Cisco - acquisition (Aironet 4500, Aironet 4800, Aironet 4800B). It also - supports OEM of Cisco such as the DELL TrueMobile 4800 and Xircom - 802.11b cards. - - This driver support both the standard Linux Wireless Extensions - and Cisco proprietary API, so both the Linux Wireless Tools and the - Cisco Linux utilities can be used to configure the card. - -endif # WLAN_VENDOR_CISCO diff --git a/drivers/net/wireless/cisco/Makefile b/drivers/net/wireless/cisco/Makefile deleted file mode 100644 index 506a19ce375f4..0000000000000 --- a/drivers/net/wireless/cisco/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_AIRO) += airo.o -obj-$(CONFIG_AIRO_CS) += airo_cs.o airo.o diff --git a/drivers/net/wireless/cisco/airo.c b/drivers/net/wireless/cisco/airo.c deleted file mode 100644 index dbd13f7aa3e6e..0000000000000 --- a/drivers/net/wireless/cisco/airo.c +++ /dev/null @@ -1,8288 +0,0 @@ -/*====================================================================== - - Aironet driver for 4500 and 4800 series cards - - This code is released under both the GPL version 2 and BSD licenses. - Either license may be used. The respective licenses are found at - the end of this file. - - This code was developed by Benjamin Reed - including portions of which come from the Aironet PC4500 - Developer's Reference Manual and used with permission. Copyright - (C) 1999 Benjamin Reed. All Rights Reserved. Permission to use - code in the Developer's manual was granted for this driver by - Aironet. Major code contributions were received from Javier Achirica - and Jean Tourrilhes . - Code was also integrated from the Cisco Aironet driver for Linux. - Support for MPI350 cards was added by Fabrice Bellet - . - -======================================================================*/ - -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include "airo.h" - -#define DRV_NAME "airo" - -#ifdef CONFIG_PCI -static const struct pci_device_id card_ids[] = { - { 0x14b9, 1, PCI_ANY_ID, PCI_ANY_ID, }, - { 0x14b9, 0x4500, PCI_ANY_ID, PCI_ANY_ID }, - { 0x14b9, 0x4800, PCI_ANY_ID, PCI_ANY_ID, }, - { 0x14b9, 0x0340, PCI_ANY_ID, PCI_ANY_ID, }, - { 0x14b9, 0x0350, PCI_ANY_ID, PCI_ANY_ID, }, - { 0x14b9, 0x5000, PCI_ANY_ID, PCI_ANY_ID, }, - { 0x14b9, 0xa504, PCI_ANY_ID, PCI_ANY_ID, }, - { 0, } -}; -MODULE_DEVICE_TABLE(pci, card_ids); - -static int airo_pci_probe(struct pci_dev *, const struct pci_device_id *); -static void airo_pci_remove(struct pci_dev *); -static int __maybe_unused airo_pci_suspend(struct device *dev); -static int __maybe_unused airo_pci_resume(struct device *dev); - -static SIMPLE_DEV_PM_OPS(airo_pci_pm_ops, - airo_pci_suspend, - airo_pci_resume); - -static struct pci_driver airo_driver = { - .name = DRV_NAME, - .id_table = card_ids, - .probe = airo_pci_probe, - .remove = airo_pci_remove, - .driver.pm = &airo_pci_pm_ops, -}; -#endif /* CONFIG_PCI */ - -/* Include Wireless Extension definition and check version - Jean II */ -#include -#define WIRELESS_SPY /* enable iwspy support */ - -#define CISCO_EXT /* enable Cisco extensions */ -#ifdef CISCO_EXT -#include -#endif - -/* Hack to do some power saving */ -#define POWER_ON_DOWN - -/* As you can see this list is HUGH! - I really don't know what a lot of these counts are about, but they - are all here for completeness. If the IGNLABEL macro is put in - infront of the label, that statistic will not be included in the list - of statistics in the /proc filesystem */ - -#define IGNLABEL(comment) NULL -static const char *statsLabels[] = { - "RxOverrun", - IGNLABEL("RxPlcpCrcErr"), - IGNLABEL("RxPlcpFormatErr"), - IGNLABEL("RxPlcpLengthErr"), - "RxMacCrcErr", - "RxMacCrcOk", - "RxWepErr", - "RxWepOk", - "RetryLong", - "RetryShort", - "MaxRetries", - "NoAck", - "NoCts", - "RxAck", - "RxCts", - "TxAck", - "TxRts", - "TxCts", - "TxMc", - "TxBc", - "TxUcFrags", - "TxUcPackets", - "TxBeacon", - "RxBeacon", - "TxSinColl", - "TxMulColl", - "DefersNo", - "DefersProt", - "DefersEngy", - "DupFram", - "RxFragDisc", - "TxAged", - "RxAged", - "LostSync-MaxRetry", - "LostSync-MissedBeacons", - "LostSync-ArlExceeded", - "LostSync-Deauth", - "LostSync-Disassoced", - "LostSync-TsfTiming", - "HostTxMc", - "HostTxBc", - "HostTxUc", - "HostTxFail", - "HostRxMc", - "HostRxBc", - "HostRxUc", - "HostRxDiscard", - IGNLABEL("HmacTxMc"), - IGNLABEL("HmacTxBc"), - IGNLABEL("HmacTxUc"), - IGNLABEL("HmacTxFail"), - IGNLABEL("HmacRxMc"), - IGNLABEL("HmacRxBc"), - IGNLABEL("HmacRxUc"), - IGNLABEL("HmacRxDiscard"), - IGNLABEL("HmacRxAccepted"), - "SsidMismatch", - "ApMismatch", - "RatesMismatch", - "AuthReject", - "AuthTimeout", - "AssocReject", - "AssocTimeout", - IGNLABEL("ReasonOutsideTable"), - IGNLABEL("ReasonStatus1"), - IGNLABEL("ReasonStatus2"), - IGNLABEL("ReasonStatus3"), - IGNLABEL("ReasonStatus4"), - IGNLABEL("ReasonStatus5"), - IGNLABEL("ReasonStatus6"), - IGNLABEL("ReasonStatus7"), - IGNLABEL("ReasonStatus8"), - IGNLABEL("ReasonStatus9"), - IGNLABEL("ReasonStatus10"), - IGNLABEL("ReasonStatus11"), - IGNLABEL("ReasonStatus12"), - IGNLABEL("ReasonStatus13"), - IGNLABEL("ReasonStatus14"), - IGNLABEL("ReasonStatus15"), - IGNLABEL("ReasonStatus16"), - IGNLABEL("ReasonStatus17"), - IGNLABEL("ReasonStatus18"), - IGNLABEL("ReasonStatus19"), - "RxMan", - "TxMan", - "RxRefresh", - "TxRefresh", - "RxPoll", - "TxPoll", - "HostRetries", - "LostSync-HostReq", - "HostTxBytes", - "HostRxBytes", - "ElapsedUsec", - "ElapsedSec", - "LostSyncBetterAP", - "PrivacyMismatch", - "Jammed", - "DiscRxNotWepped", - "PhyEleMismatch", - (char*)-1 }; -#ifndef RUN_AT -#define RUN_AT(x) (jiffies+(x)) -#endif - - -/* These variables are for insmod, since it seems that the rates - can only be set in setup_card. Rates should be a comma separated - (no spaces) list of rates (up to 8). */ - -static int rates[8]; -static char *ssids[3]; - -static int io[4]; -static int irq[4]; - -static -int maxencrypt /* = 0 */; /* The highest rate that the card can encrypt at. - 0 means no limit. For old cards this was 4 */ - -static int auto_wep /* = 0 */; /* If set, it tries to figure out the wep mode */ -static int aux_bap /* = 0 */; /* Checks to see if the aux ports are needed to read - the bap, needed on some older cards and buses. */ -static int adhoc; - -static int probe = 1; - -static kuid_t proc_kuid; -static int proc_uid /* = 0 */; - -static kgid_t proc_kgid; -static int proc_gid /* = 0 */; - -static int airo_perm = 0555; - -static int proc_perm = 0644; - -MODULE_AUTHOR("Benjamin Reed"); -MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet cards. " - "Direct support for ISA/PCI/MPI cards and support for PCMCIA when used with airo_cs."); -MODULE_LICENSE("Dual BSD/GPL"); -module_param_hw_array(io, int, ioport, NULL, 0); -module_param_hw_array(irq, int, irq, NULL, 0); -module_param_array(rates, int, NULL, 0); -module_param_array(ssids, charp, NULL, 0); -module_param(auto_wep, int, 0); -MODULE_PARM_DESC(auto_wep, - "If non-zero, the driver will keep looping through the authentication options until an association is made. " - "The value of auto_wep is number of the wep keys to check. " - "A value of 2 will try using the key at index 0 and index 1."); -module_param(aux_bap, int, 0); -MODULE_PARM_DESC(aux_bap, - "If non-zero, the driver will switch into a mode that seems to work better for older cards with some older buses. " - "Before switching it checks that the switch is needed."); -module_param(maxencrypt, int, 0); -MODULE_PARM_DESC(maxencrypt, - "The maximum speed that the card can do encryption. " - "Units are in 512kbs. " - "Zero (default) means there is no limit. " - "Older cards used to be limited to 2mbs (4)."); -module_param(adhoc, int, 0); -MODULE_PARM_DESC(adhoc, "If non-zero, the card will start in adhoc mode."); -module_param(probe, int, 0); -MODULE_PARM_DESC(probe, "If zero, the driver won't start the card."); - -module_param(proc_uid, int, 0); -MODULE_PARM_DESC(proc_uid, "The uid that the /proc files will belong to."); -module_param(proc_gid, int, 0); -MODULE_PARM_DESC(proc_gid, "The gid that the /proc files will belong to."); -module_param(airo_perm, int, 0); -MODULE_PARM_DESC(airo_perm, "The permission bits of /proc/[driver/]aironet."); -module_param(proc_perm, int, 0); -MODULE_PARM_DESC(proc_perm, "The permission bits of the files in /proc"); - -/* This is a kind of sloppy hack to get this information to OUT4500 and - IN4500. I would be extremely interested in the situation where this - doesn't work though!!! */ -static int do8bitIO /* = 0 */; - -/* Return codes */ -#define SUCCESS 0 -#define ERROR -1 -#define NO_PACKET -2 - -/* Commands */ -#define NOP2 0x0000 -#define MAC_ENABLE 0x0001 -#define MAC_DISABLE 0x0002 -#define CMD_LOSE_SYNC 0x0003 /* Not sure what this does... */ -#define CMD_SOFTRESET 0x0004 -#define HOSTSLEEP 0x0005 -#define CMD_MAGIC_PKT 0x0006 -#define CMD_SETWAKEMASK 0x0007 -#define CMD_READCFG 0x0008 -#define CMD_SETMODE 0x0009 -#define CMD_ALLOCATETX 0x000a -#define CMD_TRANSMIT 0x000b -#define CMD_DEALLOCATETX 0x000c -#define NOP 0x0010 -#define CMD_WORKAROUND 0x0011 -#define CMD_ALLOCATEAUX 0x0020 -#define CMD_ACCESS 0x0021 -#define CMD_PCIBAP 0x0022 -#define CMD_PCIAUX 0x0023 -#define CMD_ALLOCBUF 0x0028 -#define CMD_GETTLV 0x0029 -#define CMD_PUTTLV 0x002a -#define CMD_DELTLV 0x002b -#define CMD_FINDNEXTTLV 0x002c -#define CMD_PSPNODES 0x0030 -#define CMD_SETCW 0x0031 -#define CMD_SETPCF 0x0032 -#define CMD_SETPHYREG 0x003e -#define CMD_TXTEST 0x003f -#define MAC_ENABLETX 0x0101 -#define CMD_LISTBSS 0x0103 -#define CMD_SAVECFG 0x0108 -#define CMD_ENABLEAUX 0x0111 -#define CMD_WRITERID 0x0121 -#define CMD_USEPSPNODES 0x0130 -#define MAC_ENABLERX 0x0201 - -/* Command errors */ -#define ERROR_QUALIF 0x00 -#define ERROR_ILLCMD 0x01 -#define ERROR_ILLFMT 0x02 -#define ERROR_INVFID 0x03 -#define ERROR_INVRID 0x04 -#define ERROR_LARGE 0x05 -#define ERROR_NDISABL 0x06 -#define ERROR_ALLOCBSY 0x07 -#define ERROR_NORD 0x0B -#define ERROR_NOWR 0x0C -#define ERROR_INVFIDTX 0x0D -#define ERROR_TESTACT 0x0E -#define ERROR_TAGNFND 0x12 -#define ERROR_DECODE 0x20 -#define ERROR_DESCUNAV 0x21 -#define ERROR_BADLEN 0x22 -#define ERROR_MODE 0x80 -#define ERROR_HOP 0x81 -#define ERROR_BINTER 0x82 -#define ERROR_RXMODE 0x83 -#define ERROR_MACADDR 0x84 -#define ERROR_RATES 0x85 -#define ERROR_ORDER 0x86 -#define ERROR_SCAN 0x87 -#define ERROR_AUTH 0x88 -#define ERROR_PSMODE 0x89 -#define ERROR_RTYPE 0x8A -#define ERROR_DIVER 0x8B -#define ERROR_SSID 0x8C -#define ERROR_APLIST 0x8D -#define ERROR_AUTOWAKE 0x8E -#define ERROR_LEAP 0x8F - -/* Registers */ -#define COMMAND 0x00 -#define PARAM0 0x02 -#define PARAM1 0x04 -#define PARAM2 0x06 -#define STATUS 0x08 -#define RESP0 0x0a -#define RESP1 0x0c -#define RESP2 0x0e -#define LINKSTAT 0x10 -#define SELECT0 0x18 -#define OFFSET0 0x1c -#define RXFID 0x20 -#define TXALLOCFID 0x22 -#define TXCOMPLFID 0x24 -#define DATA0 0x36 -#define EVSTAT 0x30 -#define EVINTEN 0x32 -#define EVACK 0x34 -#define SWS0 0x28 -#define SWS1 0x2a -#define SWS2 0x2c -#define SWS3 0x2e -#define AUXPAGE 0x3A -#define AUXOFF 0x3C -#define AUXDATA 0x3E - -#define FID_TX 1 -#define FID_RX 2 -/* Offset into aux memory for descriptors */ -#define AUX_OFFSET 0x800 -/* Size of allocated packets */ -#define PKTSIZE 1840 -#define RIDSIZE 2048 -/* Size of the transmit queue */ -#define MAXTXQ 64 - -/* BAP selectors */ -#define BAP0 0 /* Used for receiving packets */ -#define BAP1 2 /* Used for xmiting packets and working with RIDS */ - -/* Flags */ -#define COMMAND_BUSY 0x8000 - -#define BAP_BUSY 0x8000 -#define BAP_ERR 0x4000 -#define BAP_DONE 0x2000 - -#define PROMISC 0xffff -#define NOPROMISC 0x0000 - -#define EV_CMD 0x10 -#define EV_CLEARCOMMANDBUSY 0x4000 -#define EV_RX 0x01 -#define EV_TX 0x02 -#define EV_TXEXC 0x04 -#define EV_ALLOC 0x08 -#define EV_LINK 0x80 -#define EV_AWAKE 0x100 -#define EV_TXCPY 0x400 -#define EV_UNKNOWN 0x800 -#define EV_MIC 0x1000 /* Message Integrity Check Interrupt */ -#define EV_AWAKEN 0x2000 -#define STATUS_INTS (EV_AWAKE|EV_LINK|EV_TXEXC|EV_TX|EV_TXCPY|EV_RX|EV_MIC) - -#ifdef CHECK_UNKNOWN_INTS -#define IGNORE_INTS (EV_CMD | EV_UNKNOWN) -#else -#define IGNORE_INTS (~STATUS_INTS) -#endif - -/* RID TYPES */ -#define RID_RW 0x20 - -/* The RIDs */ -#define RID_CAPABILITIES 0xFF00 -#define RID_APINFO 0xFF01 -#define RID_RADIOINFO 0xFF02 -#define RID_UNKNOWN3 0xFF03 -#define RID_RSSI 0xFF04 -#define RID_CONFIG 0xFF10 -#define RID_SSID 0xFF11 -#define RID_APLIST 0xFF12 -#define RID_DRVNAME 0xFF13 -#define RID_ETHERENCAP 0xFF14 -#define RID_WEP_TEMP 0xFF15 -#define RID_WEP_PERM 0xFF16 -#define RID_MODULATION 0xFF17 -#define RID_OPTIONS 0xFF18 -#define RID_ACTUALCONFIG 0xFF20 /*readonly*/ -#define RID_FACTORYCONFIG 0xFF21 -#define RID_UNKNOWN22 0xFF22 -#define RID_LEAPUSERNAME 0xFF23 -#define RID_LEAPPASSWORD 0xFF24 -#define RID_STATUS 0xFF50 -#define RID_BEACON_HST 0xFF51 -#define RID_BUSY_HST 0xFF52 -#define RID_RETRIES_HST 0xFF53 -#define RID_UNKNOWN54 0xFF54 -#define RID_UNKNOWN55 0xFF55 -#define RID_UNKNOWN56 0xFF56 -#define RID_MIC 0xFF57 -#define RID_STATS16 0xFF60 -#define RID_STATS16DELTA 0xFF61 -#define RID_STATS16DELTACLEAR 0xFF62 -#define RID_STATS 0xFF68 -#define RID_STATSDELTA 0xFF69 -#define RID_STATSDELTACLEAR 0xFF6A -#define RID_ECHOTEST_RID 0xFF70 -#define RID_ECHOTEST_RESULTS 0xFF71 -#define RID_BSSLISTFIRST 0xFF72 -#define RID_BSSLISTNEXT 0xFF73 -#define RID_WPA_BSSLISTFIRST 0xFF74 -#define RID_WPA_BSSLISTNEXT 0xFF75 - -typedef struct { - u16 cmd; - u16 parm0; - u16 parm1; - u16 parm2; -} Cmd; - -typedef struct { - u16 status; - u16 rsp0; - u16 rsp1; - u16 rsp2; -} Resp; - -/* - * Rids and endian-ness: The Rids will always be in cpu endian, since - * this all the patches from the big-endian guys end up doing that. - * so all rid access should use the read/writeXXXRid routines. - */ - -/* This structure came from an email sent to me from an engineer at - aironet for inclusion into this driver */ -typedef struct WepKeyRid WepKeyRid; -struct WepKeyRid { - __le16 len; - __le16 kindex; - u8 mac[ETH_ALEN]; - __le16 klen; - u8 key[16]; -} __packed; - -/* These structures are from the Aironet's PC4500 Developers Manual */ -typedef struct Ssid Ssid; -struct Ssid { - __le16 len; - u8 ssid[32]; -} __packed; - -typedef struct SsidRid SsidRid; -struct SsidRid { - __le16 len; - Ssid ssids[3]; -} __packed; - -typedef struct ModulationRid ModulationRid; -struct ModulationRid { - __le16 len; - __le16 modulation; -#define MOD_DEFAULT cpu_to_le16(0) -#define MOD_CCK cpu_to_le16(1) -#define MOD_MOK cpu_to_le16(2) -} __packed; - -typedef struct ConfigRid ConfigRid; -struct ConfigRid { - __le16 len; /* sizeof(ConfigRid) */ - __le16 opmode; /* operating mode */ -#define MODE_STA_IBSS cpu_to_le16(0) -#define MODE_STA_ESS cpu_to_le16(1) -#define MODE_AP cpu_to_le16(2) -#define MODE_AP_RPTR cpu_to_le16(3) -#define MODE_CFG_MASK cpu_to_le16(0xff) -#define MODE_ETHERNET_HOST cpu_to_le16(0<<8) /* rx payloads converted */ -#define MODE_LLC_HOST cpu_to_le16(1<<8) /* rx payloads left as is */ -#define MODE_AIRONET_EXTEND cpu_to_le16(1<<9) /* enable Aironet extensions */ -#define MODE_AP_INTERFACE cpu_to_le16(1<<10) /* enable ap interface extensions */ -#define MODE_ANTENNA_ALIGN cpu_to_le16(1<<11) /* enable antenna alignment */ -#define MODE_ETHER_LLC cpu_to_le16(1<<12) /* enable ethernet LLC */ -#define MODE_LEAF_NODE cpu_to_le16(1<<13) /* enable leaf node bridge */ -#define MODE_CF_POLLABLE cpu_to_le16(1<<14) /* enable CF pollable */ -#define MODE_MIC cpu_to_le16(1<<15) /* enable MIC */ - __le16 rmode; /* receive mode */ -#define RXMODE_BC_MC_ADDR cpu_to_le16(0) -#define RXMODE_BC_ADDR cpu_to_le16(1) /* ignore multicasts */ -#define RXMODE_ADDR cpu_to_le16(2) /* ignore multicast and broadcast */ -#define RXMODE_RFMON cpu_to_le16(3) /* wireless monitor mode */ -#define RXMODE_RFMON_ANYBSS cpu_to_le16(4) -#define RXMODE_LANMON cpu_to_le16(5) /* lan style monitor -- data packets only */ -#define RXMODE_MASK cpu_to_le16(255) -#define RXMODE_DISABLE_802_3_HEADER cpu_to_le16(1<<8) /* disables 802.3 header on rx */ -#define RXMODE_FULL_MASK (RXMODE_MASK | RXMODE_DISABLE_802_3_HEADER) -#define RXMODE_NORMALIZED_RSSI cpu_to_le16(1<<9) /* return normalized RSSI */ - __le16 fragThresh; - __le16 rtsThres; - u8 macAddr[ETH_ALEN]; - u8 rates[8]; - __le16 shortRetryLimit; - __le16 longRetryLimit; - __le16 txLifetime; /* in kusec */ - __le16 rxLifetime; /* in kusec */ - __le16 stationary; - __le16 ordering; - __le16 u16deviceType; /* for overriding device type */ - __le16 cfpRate; - __le16 cfpDuration; - __le16 _reserved1[3]; - /*---------- Scanning/Associating ----------*/ - __le16 scanMode; -#define SCANMODE_ACTIVE cpu_to_le16(0) -#define SCANMODE_PASSIVE cpu_to_le16(1) -#define SCANMODE_AIROSCAN cpu_to_le16(2) - __le16 probeDelay; /* in kusec */ - __le16 probeEnergyTimeout; /* in kusec */ - __le16 probeResponseTimeout; - __le16 beaconListenTimeout; - __le16 joinNetTimeout; - __le16 authTimeout; - __le16 authType; -#define AUTH_OPEN cpu_to_le16(0x1) -#define AUTH_ENCRYPT cpu_to_le16(0x101) -#define AUTH_SHAREDKEY cpu_to_le16(0x102) -#define AUTH_ALLOW_UNENCRYPTED cpu_to_le16(0x200) - __le16 associationTimeout; - __le16 specifiedApTimeout; - __le16 offlineScanInterval; - __le16 offlineScanDuration; - __le16 linkLossDelay; - __le16 maxBeaconLostTime; - __le16 refreshInterval; -#define DISABLE_REFRESH cpu_to_le16(0xFFFF) - __le16 _reserved1a[1]; - /*---------- Power save operation ----------*/ - __le16 powerSaveMode; -#define POWERSAVE_CAM cpu_to_le16(0) -#define POWERSAVE_PSP cpu_to_le16(1) -#define POWERSAVE_PSPCAM cpu_to_le16(2) - __le16 sleepForDtims; - __le16 listenInterval; - __le16 fastListenInterval; - __le16 listenDecay; - __le16 fastListenDelay; - __le16 _reserved2[2]; - /*---------- Ap/Ibss config items ----------*/ - __le16 beaconPeriod; - __le16 atimDuration; - __le16 hopPeriod; - __le16 channelSet; - __le16 channel; - __le16 dtimPeriod; - __le16 bridgeDistance; - __le16 radioID; - /*---------- Radio configuration ----------*/ - __le16 radioType; -#define RADIOTYPE_DEFAULT cpu_to_le16(0) -#define RADIOTYPE_802_11 cpu_to_le16(1) -#define RADIOTYPE_LEGACY cpu_to_le16(2) - u8 rxDiversity; - u8 txDiversity; - __le16 txPower; -#define TXPOWER_DEFAULT 0 - __le16 rssiThreshold; -#define RSSI_DEFAULT 0 - __le16 modulation; -#define PREAMBLE_AUTO cpu_to_le16(0) -#define PREAMBLE_LONG cpu_to_le16(1) -#define PREAMBLE_SHORT cpu_to_le16(2) - __le16 preamble; - __le16 homeProduct; - __le16 radioSpecific; - /*---------- Aironet Extensions ----------*/ - u8 nodeName[16]; - __le16 arlThreshold; - __le16 arlDecay; - __le16 arlDelay; - __le16 _reserved4[1]; - /*---------- Aironet Extensions ----------*/ - u8 magicAction; -#define MAGIC_ACTION_STSCHG 1 -#define MAGIC_ACTION_RESUME 2 -#define MAGIC_IGNORE_MCAST (1<<8) -#define MAGIC_IGNORE_BCAST (1<<9) -#define MAGIC_SWITCH_TO_PSP (0<<10) -#define MAGIC_STAY_IN_CAM (1<<10) - u8 magicControl; - __le16 autoWake; -} __packed; - -typedef struct StatusRid StatusRid; -struct StatusRid { - __le16 len; - u8 mac[ETH_ALEN]; - __le16 mode; - __le16 errorCode; - __le16 sigQuality; - __le16 SSIDlen; - char SSID[32]; - char apName[16]; - u8 bssid[4][ETH_ALEN]; - __le16 beaconPeriod; - __le16 dimPeriod; - __le16 atimDuration; - __le16 hopPeriod; - __le16 channelSet; - __le16 channel; - __le16 hopsToBackbone; - __le16 apTotalLoad; - __le16 generatedLoad; - __le16 accumulatedArl; - __le16 signalQuality; - __le16 currentXmitRate; - __le16 apDevExtensions; - __le16 normalizedSignalStrength; - __le16 shortPreamble; - u8 apIP[4]; - u8 noisePercent; /* Noise percent in last second */ - u8 noisedBm; /* Noise dBm in last second */ - u8 noiseAvePercent; /* Noise percent in last minute */ - u8 noiseAvedBm; /* Noise dBm in last minute */ - u8 noiseMaxPercent; /* Highest noise percent in last minute */ - u8 noiseMaxdBm; /* Highest noise dbm in last minute */ - __le16 load; - u8 carrier[4]; - __le16 assocStatus; -#define STAT_NOPACKETS 0 -#define STAT_NOCARRIERSET 10 -#define STAT_GOTCARRIERSET 11 -#define STAT_WRONGSSID 20 -#define STAT_BADCHANNEL 25 -#define STAT_BADBITRATES 30 -#define STAT_BADPRIVACY 35 -#define STAT_APFOUND 40 -#define STAT_APREJECTED 50 -#define STAT_AUTHENTICATING 60 -#define STAT_DEAUTHENTICATED 61 -#define STAT_AUTHTIMEOUT 62 -#define STAT_ASSOCIATING 70 -#define STAT_DEASSOCIATED 71 -#define STAT_ASSOCTIMEOUT 72 -#define STAT_NOTAIROAP 73 -#define STAT_ASSOCIATED 80 -#define STAT_LEAPING 90 -#define STAT_LEAPFAILED 91 -#define STAT_LEAPTIMEDOUT 92 -#define STAT_LEAPCOMPLETE 93 -} __packed; - -typedef struct StatsRid StatsRid; -struct StatsRid { - __le16 len; - __le16 spacer; - __le32 vals[100]; -} __packed; - -typedef struct APListRid APListRid; -struct APListRid { - __le16 len; - u8 ap[4][ETH_ALEN]; -} __packed; - -typedef struct CapabilityRid CapabilityRid; -struct CapabilityRid { - __le16 len; - char oui[3]; - char zero; - __le16 prodNum; - char manName[32]; - char prodName[16]; - char prodVer[8]; - char factoryAddr[ETH_ALEN]; - char aironetAddr[ETH_ALEN]; - __le16 radioType; - __le16 country; - char callid[ETH_ALEN]; - char supportedRates[8]; - char rxDiversity; - char txDiversity; - __le16 txPowerLevels[8]; - __le16 hardVer; - __le16 hardCap; - __le16 tempRange; - __le16 softVer; - __le16 softSubVer; - __le16 interfaceVer; - __le16 softCap; - __le16 bootBlockVer; - __le16 requiredHard; - __le16 extSoftCap; -} __packed; - -/* Only present on firmware >= 5.30.17 */ -typedef struct BSSListRidExtra BSSListRidExtra; -struct BSSListRidExtra { - __le16 unknown[4]; - u8 fixed[12]; /* WLAN management frame */ - u8 iep[624]; -} __packed; - -typedef struct BSSListRid BSSListRid; -struct BSSListRid { - __le16 len; - __le16 index; /* First is 0 and 0xffff means end of list */ -#define RADIO_FH 1 /* Frequency hopping radio type */ -#define RADIO_DS 2 /* Direct sequence radio type */ -#define RADIO_TMA 4 /* Proprietary radio used in old cards (2500) */ - __le16 radioType; - u8 bssid[ETH_ALEN]; /* Mac address of the BSS */ - u8 zero; - u8 ssidLen; - u8 ssid[32]; - __le16 dBm; -#define CAP_ESS cpu_to_le16(1<<0) -#define CAP_IBSS cpu_to_le16(1<<1) -#define CAP_PRIVACY cpu_to_le16(1<<4) -#define CAP_SHORTHDR cpu_to_le16(1<<5) - __le16 cap; - __le16 beaconInterval; - u8 rates[8]; /* Same as rates for config rid */ - struct { /* For frequency hopping only */ - __le16 dwell; - u8 hopSet; - u8 hopPattern; - u8 hopIndex; - u8 fill; - } fh; - __le16 dsChannel; - __le16 atimWindow; - - /* Only present on firmware >= 5.30.17 */ - BSSListRidExtra extra; -} __packed; - -typedef struct { - BSSListRid bss; - struct list_head list; -} BSSListElement; - -typedef struct tdsRssiEntry tdsRssiEntry; -struct tdsRssiEntry { - u8 rssipct; - u8 rssidBm; -} __packed; - -typedef struct tdsRssiRid tdsRssiRid; -struct tdsRssiRid { - u16 len; - tdsRssiEntry x[256]; -} __packed; - -typedef struct MICRid MICRid; -struct MICRid { - __le16 len; - __le16 state; - __le16 multicastValid; - u8 multicast[16]; - __le16 unicastValid; - u8 unicast[16]; -} __packed; - -typedef struct MICBuffer MICBuffer; -struct MICBuffer { - __be16 typelen; - - union { - u8 snap[8]; - struct { - u8 dsap; - u8 ssap; - u8 control; - u8 orgcode[3]; - u8 fieldtype[2]; - } llc; - } u; - __be32 mic; - __be32 seq; -} __packed; - -typedef struct { - u8 da[ETH_ALEN]; - u8 sa[ETH_ALEN]; -} etherHead; - -#define TXCTL_TXOK (1<<1) /* report if tx is ok */ -#define TXCTL_TXEX (1<<2) /* report if tx fails */ -#define TXCTL_802_3 (0<<3) /* 802.3 packet */ -#define TXCTL_802_11 (1<<3) /* 802.11 mac packet */ -#define TXCTL_ETHERNET (0<<4) /* payload has ethertype */ -#define TXCTL_LLC (1<<4) /* payload is llc */ -#define TXCTL_RELEASE (0<<5) /* release after completion */ -#define TXCTL_NORELEASE (1<<5) /* on completion returns to host */ - -#define BUSY_FID 0x10000 - -#ifdef CISCO_EXT -#define AIROMAGIC 0xa55a -/* Warning : SIOCDEVPRIVATE may disapear during 2.5.X - Jean II */ -#ifdef SIOCIWFIRSTPRIV -#ifdef SIOCDEVPRIVATE -#define AIROOLDIOCTL SIOCDEVPRIVATE -#define AIROOLDIDIFC AIROOLDIOCTL + 1 -#endif /* SIOCDEVPRIVATE */ -#else /* SIOCIWFIRSTPRIV */ -#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE -#endif /* SIOCIWFIRSTPRIV */ -/* This may be wrong. When using the new SIOCIWFIRSTPRIV range, we probably - * should use only "GET" ioctls (last bit set to 1). "SET" ioctls are root - * only and don't return the modified struct ifreq to the application which - * is usually a problem. - Jean II */ -#define AIROIOCTL SIOCIWFIRSTPRIV -#define AIROIDIFC AIROIOCTL + 1 - -/* Ioctl constants to be used in airo_ioctl.command */ - -#define AIROGCAP 0 // Capability rid -#define AIROGCFG 1 // USED A LOT -#define AIROGSLIST 2 // System ID list -#define AIROGVLIST 3 // List of specified AP's -#define AIROGDRVNAM 4 // NOTUSED -#define AIROGEHTENC 5 // NOTUSED -#define AIROGWEPKTMP 6 -#define AIROGWEPKNV 7 -#define AIROGSTAT 8 -#define AIROGSTATSC32 9 -#define AIROGSTATSD32 10 -#define AIROGMICRID 11 -#define AIROGMICSTATS 12 -#define AIROGFLAGS 13 -#define AIROGID 14 -#define AIRORRID 15 -#define AIRORSWVERSION 17 - -/* Leave gap of 40 commands after AIROGSTATSD32 for future */ - -#define AIROPCAP AIROGSTATSD32 + 40 -#define AIROPVLIST AIROPCAP + 1 -#define AIROPSLIST AIROPVLIST + 1 -#define AIROPCFG AIROPSLIST + 1 -#define AIROPSIDS AIROPCFG + 1 -#define AIROPAPLIST AIROPSIDS + 1 -#define AIROPMACON AIROPAPLIST + 1 /* Enable mac */ -#define AIROPMACOFF AIROPMACON + 1 /* Disable mac */ -#define AIROPSTCLR AIROPMACOFF + 1 -#define AIROPWEPKEY AIROPSTCLR + 1 -#define AIROPWEPKEYNV AIROPWEPKEY + 1 -#define AIROPLEAPPWD AIROPWEPKEYNV + 1 -#define AIROPLEAPUSR AIROPLEAPPWD + 1 - -/* Flash codes */ - -#define AIROFLSHRST AIROPWEPKEYNV + 40 -#define AIROFLSHGCHR AIROFLSHRST + 1 -#define AIROFLSHSTFL AIROFLSHGCHR + 1 -#define AIROFLSHPCHR AIROFLSHSTFL + 1 -#define AIROFLPUTBUF AIROFLSHPCHR + 1 -#define AIRORESTART AIROFLPUTBUF + 1 - -#define FLASHSIZE 32768 -#define AUXMEMSIZE (256 * 1024) - -typedef struct aironet_ioctl { - unsigned short command; // What to do - unsigned short len; // Len of data - unsigned short ridnum; // rid number - unsigned char __user *data; // d-data -} aironet_ioctl; - -static const char swversion[] = "2.1"; -#endif /* CISCO_EXT */ - -#define NUM_MODULES 2 -#define MIC_MSGLEN_MAX 2400 -#define EMMH32_MSGLEN_MAX MIC_MSGLEN_MAX -#define AIRO_DEF_MTU 2312 - -typedef struct { - u32 size; // size - u8 enabled; // MIC enabled or not - u32 rxSuccess; // successful packets received - u32 rxIncorrectMIC; // pkts dropped due to incorrect MIC comparison - u32 rxNotMICed; // pkts dropped due to not being MIC'd - u32 rxMICPlummed; // pkts dropped due to not having a MIC plummed - u32 rxWrongSequence; // pkts dropped due to sequence number violation - u32 reserve[32]; -} mic_statistics; - -typedef struct { - __be32 coeff[((EMMH32_MSGLEN_MAX)+3)>>2]; - u64 accum; // accumulated mic, reduced to u32 in final() - int position; // current position (byte offset) in message - union { - u8 d8[4]; - __be32 d32; - } part; // saves partial message word across update() calls -} emmh32_context; - -typedef struct { - emmh32_context seed; // Context - the seed - u32 rx; // Received sequence number - u32 tx; // Tx sequence number - u32 window; // Start of window - u8 valid; // Flag to say if context is valid or not - u8 key[16]; -} miccntx; - -typedef struct { - miccntx mCtx; // Multicast context - miccntx uCtx; // Unicast context -} mic_module; - -typedef struct { - unsigned int rid: 16; - unsigned int len: 15; - unsigned int valid: 1; - dma_addr_t host_addr; -} Rid; - -typedef struct { - unsigned int offset: 15; - unsigned int eoc: 1; - unsigned int len: 15; - unsigned int valid: 1; - dma_addr_t host_addr; -} TxFid; - -struct rx_hdr { - __le16 status, len; - u8 rssi[2]; - u8 rate; - u8 freq; - __le16 tmp[4]; -} __packed; - -typedef struct { - unsigned int ctl: 15; - unsigned int rdy: 1; - unsigned int len: 15; - unsigned int valid: 1; - dma_addr_t host_addr; -} RxFid; - -/* - * Host receive descriptor - */ -typedef struct { - unsigned char __iomem *card_ram_off; /* offset into card memory of the - desc */ - RxFid rx_desc; /* card receive descriptor */ - char *virtual_host_addr; /* virtual address of host receive - buffer */ - int pending; -} HostRxDesc; - -/* - * Host transmit descriptor - */ -typedef struct { - unsigned char __iomem *card_ram_off; /* offset into card memory of the - desc */ - TxFid tx_desc; /* card transmit descriptor */ - char *virtual_host_addr; /* virtual address of host receive - buffer */ - int pending; -} HostTxDesc; - -/* - * Host RID descriptor - */ -typedef struct { - unsigned char __iomem *card_ram_off; /* offset into card memory of the - descriptor */ - Rid rid_desc; /* card RID descriptor */ - char *virtual_host_addr; /* virtual address of host receive - buffer */ -} HostRidDesc; - -typedef struct { - u16 sw0; - u16 sw1; - u16 status; - u16 len; -#define HOST_SET (1 << 0) -#define HOST_INT_TX (1 << 1) /* Interrupt on successful TX */ -#define HOST_INT_TXERR (1 << 2) /* Interrupt on unseccessful TX */ -#define HOST_LCC_PAYLOAD (1 << 4) /* LLC payload, 0 = Ethertype */ -#define HOST_DONT_RLSE (1 << 5) /* Don't release buffer when done */ -#define HOST_DONT_RETRY (1 << 6) /* Don't retry trasmit */ -#define HOST_CLR_AID (1 << 7) /* clear AID failure */ -#define HOST_RTS (1 << 9) /* Force RTS use */ -#define HOST_SHORT (1 << 10) /* Do short preamble */ - u16 ctl; - u16 aid; - u16 retries; - u16 fill; -} TxCtlHdr; - -typedef struct { - u16 ctl; - u16 duration; - char addr1[6]; - char addr2[6]; - char addr3[6]; - u16 seq; - char addr4[6]; -} WifiHdr; - - -typedef struct { - TxCtlHdr ctlhdr; - u16 fill1; - u16 fill2; - WifiHdr wifihdr; - u16 gaplen; - u16 status; -} WifiCtlHdr; - -static WifiCtlHdr wifictlhdr8023 = { - .ctlhdr = { - .ctl = HOST_DONT_RLSE, - } -}; - -// A few details needed for WEP (Wireless Equivalent Privacy) -#define MAX_KEY_SIZE 13 // 128 (?) bits -#define MIN_KEY_SIZE 5 // 40 bits RC4 - WEP -typedef struct wep_key_t { - u16 len; - u8 key[16]; /* 40-bit and 104-bit keys */ -} wep_key_t; - -/* List of Wireless Handlers (new API) */ -static const struct iw_handler_def airo_handler_def; - -static const char version[] = "airo.c 0.6 (Ben Reed & Javier Achirica)"; - -struct airo_info; - -static int get_dec_u16(char *buffer, int *start, int limit); -static void OUT4500(struct airo_info *, u16 reg, u16 value); -static unsigned short IN4500(struct airo_info *, u16 reg); -static u16 setup_card(struct airo_info*, struct net_device *dev, int lock); -static int enable_MAC(struct airo_info *ai, int lock); -static void disable_MAC(struct airo_info *ai, int lock); -static void enable_interrupts(struct airo_info*); -static void disable_interrupts(struct airo_info*); -static u16 issuecommand(struct airo_info*, Cmd *pCmd, Resp *pRsp, - bool may_sleep); -static int bap_setup(struct airo_info*, u16 rid, u16 offset, int whichbap); -static int aux_bap_read(struct airo_info*, __le16 *pu16Dst, int bytelen, - int whichbap); -static int fast_bap_read(struct airo_info*, __le16 *pu16Dst, int bytelen, - int whichbap); -static int bap_write(struct airo_info*, const __le16 *pu16Src, int bytelen, - int whichbap); -static int PC4500_accessrid(struct airo_info*, u16 rid, u16 accmd); -static int PC4500_readrid(struct airo_info*, u16 rid, void *pBuf, int len, int lock); -static int PC4500_writerid(struct airo_info*, u16 rid, const void - *pBuf, int len, int lock); -static int do_writerid(struct airo_info*, u16 rid, const void *rid_data, - int len, int dummy); -static u16 transmit_allocate(struct airo_info*, int lenPayload, int raw); -static int transmit_802_3_packet(struct airo_info*, int len, char *pPacket, - bool may_sleep); -static int transmit_802_11_packet(struct airo_info*, int len, char *pPacket, - bool may_sleep); - -static int mpi_send_packet(struct net_device *dev); -static void mpi_unmap_card(struct pci_dev *pci); -static void mpi_receive_802_3(struct airo_info *ai); -static void mpi_receive_802_11(struct airo_info *ai); -static int waitbusy(struct airo_info *ai); - -static irqreturn_t airo_interrupt(int irq, void* dev_id); -static int airo_thread(void *data); -static void timer_func(struct net_device *dev); -static int airo_siocdevprivate(struct net_device *dev, struct ifreq *rq, void __user *, int cmd); -static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev); -#ifdef CISCO_EXT -static int readrids(struct net_device *dev, aironet_ioctl *comp); -static int writerids(struct net_device *dev, aironet_ioctl *comp); -static int flashcard(struct net_device *dev, aironet_ioctl *comp); -#endif /* CISCO_EXT */ -static void micinit(struct airo_info *ai); -static int micsetup(struct airo_info *ai); -static int encapsulate(struct airo_info *ai, etherHead *pPacket, MICBuffer *buffer, int len); -static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *pPacket, u16 payLen); - -static u8 airo_rssi_to_dbm(tdsRssiEntry *rssi_rid, u8 rssi); -static u8 airo_dbm_to_pct(tdsRssiEntry *rssi_rid, u8 dbm); - -static void airo_networks_free(struct airo_info *ai); - -struct airo_info { - struct net_device *dev; - struct list_head dev_list; - /* Note, we can have MAX_FIDS outstanding. FIDs are 16-bits, so we - use the high bit to mark whether it is in use. */ -#define MAX_FIDS 6 -#define MPI_MAX_FIDS 1 - u32 fids[MAX_FIDS]; - ConfigRid config; - char keyindex; // Used with auto wep - char defindex; // Used with auto wep - struct proc_dir_entry *proc_entry; - spinlock_t aux_lock; -#define FLAG_RADIO_OFF 0 /* User disabling of MAC */ -#define FLAG_RADIO_DOWN 1 /* ifup/ifdown disabling of MAC */ -#define FLAG_RADIO_MASK 0x03 -#define FLAG_ENABLED 2 -#define FLAG_ADHOC 3 /* Needed by MIC */ -#define FLAG_MIC_CAPABLE 4 -#define FLAG_UPDATE_MULTI 5 -#define FLAG_UPDATE_UNI 6 -#define FLAG_802_11 7 -#define FLAG_PROMISC 8 /* IFF_PROMISC 0x100 - include/linux/if.h */ -#define FLAG_PENDING_XMIT 9 -#define FLAG_PENDING_XMIT11 10 -#define FLAG_MPI 11 -#define FLAG_REGISTERED 12 -#define FLAG_COMMIT 13 -#define FLAG_RESET 14 -#define FLAG_FLASHING 15 -#define FLAG_WPA_CAPABLE 16 - unsigned long flags; -#define JOB_DIE 0 -#define JOB_XMIT 1 -#define JOB_XMIT11 2 -#define JOB_STATS 3 -#define JOB_PROMISC 4 -#define JOB_MIC 5 -#define JOB_EVENT 6 -#define JOB_AUTOWEP 7 -#define JOB_SCAN_RESULTS 9 - unsigned long jobs; - int (*bap_read)(struct airo_info*, __le16 *pu16Dst, int bytelen, - int whichbap); - unsigned short *flash; - tdsRssiEntry *rssi; - struct task_struct *list_bss_task; - struct task_struct *airo_thread_task; - struct semaphore sem; - wait_queue_head_t thr_wait; - unsigned long expires; - struct { - struct sk_buff *skb; - int fid; - } xmit, xmit11; - struct net_device *wifidev; - struct iw_statistics wstats; // wireless stats - unsigned long scan_timeout; /* Time scan should be read */ - struct iw_spy_data spy_data; - struct iw_public_data wireless_data; - /* MIC stuff */ - struct crypto_sync_skcipher *tfm; - mic_module mod[2]; - mic_statistics micstats; - HostRxDesc rxfids[MPI_MAX_FIDS]; // rx/tx/config MPI350 descriptors - HostTxDesc txfids[MPI_MAX_FIDS]; - HostRidDesc config_desc; - unsigned long ridbus; // phys addr of config_desc - struct sk_buff_head txq;// tx queue used by mpi350 code - struct pci_dev *pci; - unsigned char __iomem *pcimem; - unsigned char __iomem *pciaux; - unsigned char *shared; - dma_addr_t shared_dma; - pm_message_t power; - SsidRid *SSID; - APListRid APList; -#define PCI_SHARED_LEN 2*MPI_MAX_FIDS*PKTSIZE+RIDSIZE - char proc_name[IFNAMSIZ]; - - int wep_capable; - int max_wep_idx; - int last_auth; - - /* WPA-related stuff */ - unsigned int bssListFirst; - unsigned int bssListNext; - unsigned int bssListRidLen; - - struct list_head network_list; - struct list_head network_free_list; - BSSListElement *networks; -}; - -static inline int bap_read(struct airo_info *ai, __le16 *pu16Dst, int bytelen, - int whichbap) -{ - return ai->bap_read(ai, pu16Dst, bytelen, whichbap); -} - -static int setup_proc_entry(struct net_device *dev, - struct airo_info *apriv); -static int takedown_proc_entry(struct net_device *dev, - struct airo_info *apriv); - -static int cmdreset(struct airo_info *ai); -static int setflashmode(struct airo_info *ai); -static int flashgchar(struct airo_info *ai, int matchbyte, int dwelltime); -static int flashputbuf(struct airo_info *ai); -static int flashrestart(struct airo_info *ai, struct net_device *dev); - -#define airo_print(type, name, fmt, args...) \ - printk(type DRV_NAME "(%s): " fmt "\n", name, ##args) - -#define airo_print_info(name, fmt, args...) \ - airo_print(KERN_INFO, name, fmt, ##args) - -#define airo_print_dbg(name, fmt, args...) \ - airo_print(KERN_DEBUG, name, fmt, ##args) - -#define airo_print_warn(name, fmt, args...) \ - airo_print(KERN_WARNING, name, fmt, ##args) - -#define airo_print_err(name, fmt, args...) \ - airo_print(KERN_ERR, name, fmt, ##args) - -#define AIRO_FLASH(dev) (((struct airo_info *)dev->ml_priv)->flash) - -/*********************************************************************** - * MIC ROUTINES * - *********************************************************************** - */ - -static int RxSeqValid(struct airo_info *ai, miccntx *context, int mcast, u32 micSeq); -static void MoveWindow(miccntx *context, u32 micSeq); -static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, - struct crypto_sync_skcipher *tfm); -static void emmh32_init(emmh32_context *context); -static void emmh32_update(emmh32_context *context, u8 *pOctets, int len); -static void emmh32_final(emmh32_context *context, u8 digest[4]); -static int flashpchar(struct airo_info *ai, int byte, int dwelltime); - -static void age_mic_context(miccntx *cur, miccntx *old, u8 *key, int key_len, - struct crypto_sync_skcipher *tfm) -{ - /* If the current MIC context is valid and its key is the same as - * the MIC register, there's nothing to do. - */ - if (cur->valid && (memcmp(cur->key, key, key_len) == 0)) - return; - - /* Age current mic Context */ - memcpy(old, cur, sizeof(*cur)); - - /* Initialize new context */ - memcpy(cur->key, key, key_len); - cur->window = 33; /* Window always points to the middle */ - cur->rx = 0; /* Rx Sequence numbers */ - cur->tx = 0; /* Tx sequence numbers */ - cur->valid = 1; /* Key is now valid */ - - /* Give key to mic seed */ - emmh32_setseed(&cur->seed, key, key_len, tfm); -} - -/* micinit - Initialize mic seed */ - -static void micinit(struct airo_info *ai) -{ - MICRid mic_rid; - - clear_bit(JOB_MIC, &ai->jobs); - PC4500_readrid(ai, RID_MIC, &mic_rid, sizeof(mic_rid), 0); - up(&ai->sem); - - ai->micstats.enabled = (le16_to_cpu(mic_rid.state) & 0x00FF) ? 1 : 0; - if (!ai->micstats.enabled) { - /* So next time we have a valid key and mic is enabled, we will - * update the sequence number if the key is the same as before. - */ - ai->mod[0].uCtx.valid = 0; - ai->mod[0].mCtx.valid = 0; - return; - } - - if (mic_rid.multicastValid) { - age_mic_context(&ai->mod[0].mCtx, &ai->mod[1].mCtx, - mic_rid.multicast, sizeof(mic_rid.multicast), - ai->tfm); - } - - if (mic_rid.unicastValid) { - age_mic_context(&ai->mod[0].uCtx, &ai->mod[1].uCtx, - mic_rid.unicast, sizeof(mic_rid.unicast), - ai->tfm); - } -} - -/* micsetup - Get ready for business */ - -static int micsetup(struct airo_info *ai) -{ - int i; - - if (ai->tfm == NULL) - ai->tfm = crypto_alloc_sync_skcipher("ctr(aes)", 0, 0); - - if (IS_ERR(ai->tfm)) { - airo_print_err(ai->dev->name, "failed to load transform for AES"); - ai->tfm = NULL; - return ERROR; - } - - for (i = 0; i < NUM_MODULES; i++) { - memset(&ai->mod[i].mCtx, 0, sizeof(miccntx)); - memset(&ai->mod[i].uCtx, 0, sizeof(miccntx)); - } - return SUCCESS; -} - -static const u8 micsnap[] = {0xAA, 0xAA, 0x03, 0x00, 0x40, 0x96, 0x00, 0x02}; - -/*=========================================================================== - * Description: Mic a packet - * - * Inputs: etherHead * pointer to an 802.3 frame - * - * Returns: BOOLEAN if successful, otherwise false. - * PacketTxLen will be updated with the mic'd packets size. - * - * Caveats: It is assumed that the frame buffer will already - * be big enough to hold the largets mic message possible. - * (No memory allocation is done here). - * - * Author: sbraneky (10/15/01) - * Merciless hacks by rwilcher (1/14/02) - */ - -static int encapsulate(struct airo_info *ai, etherHead *frame, MICBuffer *mic, int payLen) -{ - miccntx *context; - - // Determine correct context - // If not adhoc, always use unicast key - - if (test_bit(FLAG_ADHOC, &ai->flags) && (frame->da[0] & 0x1)) - context = &ai->mod[0].mCtx; - else - context = &ai->mod[0].uCtx; - - if (!context->valid) - return ERROR; - - mic->typelen = htons(payLen + 16); //Length of Mic'd packet - - memcpy(&mic->u.snap, micsnap, sizeof(micsnap)); // Add Snap - - // Add Tx sequence - mic->seq = htonl(context->tx); - context->tx += 2; - - emmh32_init(&context->seed); // Mic the packet - emmh32_update(&context->seed, frame->da, ETH_ALEN * 2); // DA, SA - emmh32_update(&context->seed, (u8*)&mic->typelen, 10); // Type/Length and Snap - emmh32_update(&context->seed, (u8*)&mic->seq, sizeof(mic->seq)); //SEQ - emmh32_update(&context->seed, (u8*)(frame + 1), payLen); //payload - emmh32_final(&context->seed, (u8*)&mic->mic); - - /* New Type/length ?????????? */ - mic->typelen = 0; //Let NIC know it could be an oversized packet - return SUCCESS; -} - -typedef enum { - NONE, - NOMIC, - NOMICPLUMMED, - SEQUENCE, - INCORRECTMIC, -} mic_error; - -/*=========================================================================== - * Description: Decapsulates a MIC'd packet and returns the 802.3 packet - * (removes the MIC stuff) if packet is a valid packet. - * - * Inputs: etherHead pointer to the 802.3 packet - * - * Returns: BOOLEAN - TRUE if packet should be dropped otherwise FALSE - * - * Author: sbraneky (10/15/01) - * Merciless hacks by rwilcher (1/14/02) - *--------------------------------------------------------------------------- - */ - -static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *eth, u16 payLen) -{ - int i; - u32 micSEQ; - miccntx *context; - u8 digest[4]; - mic_error micError = NONE; - - // Check if the packet is a Mic'd packet - - if (!ai->micstats.enabled) { - //No Mic set or Mic OFF but we received a MIC'd packet. - if (memcmp ((u8*)eth + 14, micsnap, sizeof(micsnap)) == 0) { - ai->micstats.rxMICPlummed++; - return ERROR; - } - return SUCCESS; - } - - if (ntohs(mic->typelen) == 0x888E) - return SUCCESS; - - if (memcmp (mic->u.snap, micsnap, sizeof(micsnap)) != 0) { - // Mic enabled but packet isn't Mic'd - ai->micstats.rxMICPlummed++; - return ERROR; - } - - micSEQ = ntohl(mic->seq); //store SEQ as CPU order - - //At this point we a have a mic'd packet and mic is enabled - //Now do the mic error checking. - - //Receive seq must be odd - if ((micSEQ & 1) == 0) { - ai->micstats.rxWrongSequence++; - return ERROR; - } - - for (i = 0; i < NUM_MODULES; i++) { - int mcast = eth->da[0] & 1; - //Determine proper context - context = mcast ? &ai->mod[i].mCtx : &ai->mod[i].uCtx; - - //Make sure context is valid - if (!context->valid) { - if (i == 0) - micError = NOMICPLUMMED; - continue; - } - //DeMic it - - if (!mic->typelen) - mic->typelen = htons(payLen + sizeof(MICBuffer) - 2); - - emmh32_init(&context->seed); - emmh32_update(&context->seed, eth->da, ETH_ALEN*2); - emmh32_update(&context->seed, (u8 *)&mic->typelen, sizeof(mic->typelen)+sizeof(mic->u.snap)); - emmh32_update(&context->seed, (u8 *)&mic->seq, sizeof(mic->seq)); - emmh32_update(&context->seed, (u8 *)(eth + 1), payLen); - //Calculate MIC - emmh32_final(&context->seed, digest); - - if (memcmp(digest, &mic->mic, 4)) { //Make sure the mics match - //Invalid Mic - if (i == 0) - micError = INCORRECTMIC; - continue; - } - - //Check Sequence number if mics pass - if (RxSeqValid(ai, context, mcast, micSEQ) == SUCCESS) { - ai->micstats.rxSuccess++; - return SUCCESS; - } - if (i == 0) - micError = SEQUENCE; - } - - // Update statistics - switch (micError) { - case NOMICPLUMMED: ai->micstats.rxMICPlummed++; break; - case SEQUENCE: ai->micstats.rxWrongSequence++; break; - case INCORRECTMIC: ai->micstats.rxIncorrectMIC++; break; - case NONE: break; - case NOMIC: break; - } - return ERROR; -} - -/*=========================================================================== - * Description: Checks the Rx Seq number to make sure it is valid - * and hasn't already been received - * - * Inputs: miccntx - mic context to check seq against - * micSeq - the Mic seq number - * - * Returns: TRUE if valid otherwise FALSE. - * - * Author: sbraneky (10/15/01) - * Merciless hacks by rwilcher (1/14/02) - *--------------------------------------------------------------------------- - */ - -static int RxSeqValid(struct airo_info *ai, miccntx *context, int mcast, u32 micSeq) -{ - u32 seq, index; - - //Allow for the ap being rebooted - if it is then use the next - //sequence number of the current sequence number - might go backwards - - if (mcast) { - if (test_bit(FLAG_UPDATE_MULTI, &ai->flags)) { - clear_bit (FLAG_UPDATE_MULTI, &ai->flags); - context->window = (micSeq > 33) ? micSeq : 33; - context->rx = 0; // Reset rx - } - } else if (test_bit(FLAG_UPDATE_UNI, &ai->flags)) { - clear_bit (FLAG_UPDATE_UNI, &ai->flags); - context->window = (micSeq > 33) ? micSeq : 33; // Move window - context->rx = 0; // Reset rx - } - - //Make sequence number relative to START of window - seq = micSeq - (context->window - 33); - - //Too old of a SEQ number to check. - if ((s32)seq < 0) - return ERROR; - - if (seq > 64) { - //Window is infinite forward - MoveWindow(context, micSeq); - return SUCCESS; - } - - // We are in the window. Now check the context rx bit to see if it was already sent - seq >>= 1; //divide by 2 because we only have odd numbers - index = 1 << seq; //Get an index number - - if (!(context->rx & index)) { - //micSEQ falls inside the window. - //Add seqence number to the list of received numbers. - context->rx |= index; - - MoveWindow(context, micSeq); - - return SUCCESS; - } - return ERROR; -} - -static void MoveWindow(miccntx *context, u32 micSeq) -{ - u32 shift; - - //Move window if seq greater than the middle of the window - if (micSeq > context->window) { - shift = (micSeq - context->window) >> 1; - - //Shift out old - if (shift < 32) - context->rx >>= shift; - else - context->rx = 0; - - context->window = micSeq; //Move window - } -} - -/*==============================================*/ -/*========== EMMH ROUTINES ====================*/ -/*==============================================*/ - -/* mic accumulate */ -#define MIC_ACCUM(val) \ - context->accum += (u64)(val) * be32_to_cpu(context->coeff[coeff_position++]); - -/* expand the key to fill the MMH coefficient array */ -static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, - struct crypto_sync_skcipher *tfm) -{ - /* take the keying material, expand if necessary, truncate at 16-bytes */ - /* run through AES counter mode to generate context->coeff[] */ - - SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm); - struct scatterlist sg; - u8 iv[AES_BLOCK_SIZE] = {}; - int ret; - - crypto_sync_skcipher_setkey(tfm, pkey, 16); - - memset(context->coeff, 0, sizeof(context->coeff)); - sg_init_one(&sg, context->coeff, sizeof(context->coeff)); - - skcipher_request_set_sync_tfm(req, tfm); - skcipher_request_set_callback(req, 0, NULL, NULL); - skcipher_request_set_crypt(req, &sg, &sg, sizeof(context->coeff), iv); - - ret = crypto_skcipher_encrypt(req); - WARN_ON_ONCE(ret); -} - -/* prepare for calculation of a new mic */ -static void emmh32_init(emmh32_context *context) -{ - /* prepare for new mic calculation */ - context->accum = 0; - context->position = 0; -} - -/* add some bytes to the mic calculation */ -static void emmh32_update(emmh32_context *context, u8 *pOctets, int len) -{ - int coeff_position, byte_position; - - if (len == 0) return; - - coeff_position = context->position >> 2; - - /* deal with partial 32-bit word left over from last update */ - byte_position = context->position & 3; - if (byte_position) { - /* have a partial word in part to deal with */ - do { - if (len == 0) return; - context->part.d8[byte_position++] = *pOctets++; - context->position++; - len--; - } while (byte_position < 4); - MIC_ACCUM(ntohl(context->part.d32)); - } - - /* deal with full 32-bit words */ - while (len >= 4) { - MIC_ACCUM(ntohl(*(__be32 *)pOctets)); - context->position += 4; - pOctets += 4; - len -= 4; - } - - /* deal with partial 32-bit word that will be left over from this update */ - byte_position = 0; - while (len > 0) { - context->part.d8[byte_position++] = *pOctets++; - context->position++; - len--; - } -} - -/* mask used to zero empty bytes for final partial word */ -static u32 mask32[4] = { 0x00000000L, 0xFF000000L, 0xFFFF0000L, 0xFFFFFF00L }; - -/* calculate the mic */ -static void emmh32_final(emmh32_context *context, u8 digest[4]) -{ - int coeff_position, byte_position; - u32 val; - - u64 sum, utmp; - s64 stmp; - - coeff_position = context->position >> 2; - - /* deal with partial 32-bit word left over from last update */ - byte_position = context->position & 3; - if (byte_position) { - /* have a partial word in part to deal with */ - val = ntohl(context->part.d32); - MIC_ACCUM(val & mask32[byte_position]); /* zero empty bytes */ - } - - /* reduce the accumulated u64 to a 32-bit MIC */ - sum = context->accum; - stmp = (sum & 0xffffffffLL) - ((sum >> 32) * 15); - utmp = (stmp & 0xffffffffLL) - ((stmp >> 32) * 15); - sum = utmp & 0xffffffffLL; - if (utmp > 0x10000000fLL) - sum -= 15; - - val = (u32)sum; - digest[0] = (val>>24) & 0xFF; - digest[1] = (val>>16) & 0xFF; - digest[2] = (val>>8) & 0xFF; - digest[3] = val & 0xFF; -} - -static int readBSSListRid(struct airo_info *ai, int first, - BSSListRid *list) -{ - Cmd cmd; - Resp rsp; - - if (first == 1) { - if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN; - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd = CMD_LISTBSS; - if (down_interruptible(&ai->sem)) - return -ERESTARTSYS; - ai->list_bss_task = current; - issuecommand(ai, &cmd, &rsp, true); - up(&ai->sem); - /* Let the command take effect */ - schedule_timeout_uninterruptible(3 * HZ); - ai->list_bss_task = NULL; - } - return PC4500_readrid(ai, first ? ai->bssListFirst : ai->bssListNext, - list, ai->bssListRidLen, 1); -} - -static int readWepKeyRid(struct airo_info *ai, WepKeyRid *wkr, int temp, int lock) -{ - return PC4500_readrid(ai, temp ? RID_WEP_TEMP : RID_WEP_PERM, - wkr, sizeof(*wkr), lock); -} - -static int writeWepKeyRid(struct airo_info *ai, WepKeyRid *wkr, int perm, int lock) -{ - int rc; - rc = PC4500_writerid(ai, RID_WEP_TEMP, wkr, sizeof(*wkr), lock); - if (rc!=SUCCESS) - airo_print_err(ai->dev->name, "WEP_TEMP set %x", rc); - if (perm) { - rc = PC4500_writerid(ai, RID_WEP_PERM, wkr, sizeof(*wkr), lock); - if (rc!=SUCCESS) - airo_print_err(ai->dev->name, "WEP_PERM set %x", rc); - } - return rc; -} - -static int readSsidRid(struct airo_info*ai, SsidRid *ssidr) -{ - return PC4500_readrid(ai, RID_SSID, ssidr, sizeof(*ssidr), 1); -} - -static int writeSsidRid(struct airo_info*ai, SsidRid *pssidr, int lock) -{ - return PC4500_writerid(ai, RID_SSID, pssidr, sizeof(*pssidr), lock); -} - -static int readConfigRid(struct airo_info *ai, int lock) -{ - int rc; - ConfigRid cfg; - - if (ai->config.len) - return SUCCESS; - - rc = PC4500_readrid(ai, RID_ACTUALCONFIG, &cfg, sizeof(cfg), lock); - if (rc != SUCCESS) - return rc; - - ai->config = cfg; - return SUCCESS; -} - -static inline void checkThrottle(struct airo_info *ai) -{ - int i; -/* Old hardware had a limit on encryption speed */ - if (ai->config.authType != AUTH_OPEN && maxencrypt) { - for (i = 0; i<8; i++) { - if (ai->config.rates[i] > maxencrypt) { - ai->config.rates[i] = 0; - } - } - } -} - -static int writeConfigRid(struct airo_info *ai, int lock) -{ - ConfigRid cfgr; - - if (!test_bit (FLAG_COMMIT, &ai->flags)) - return SUCCESS; - - clear_bit (FLAG_COMMIT, &ai->flags); - clear_bit (FLAG_RESET, &ai->flags); - checkThrottle(ai); - cfgr = ai->config; - - if ((cfgr.opmode & MODE_CFG_MASK) == MODE_STA_IBSS) - set_bit(FLAG_ADHOC, &ai->flags); - else - clear_bit(FLAG_ADHOC, &ai->flags); - - return PC4500_writerid(ai, RID_CONFIG, &cfgr, sizeof(cfgr), lock); -} - -static int readStatusRid(struct airo_info *ai, StatusRid *statr, int lock) -{ - return PC4500_readrid(ai, RID_STATUS, statr, sizeof(*statr), lock); -} - -static int writeAPListRid(struct airo_info *ai, APListRid *aplr, int lock) -{ - return PC4500_writerid(ai, RID_APLIST, aplr, sizeof(*aplr), lock); -} - -static int readCapabilityRid(struct airo_info *ai, CapabilityRid *capr, int lock) -{ - return PC4500_readrid(ai, RID_CAPABILITIES, capr, sizeof(*capr), lock); -} - -static int readStatsRid(struct airo_info*ai, StatsRid *sr, int rid, int lock) -{ - return PC4500_readrid(ai, rid, sr, sizeof(*sr), lock); -} - -static void try_auto_wep(struct airo_info *ai) -{ - if (auto_wep && !test_bit(FLAG_RADIO_DOWN, &ai->flags)) { - ai->expires = RUN_AT(3*HZ); - wake_up_interruptible(&ai->thr_wait); - } -} - -static int airo_open(struct net_device *dev) -{ - struct airo_info *ai = dev->ml_priv; - int rc = 0; - - if (test_bit(FLAG_FLASHING, &ai->flags)) - return -EIO; - - /* Make sure the card is configured. - * Wireless Extensions may postpone config changes until the card - * is open (to pipeline changes and speed-up card setup). If - * those changes are not yet committed, do it now - Jean II */ - if (test_bit(FLAG_COMMIT, &ai->flags)) { - disable_MAC(ai, 1); - writeConfigRid(ai, 1); - } - - if (ai->wifidev != dev) { - clear_bit(JOB_DIE, &ai->jobs); - ai->airo_thread_task = kthread_run(airo_thread, dev, "%s", - dev->name); - if (IS_ERR(ai->airo_thread_task)) - return (int)PTR_ERR(ai->airo_thread_task); - - rc = request_irq(dev->irq, airo_interrupt, IRQF_SHARED, - dev->name, dev); - if (rc) { - airo_print_err(dev->name, - "register interrupt %d failed, rc %d", - dev->irq, rc); - set_bit(JOB_DIE, &ai->jobs); - kthread_stop(ai->airo_thread_task); - return rc; - } - - /* Power on the MAC controller (which may have been disabled) */ - clear_bit(FLAG_RADIO_DOWN, &ai->flags); - enable_interrupts(ai); - - try_auto_wep(ai); - } - enable_MAC(ai, 1); - - netif_start_queue(dev); - return 0; -} - -static netdev_tx_t mpi_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - int npacks, pending; - unsigned long flags; - struct airo_info *ai = dev->ml_priv; - - if (!skb) { - airo_print_err(dev->name, "%s: skb == NULL!",__func__); - return NETDEV_TX_OK; - } - if (skb_padto(skb, ETH_ZLEN)) { - dev->stats.tx_dropped++; - return NETDEV_TX_OK; - } - npacks = skb_queue_len (&ai->txq); - - if (npacks >= MAXTXQ - 1) { - netif_stop_queue (dev); - if (npacks > MAXTXQ) { - dev->stats.tx_fifo_errors++; - return NETDEV_TX_BUSY; - } - skb_queue_tail (&ai->txq, skb); - return NETDEV_TX_OK; - } - - spin_lock_irqsave(&ai->aux_lock, flags); - skb_queue_tail (&ai->txq, skb); - pending = test_bit(FLAG_PENDING_XMIT, &ai->flags); - spin_unlock_irqrestore(&ai->aux_lock, flags); - netif_wake_queue (dev); - - if (pending == 0) { - set_bit(FLAG_PENDING_XMIT, &ai->flags); - mpi_send_packet (dev); - } - return NETDEV_TX_OK; -} - -/* - * @mpi_send_packet - * - * Attempt to transmit a packet. Can be called from interrupt - * or transmit . return number of packets we tried to send - */ - -static int mpi_send_packet (struct net_device *dev) -{ - struct sk_buff *skb; - unsigned char *buffer; - s16 len; - __le16 *payloadLen; - struct airo_info *ai = dev->ml_priv; - u8 *sendbuf; - - /* get a packet to send */ - - if ((skb = skb_dequeue(&ai->txq)) == NULL) { - airo_print_err(dev->name, - "%s: Dequeue'd zero in send_packet()", - __func__); - return 0; - } - - /* check min length*/ - len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - buffer = skb->data; - - ai->txfids[0].tx_desc.offset = 0; - ai->txfids[0].tx_desc.valid = 1; - ai->txfids[0].tx_desc.eoc = 1; - ai->txfids[0].tx_desc.len =len+sizeof(WifiHdr); - -/* - * Magic, the cards firmware needs a length count (2 bytes) in the host buffer - * right after TXFID_HDR.The TXFID_HDR contains the status short so payloadlen - * is immediately after it. ------------------------------------------------ - * |TXFIDHDR+STATUS|PAYLOADLEN|802.3HDR|PACKETDATA| - * ------------------------------------------------ - */ - - memcpy(ai->txfids[0].virtual_host_addr, - (char *)&wifictlhdr8023, sizeof(wifictlhdr8023)); - - payloadLen = (__le16 *)(ai->txfids[0].virtual_host_addr + - sizeof(wifictlhdr8023)); - sendbuf = ai->txfids[0].virtual_host_addr + - sizeof(wifictlhdr8023) + 2 ; - - /* - * Firmware automatically puts 802 header on so - * we don't need to account for it in the length - */ - if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled && - (ntohs(((__be16 *)buffer)[6]) != 0x888E)) { - MICBuffer pMic; - - if (encapsulate(ai, (etherHead *)buffer, &pMic, len - sizeof(etherHead)) != SUCCESS) - return ERROR; - - *payloadLen = cpu_to_le16(len-sizeof(etherHead)+sizeof(pMic)); - ai->txfids[0].tx_desc.len += sizeof(pMic); - /* copy data into airo dma buffer */ - memcpy (sendbuf, buffer, sizeof(etherHead)); - buffer += sizeof(etherHead); - sendbuf += sizeof(etherHead); - memcpy (sendbuf, &pMic, sizeof(pMic)); - sendbuf += sizeof(pMic); - memcpy (sendbuf, buffer, len - sizeof(etherHead)); - } else { - *payloadLen = cpu_to_le16(len - sizeof(etherHead)); - - netif_trans_update(dev); - - /* copy data into airo dma buffer */ - memcpy(sendbuf, buffer, len); - } - - memcpy_toio(ai->txfids[0].card_ram_off, - &ai->txfids[0].tx_desc, sizeof(TxFid)); - - OUT4500(ai, EVACK, 8); - - dev_kfree_skb_any(skb); - return 1; -} - -static void get_tx_error(struct airo_info *ai, s32 fid) -{ - __le16 status; - - if (fid < 0) - status = ((WifiCtlHdr *)ai->txfids[0].virtual_host_addr)->ctlhdr.status; - else { - if (bap_setup(ai, ai->fids[fid] & 0xffff, 4, BAP0) != SUCCESS) - return; - bap_read(ai, &status, 2, BAP0); - } - if (le16_to_cpu(status) & 2) /* Too many retries */ - ai->dev->stats.tx_aborted_errors++; - if (le16_to_cpu(status) & 4) /* Transmit lifetime exceeded */ - ai->dev->stats.tx_heartbeat_errors++; - if (le16_to_cpu(status) & 8) /* Aid fail */ - { } - if (le16_to_cpu(status) & 0x10) /* MAC disabled */ - ai->dev->stats.tx_carrier_errors++; - if (le16_to_cpu(status) & 0x20) /* Association lost */ - { } - /* We produce a TXDROP event only for retry or lifetime - * exceeded, because that's the only status that really mean - * that this particular node went away. - * Other errors means that *we* screwed up. - Jean II */ - if ((le16_to_cpu(status) & 2) || - (le16_to_cpu(status) & 4)) { - union iwreq_data wrqu; - char junk[0x18]; - - /* Faster to skip over useless data than to do - * another bap_setup(). We are at offset 0x6 and - * need to go to 0x18 and read 6 bytes - Jean II */ - bap_read(ai, (__le16 *) junk, 0x18, BAP0); - - /* Copy 802.11 dest address. - * We use the 802.11 header because the frame may - * not be 802.3 or may be mangled... - * In Ad-Hoc mode, it will be the node address. - * In managed mode, it will be most likely the AP addr - * User space will figure out how to convert it to - * whatever it needs (IP address or else). - * - Jean II */ - memcpy(wrqu.addr.sa_data, junk + 0x12, ETH_ALEN); - wrqu.addr.sa_family = ARPHRD_ETHER; - - /* Send event to user space */ - wireless_send_event(ai->dev, IWEVTXDROP, &wrqu, NULL); - } -} - -static void airo_end_xmit(struct net_device *dev, bool may_sleep) -{ - u16 status; - int i; - struct airo_info *priv = dev->ml_priv; - struct sk_buff *skb = priv->xmit.skb; - int fid = priv->xmit.fid; - u32 *fids = priv->fids; - - clear_bit(JOB_XMIT, &priv->jobs); - clear_bit(FLAG_PENDING_XMIT, &priv->flags); - status = transmit_802_3_packet(priv, fids[fid], skb->data, may_sleep); - up(&priv->sem); - - i = 0; - if (status == SUCCESS) { - netif_trans_update(dev); - for (; i < MAX_FIDS / 2 && (priv->fids[i] & 0xffff0000); i++); - } else { - priv->fids[fid] &= 0xffff; - dev->stats.tx_window_errors++; - } - if (i < MAX_FIDS / 2) - netif_wake_queue(dev); - dev_kfree_skb(skb); -} - -static netdev_tx_t airo_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - s16 len; - int i, j; - struct airo_info *priv = dev->ml_priv; - u32 *fids = priv->fids; - - if (skb == NULL) { - airo_print_err(dev->name, "%s: skb == NULL!", __func__); - return NETDEV_TX_OK; - } - if (skb_padto(skb, ETH_ZLEN)) { - dev->stats.tx_dropped++; - return NETDEV_TX_OK; - } - - /* Find a vacant FID */ - for (i = 0; i < MAX_FIDS / 2 && (fids[i] & 0xffff0000); i++); - for (j = i + 1; j < MAX_FIDS / 2 && (fids[j] & 0xffff0000); j++); - - if (j >= MAX_FIDS / 2) { - netif_stop_queue(dev); - - if (i == MAX_FIDS / 2) { - dev->stats.tx_fifo_errors++; - return NETDEV_TX_BUSY; - } - } - /* check min length*/ - len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - /* Mark fid as used & save length for later */ - fids[i] |= (len << 16); - priv->xmit.skb = skb; - priv->xmit.fid = i; - if (down_trylock(&priv->sem) != 0) { - set_bit(FLAG_PENDING_XMIT, &priv->flags); - netif_stop_queue(dev); - set_bit(JOB_XMIT, &priv->jobs); - wake_up_interruptible(&priv->thr_wait); - } else - airo_end_xmit(dev, false); - return NETDEV_TX_OK; -} - -static void airo_end_xmit11(struct net_device *dev, bool may_sleep) -{ - u16 status; - int i; - struct airo_info *priv = dev->ml_priv; - struct sk_buff *skb = priv->xmit11.skb; - int fid = priv->xmit11.fid; - u32 *fids = priv->fids; - - clear_bit(JOB_XMIT11, &priv->jobs); - clear_bit(FLAG_PENDING_XMIT11, &priv->flags); - status = transmit_802_11_packet(priv, fids[fid], skb->data, may_sleep); - up(&priv->sem); - - i = MAX_FIDS / 2; - if (status == SUCCESS) { - netif_trans_update(dev); - for (; i < MAX_FIDS && (priv->fids[i] & 0xffff0000); i++); - } else { - priv->fids[fid] &= 0xffff; - dev->stats.tx_window_errors++; - } - if (i < MAX_FIDS) - netif_wake_queue(dev); - dev_kfree_skb(skb); -} - -static netdev_tx_t airo_start_xmit11(struct sk_buff *skb, - struct net_device *dev) -{ - s16 len; - int i, j; - struct airo_info *priv = dev->ml_priv; - u32 *fids = priv->fids; - - if (test_bit(FLAG_MPI, &priv->flags)) { - /* Not implemented yet for MPI350 */ - netif_stop_queue(dev); - dev_kfree_skb_any(skb); - return NETDEV_TX_OK; - } - - if (skb == NULL) { - airo_print_err(dev->name, "%s: skb == NULL!", __func__); - return NETDEV_TX_OK; - } - if (skb_padto(skb, ETH_ZLEN)) { - dev->stats.tx_dropped++; - return NETDEV_TX_OK; - } - - /* Find a vacant FID */ - for (i = MAX_FIDS / 2; i < MAX_FIDS && (fids[i] & 0xffff0000); i++); - for (j = i + 1; j < MAX_FIDS && (fids[j] & 0xffff0000); j++); - - if (j >= MAX_FIDS) { - netif_stop_queue(dev); - - if (i == MAX_FIDS) { - dev->stats.tx_fifo_errors++; - return NETDEV_TX_BUSY; - } - } - /* check min length*/ - len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - /* Mark fid as used & save length for later */ - fids[i] |= (len << 16); - priv->xmit11.skb = skb; - priv->xmit11.fid = i; - if (down_trylock(&priv->sem) != 0) { - set_bit(FLAG_PENDING_XMIT11, &priv->flags); - netif_stop_queue(dev); - set_bit(JOB_XMIT11, &priv->jobs); - wake_up_interruptible(&priv->thr_wait); - } else - airo_end_xmit11(dev, false); - return NETDEV_TX_OK; -} - -static void airo_read_stats(struct net_device *dev) -{ - struct airo_info *ai = dev->ml_priv; - StatsRid stats_rid; - __le32 *vals = stats_rid.vals; - - clear_bit(JOB_STATS, &ai->jobs); - if (ai->power.event) { - up(&ai->sem); - return; - } - readStatsRid(ai, &stats_rid, RID_STATS, 0); - up(&ai->sem); - - dev->stats.rx_packets = le32_to_cpu(vals[43]) + le32_to_cpu(vals[44]) + - le32_to_cpu(vals[45]); - dev->stats.tx_packets = le32_to_cpu(vals[39]) + le32_to_cpu(vals[40]) + - le32_to_cpu(vals[41]); - dev->stats.rx_bytes = le32_to_cpu(vals[92]); - dev->stats.tx_bytes = le32_to_cpu(vals[91]); - dev->stats.rx_errors = le32_to_cpu(vals[0]) + le32_to_cpu(vals[2]) + - le32_to_cpu(vals[3]) + le32_to_cpu(vals[4]); - dev->stats.tx_errors = le32_to_cpu(vals[42]) + - dev->stats.tx_fifo_errors; - dev->stats.multicast = le32_to_cpu(vals[43]); - dev->stats.collisions = le32_to_cpu(vals[89]); - - /* detailed rx_errors: */ - dev->stats.rx_length_errors = le32_to_cpu(vals[3]); - dev->stats.rx_crc_errors = le32_to_cpu(vals[4]); - dev->stats.rx_frame_errors = le32_to_cpu(vals[2]); - dev->stats.rx_fifo_errors = le32_to_cpu(vals[0]); -} - -static struct net_device_stats *airo_get_stats(struct net_device *dev) -{ - struct airo_info *local = dev->ml_priv; - - if (!test_bit(JOB_STATS, &local->jobs)) { - set_bit(JOB_STATS, &local->jobs); - wake_up_interruptible(&local->thr_wait); - } - - return &dev->stats; -} - -static void airo_set_promisc(struct airo_info *ai, bool may_sleep) -{ - Cmd cmd; - Resp rsp; - - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd = CMD_SETMODE; - clear_bit(JOB_PROMISC, &ai->jobs); - cmd.parm0=(ai->flags&IFF_PROMISC) ? PROMISC : NOPROMISC; - issuecommand(ai, &cmd, &rsp, may_sleep); - up(&ai->sem); -} - -static void airo_set_multicast_list(struct net_device *dev) -{ - struct airo_info *ai = dev->ml_priv; - - if ((dev->flags ^ ai->flags) & IFF_PROMISC) { - change_bit(FLAG_PROMISC, &ai->flags); - if (down_trylock(&ai->sem) != 0) { - set_bit(JOB_PROMISC, &ai->jobs); - wake_up_interruptible(&ai->thr_wait); - } else - airo_set_promisc(ai, false); - } - - if ((dev->flags&IFF_ALLMULTI) || !netdev_mc_empty(dev)) { - /* Turn on multicast. (Should be already setup...) */ - } -} - -static int airo_set_mac_address(struct net_device *dev, void *p) -{ - struct airo_info *ai = dev->ml_priv; - struct sockaddr *addr = p; - - readConfigRid(ai, 1); - memcpy (ai->config.macAddr, addr->sa_data, dev->addr_len); - set_bit (FLAG_COMMIT, &ai->flags); - disable_MAC(ai, 1); - writeConfigRid (ai, 1); - enable_MAC(ai, 1); - dev_addr_set(ai->dev, addr->sa_data); - if (ai->wifidev) - dev_addr_set(ai->wifidev, addr->sa_data); - return 0; -} - -static LIST_HEAD(airo_devices); - -static void add_airo_dev(struct airo_info *ai) -{ - /* Upper layers already keep track of PCI devices, - * so we only need to remember our non-PCI cards. */ - if (!ai->pci) - list_add_tail(&ai->dev_list, &airo_devices); -} - -static void del_airo_dev(struct airo_info *ai) -{ - if (!ai->pci) - list_del(&ai->dev_list); -} - -static int airo_close(struct net_device *dev) -{ - struct airo_info *ai = dev->ml_priv; - - netif_stop_queue(dev); - - if (ai->wifidev != dev) { -#ifdef POWER_ON_DOWN - /* Shut power to the card. The idea is that the user can save - * power when he doesn't need the card with "ifconfig down". - * That's the method that is most friendly towards the network - * stack (i.e. the network stack won't try to broadcast - * anything on the interface and routes are gone. Jean II */ - set_bit(FLAG_RADIO_DOWN, &ai->flags); - disable_MAC(ai, 1); -#endif - disable_interrupts(ai); - - free_irq(dev->irq, dev); - - set_bit(JOB_DIE, &ai->jobs); - kthread_stop(ai->airo_thread_task); - } - return 0; -} - -void stop_airo_card(struct net_device *dev, int freeres) -{ - struct airo_info *ai = dev->ml_priv; - - set_bit(FLAG_RADIO_DOWN, &ai->flags); - disable_MAC(ai, 1); - disable_interrupts(ai); - takedown_proc_entry(dev, ai); - if (test_bit(FLAG_REGISTERED, &ai->flags)) { - unregister_netdev(dev); - if (ai->wifidev) { - unregister_netdev(ai->wifidev); - free_netdev(ai->wifidev); - ai->wifidev = NULL; - } - clear_bit(FLAG_REGISTERED, &ai->flags); - } - /* - * Clean out tx queue - */ - if (test_bit(FLAG_MPI, &ai->flags) && !skb_queue_empty(&ai->txq)) { - struct sk_buff *skb = NULL; - for (;(skb = skb_dequeue(&ai->txq));) - dev_kfree_skb(skb); - } - - airo_networks_free (ai); - - kfree(ai->flash); - kfree(ai->rssi); - kfree(ai->SSID); - if (freeres) { - /* PCMCIA frees this stuff, so only for PCI and ISA */ - release_region(dev->base_addr, 64); - if (test_bit(FLAG_MPI, &ai->flags)) { - if (ai->pci) - mpi_unmap_card(ai->pci); - if (ai->pcimem) - iounmap(ai->pcimem); - if (ai->pciaux) - iounmap(ai->pciaux); - dma_free_coherent(&ai->pci->dev, PCI_SHARED_LEN, - ai->shared, ai->shared_dma); - } - } - crypto_free_sync_skcipher(ai->tfm); - del_airo_dev(ai); - free_netdev(dev); -} - -EXPORT_SYMBOL(stop_airo_card); - -static int wll_header_parse(const struct sk_buff *skb, unsigned char *haddr) -{ - memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); - return ETH_ALEN; -} - -static void mpi_unmap_card(struct pci_dev *pci) -{ - unsigned long mem_start = pci_resource_start(pci, 1); - unsigned long mem_len = pci_resource_len(pci, 1); - unsigned long aux_start = pci_resource_start(pci, 2); - unsigned long aux_len = AUXMEMSIZE; - - release_mem_region(aux_start, aux_len); - release_mem_region(mem_start, mem_len); -} - -/************************************************************* - * This routine assumes that descriptors have been setup . - * Run at insmod time or after reset when the descriptors - * have been initialized . Returns 0 if all is well nz - * otherwise . Does not allocate memory but sets up card - * using previously allocated descriptors. - */ -static int mpi_init_descriptors (struct airo_info *ai) -{ - Cmd cmd; - Resp rsp; - int i; - int rc = SUCCESS; - - /* Alloc card RX descriptors */ - netif_stop_queue(ai->dev); - - memset(&rsp, 0, sizeof(rsp)); - memset(&cmd, 0, sizeof(cmd)); - - cmd.cmd = CMD_ALLOCATEAUX; - cmd.parm0 = FID_RX; - cmd.parm1 = (ai->rxfids[0].card_ram_off - ai->pciaux); - cmd.parm2 = MPI_MAX_FIDS; - rc = issuecommand(ai, &cmd, &rsp, true); - if (rc != SUCCESS) { - airo_print_err(ai->dev->name, "Couldn't allocate RX FID"); - return rc; - } - - for (i = 0; irxfids[i].card_ram_off, - &ai->rxfids[i].rx_desc, sizeof(RxFid)); - } - - /* Alloc card TX descriptors */ - - memset(&rsp, 0, sizeof(rsp)); - memset(&cmd, 0, sizeof(cmd)); - - cmd.cmd = CMD_ALLOCATEAUX; - cmd.parm0 = FID_TX; - cmd.parm1 = (ai->txfids[0].card_ram_off - ai->pciaux); - cmd.parm2 = MPI_MAX_FIDS; - - for (i = 0; itxfids[i].tx_desc.valid = 1; - memcpy_toio(ai->txfids[i].card_ram_off, - &ai->txfids[i].tx_desc, sizeof(TxFid)); - } - ai->txfids[i-1].tx_desc.eoc = 1; /* Last descriptor has EOC set */ - - rc = issuecommand(ai, &cmd, &rsp, true); - if (rc != SUCCESS) { - airo_print_err(ai->dev->name, "Couldn't allocate TX FID"); - return rc; - } - - /* Alloc card Rid descriptor */ - memset(&rsp, 0, sizeof(rsp)); - memset(&cmd, 0, sizeof(cmd)); - - cmd.cmd = CMD_ALLOCATEAUX; - cmd.parm0 = RID_RW; - cmd.parm1 = (ai->config_desc.card_ram_off - ai->pciaux); - cmd.parm2 = 1; /* Magic number... */ - rc = issuecommand(ai, &cmd, &rsp, true); - if (rc != SUCCESS) { - airo_print_err(ai->dev->name, "Couldn't allocate RID"); - return rc; - } - - memcpy_toio(ai->config_desc.card_ram_off, - &ai->config_desc.rid_desc, sizeof(Rid)); - - return rc; -} - -/* - * We are setting up three things here: - * 1) Map AUX memory for descriptors: Rid, TxFid, or RxFid. - * 2) Map PCI memory for issuing commands. - * 3) Allocate memory (shared) to send and receive ethernet frames. - */ -static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci) -{ - unsigned long mem_start, mem_len, aux_start, aux_len; - int rc = -1; - int i; - dma_addr_t busaddroff; - unsigned char *vpackoff; - unsigned char __iomem *pciaddroff; - - mem_start = pci_resource_start(pci, 1); - mem_len = pci_resource_len(pci, 1); - aux_start = pci_resource_start(pci, 2); - aux_len = AUXMEMSIZE; - - if (!request_mem_region(mem_start, mem_len, DRV_NAME)) { - airo_print_err("", "Couldn't get region %x[%x]", - (int)mem_start, (int)mem_len); - goto out; - } - if (!request_mem_region(aux_start, aux_len, DRV_NAME)) { - airo_print_err("", "Couldn't get region %x[%x]", - (int)aux_start, (int)aux_len); - goto free_region1; - } - - ai->pcimem = ioremap(mem_start, mem_len); - if (!ai->pcimem) { - airo_print_err("", "Couldn't map region %x[%x]", - (int)mem_start, (int)mem_len); - goto free_region2; - } - ai->pciaux = ioremap(aux_start, aux_len); - if (!ai->pciaux) { - airo_print_err("", "Couldn't map region %x[%x]", - (int)aux_start, (int)aux_len); - goto free_memmap; - } - - /* Reserve PKTSIZE for each fid and 2K for the Rids */ - ai->shared = dma_alloc_coherent(&pci->dev, PCI_SHARED_LEN, - &ai->shared_dma, GFP_KERNEL); - if (!ai->shared) { - airo_print_err("", "Couldn't alloc_coherent %d", - PCI_SHARED_LEN); - goto free_auxmap; - } - - /* - * Setup descriptor RX, TX, CONFIG - */ - busaddroff = ai->shared_dma; - pciaddroff = ai->pciaux + AUX_OFFSET; - vpackoff = ai->shared; - - /* RX descriptor setup */ - for (i = 0; i < MPI_MAX_FIDS; i++) { - ai->rxfids[i].pending = 0; - ai->rxfids[i].card_ram_off = pciaddroff; - ai->rxfids[i].virtual_host_addr = vpackoff; - ai->rxfids[i].rx_desc.host_addr = busaddroff; - ai->rxfids[i].rx_desc.valid = 1; - ai->rxfids[i].rx_desc.len = PKTSIZE; - ai->rxfids[i].rx_desc.rdy = 0; - - pciaddroff += sizeof(RxFid); - busaddroff += PKTSIZE; - vpackoff += PKTSIZE; - } - - /* TX descriptor setup */ - for (i = 0; i < MPI_MAX_FIDS; i++) { - ai->txfids[i].card_ram_off = pciaddroff; - ai->txfids[i].virtual_host_addr = vpackoff; - ai->txfids[i].tx_desc.valid = 1; - ai->txfids[i].tx_desc.host_addr = busaddroff; - memcpy(ai->txfids[i].virtual_host_addr, - &wifictlhdr8023, sizeof(wifictlhdr8023)); - - pciaddroff += sizeof(TxFid); - busaddroff += PKTSIZE; - vpackoff += PKTSIZE; - } - ai->txfids[i-1].tx_desc.eoc = 1; /* Last descriptor has EOC set */ - - /* Rid descriptor setup */ - ai->config_desc.card_ram_off = pciaddroff; - ai->config_desc.virtual_host_addr = vpackoff; - ai->config_desc.rid_desc.host_addr = busaddroff; - ai->ridbus = busaddroff; - ai->config_desc.rid_desc.rid = 0; - ai->config_desc.rid_desc.len = RIDSIZE; - ai->config_desc.rid_desc.valid = 1; - pciaddroff += sizeof(Rid); - busaddroff += RIDSIZE; - vpackoff += RIDSIZE; - - /* Tell card about descriptors */ - if (mpi_init_descriptors (ai) != SUCCESS) - goto free_shared; - - return 0; - free_shared: - dma_free_coherent(&pci->dev, PCI_SHARED_LEN, ai->shared, - ai->shared_dma); - free_auxmap: - iounmap(ai->pciaux); - free_memmap: - iounmap(ai->pcimem); - free_region2: - release_mem_region(aux_start, aux_len); - free_region1: - release_mem_region(mem_start, mem_len); - out: - return rc; -} - -static const struct header_ops airo_header_ops = { - .parse = wll_header_parse, -}; - -static const struct net_device_ops airo11_netdev_ops = { - .ndo_open = airo_open, - .ndo_stop = airo_close, - .ndo_start_xmit = airo_start_xmit11, - .ndo_get_stats = airo_get_stats, - .ndo_set_mac_address = airo_set_mac_address, - .ndo_siocdevprivate = airo_siocdevprivate, -}; - -static void wifi_setup(struct net_device *dev) -{ - dev->netdev_ops = &airo11_netdev_ops; - dev->header_ops = &airo_header_ops; - dev->wireless_handlers = &airo_handler_def; - - dev->type = ARPHRD_IEEE80211; - dev->hard_header_len = ETH_HLEN; - dev->mtu = AIRO_DEF_MTU; - dev->min_mtu = 68; - dev->max_mtu = MIC_MSGLEN_MAX; - dev->addr_len = ETH_ALEN; - dev->tx_queue_len = 100; - - eth_broadcast_addr(dev->broadcast); - - dev->flags = IFF_BROADCAST|IFF_MULTICAST; -} - -static struct net_device *init_wifidev(struct airo_info *ai, - struct net_device *ethdev) -{ - int err; - struct net_device *dev = alloc_netdev(0, "wifi%d", NET_NAME_UNKNOWN, - wifi_setup); - if (!dev) - return NULL; - dev->ml_priv = ethdev->ml_priv; - dev->irq = ethdev->irq; - dev->base_addr = ethdev->base_addr; - dev->wireless_data = ethdev->wireless_data; - SET_NETDEV_DEV(dev, ethdev->dev.parent); - eth_hw_addr_inherit(dev, ethdev); - err = register_netdev(dev); - if (err<0) { - free_netdev(dev); - return NULL; - } - return dev; -} - -static int reset_card(struct net_device *dev, int lock) -{ - struct airo_info *ai = dev->ml_priv; - - if (lock && down_interruptible(&ai->sem)) - return -1; - waitbusy (ai); - OUT4500(ai, COMMAND, CMD_SOFTRESET); - msleep(200); - waitbusy (ai); - msleep(200); - if (lock) - up(&ai->sem); - return 0; -} - -#define AIRO_MAX_NETWORK_COUNT 64 -static int airo_networks_allocate(struct airo_info *ai) -{ - if (ai->networks) - return 0; - - ai->networks = kcalloc(AIRO_MAX_NETWORK_COUNT, sizeof(BSSListElement), - GFP_KERNEL); - if (!ai->networks) { - airo_print_warn("", "Out of memory allocating beacons"); - return -ENOMEM; - } - - return 0; -} - -static void airo_networks_free(struct airo_info *ai) -{ - kfree(ai->networks); - ai->networks = NULL; -} - -static void airo_networks_initialize(struct airo_info *ai) -{ - int i; - - INIT_LIST_HEAD(&ai->network_free_list); - INIT_LIST_HEAD(&ai->network_list); - for (i = 0; i < AIRO_MAX_NETWORK_COUNT; i++) - list_add_tail(&ai->networks[i].list, - &ai->network_free_list); -} - -static const struct net_device_ops airo_netdev_ops = { - .ndo_open = airo_open, - .ndo_stop = airo_close, - .ndo_start_xmit = airo_start_xmit, - .ndo_get_stats = airo_get_stats, - .ndo_set_rx_mode = airo_set_multicast_list, - .ndo_set_mac_address = airo_set_mac_address, - .ndo_siocdevprivate = airo_siocdevprivate, - .ndo_validate_addr = eth_validate_addr, -}; - -static const struct net_device_ops mpi_netdev_ops = { - .ndo_open = airo_open, - .ndo_stop = airo_close, - .ndo_start_xmit = mpi_start_xmit, - .ndo_get_stats = airo_get_stats, - .ndo_set_rx_mode = airo_set_multicast_list, - .ndo_set_mac_address = airo_set_mac_address, - .ndo_siocdevprivate = airo_siocdevprivate, - .ndo_validate_addr = eth_validate_addr, -}; - - -static struct net_device *_init_airo_card(unsigned short irq, int port, - int is_pcmcia, struct pci_dev *pci, - struct device *dmdev) -{ - struct net_device *dev; - struct airo_info *ai; - int i, rc; - CapabilityRid cap_rid; - - /* Create the network device object. */ - dev = alloc_netdev(sizeof(*ai), "", NET_NAME_UNKNOWN, ether_setup); - if (!dev) { - airo_print_err("", "Couldn't alloc_etherdev"); - return NULL; - } - - ai = dev->ml_priv = netdev_priv(dev); - ai->wifidev = NULL; - ai->flags = 1 << FLAG_RADIO_DOWN; - ai->jobs = 0; - ai->dev = dev; - if (pci && (pci->device == 0x5000 || pci->device == 0xa504)) { - airo_print_dbg("", "Found an MPI350 card"); - set_bit(FLAG_MPI, &ai->flags); - } - spin_lock_init(&ai->aux_lock); - sema_init(&ai->sem, 1); - ai->config.len = 0; - ai->pci = pci; - init_waitqueue_head (&ai->thr_wait); - ai->tfm = NULL; - add_airo_dev(ai); - ai->APList.len = cpu_to_le16(sizeof(struct APListRid)); - - if (airo_networks_allocate (ai)) - goto err_out_free; - airo_networks_initialize (ai); - - skb_queue_head_init (&ai->txq); - - /* The Airo-specific entries in the device structure. */ - if (test_bit(FLAG_MPI,&ai->flags)) - dev->netdev_ops = &mpi_netdev_ops; - else - dev->netdev_ops = &airo_netdev_ops; - dev->wireless_handlers = &airo_handler_def; - ai->wireless_data.spy_data = &ai->spy_data; - dev->wireless_data = &ai->wireless_data; - dev->irq = irq; - dev->base_addr = port; - dev->priv_flags &= ~IFF_TX_SKB_SHARING; - dev->max_mtu = MIC_MSGLEN_MAX; - - SET_NETDEV_DEV(dev, dmdev); - - reset_card (dev, 1); - msleep(400); - - if (!is_pcmcia) { - if (!request_region(dev->base_addr, 64, DRV_NAME)) { - rc = -EBUSY; - airo_print_err(dev->name, "Couldn't request region"); - goto err_out_nets; - } - } - - if (test_bit(FLAG_MPI,&ai->flags)) { - if (mpi_map_card(ai, pci)) { - airo_print_err("", "Could not map memory"); - goto err_out_res; - } - } - - if (probe) { - if (setup_card(ai, dev, 1) != SUCCESS) { - airo_print_err(dev->name, "MAC could not be enabled"); - rc = -EIO; - goto err_out_map; - } - } else if (!test_bit(FLAG_MPI,&ai->flags)) { - ai->bap_read = fast_bap_read; - set_bit(FLAG_FLASHING, &ai->flags); - } - - strcpy(dev->name, "eth%d"); - rc = register_netdev(dev); - if (rc) { - airo_print_err(dev->name, "Couldn't register_netdev"); - goto err_out_map; - } - ai->wifidev = init_wifidev(ai, dev); - if (!ai->wifidev) - goto err_out_reg; - - rc = readCapabilityRid(ai, &cap_rid, 1); - if (rc != SUCCESS) { - rc = -EIO; - goto err_out_wifi; - } - /* WEP capability discovery */ - ai->wep_capable = (cap_rid.softCap & cpu_to_le16(0x02)) ? 1 : 0; - ai->max_wep_idx = (cap_rid.softCap & cpu_to_le16(0x80)) ? 3 : 0; - - airo_print_info(dev->name, "Firmware version %x.%x.%02d", - ((le16_to_cpu(cap_rid.softVer) >> 8) & 0xF), - (le16_to_cpu(cap_rid.softVer) & 0xFF), - le16_to_cpu(cap_rid.softSubVer)); - - /* Test for WPA support */ - /* Only firmware versions 5.30.17 or better can do WPA */ - if (le16_to_cpu(cap_rid.softVer) > 0x530 - || (le16_to_cpu(cap_rid.softVer) == 0x530 - && le16_to_cpu(cap_rid.softSubVer) >= 17)) { - airo_print_info(ai->dev->name, "WPA supported."); - - set_bit(FLAG_WPA_CAPABLE, &ai->flags); - ai->bssListFirst = RID_WPA_BSSLISTFIRST; - ai->bssListNext = RID_WPA_BSSLISTNEXT; - ai->bssListRidLen = sizeof(BSSListRid); - } else { - airo_print_info(ai->dev->name, "WPA unsupported with firmware " - "versions older than 5.30.17."); - - ai->bssListFirst = RID_BSSLISTFIRST; - ai->bssListNext = RID_BSSLISTNEXT; - ai->bssListRidLen = sizeof(BSSListRid) - sizeof(BSSListRidExtra); - } - - set_bit(FLAG_REGISTERED,&ai->flags); - airo_print_info(dev->name, "MAC enabled %pM", dev->dev_addr); - - /* Allocate the transmit buffers */ - if (probe && !test_bit(FLAG_MPI,&ai->flags)) - for (i = 0; i < MAX_FIDS; i++) - ai->fids[i] = transmit_allocate(ai, AIRO_DEF_MTU, i>=MAX_FIDS/2); - - if (setup_proc_entry(dev, dev->ml_priv) < 0) - goto err_out_wifi; - - return dev; - -err_out_wifi: - unregister_netdev(ai->wifidev); - free_netdev(ai->wifidev); -err_out_reg: - unregister_netdev(dev); -err_out_map: - if (test_bit(FLAG_MPI,&ai->flags) && pci) { - dma_free_coherent(&pci->dev, PCI_SHARED_LEN, ai->shared, - ai->shared_dma); - iounmap(ai->pciaux); - iounmap(ai->pcimem); - mpi_unmap_card(ai->pci); - } -err_out_res: - if (!is_pcmcia) - release_region(dev->base_addr, 64); -err_out_nets: - airo_networks_free(ai); -err_out_free: - del_airo_dev(ai); - free_netdev(dev); - return NULL; -} - -struct net_device *init_airo_card(unsigned short irq, int port, int is_pcmcia, - struct device *dmdev) -{ - return _init_airo_card (irq, port, is_pcmcia, NULL, dmdev); -} - -EXPORT_SYMBOL(init_airo_card); - -static int waitbusy (struct airo_info *ai) -{ - int delay = 0; - while ((IN4500(ai, COMMAND) & COMMAND_BUSY) && (delay < 10000)) { - udelay (10); - if ((++delay % 20) == 0) - OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY); - } - return delay < 10000; -} - -int reset_airo_card(struct net_device *dev) -{ - int i; - struct airo_info *ai = dev->ml_priv; - - if (reset_card (dev, 1)) - return -1; - - if (setup_card(ai, dev, 1) != SUCCESS) { - airo_print_err(dev->name, "MAC could not be enabled"); - return -1; - } - airo_print_info(dev->name, "MAC enabled %pM", dev->dev_addr); - /* Allocate the transmit buffers if needed */ - if (!test_bit(FLAG_MPI,&ai->flags)) - for (i = 0; i < MAX_FIDS; i++) - ai->fids[i] = transmit_allocate (ai, AIRO_DEF_MTU, i>=MAX_FIDS/2); - - enable_interrupts(ai); - netif_wake_queue(dev); - return 0; -} - -EXPORT_SYMBOL(reset_airo_card); - -static void airo_send_event(struct net_device *dev) -{ - struct airo_info *ai = dev->ml_priv; - union iwreq_data wrqu; - StatusRid status_rid; - - clear_bit(JOB_EVENT, &ai->jobs); - PC4500_readrid(ai, RID_STATUS, &status_rid, sizeof(status_rid), 0); - up(&ai->sem); - wrqu.data.length = 0; - wrqu.data.flags = 0; - memcpy(wrqu.ap_addr.sa_data, status_rid.bssid[0], ETH_ALEN); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - - /* Send event to user space */ - wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); -} - -static void airo_process_scan_results (struct airo_info *ai) -{ - union iwreq_data wrqu; - BSSListRid bss; - int rc; - BSSListElement * loop_net; - BSSListElement * tmp_net; - - /* Blow away current list of scan results */ - list_for_each_entry_safe (loop_net, tmp_net, &ai->network_list, list) { - list_move_tail (&loop_net->list, &ai->network_free_list); - /* Don't blow away ->list, just BSS data */ - memset (loop_net, 0, sizeof (loop_net->bss)); - } - - /* Try to read the first entry of the scan result */ - rc = PC4500_readrid(ai, ai->bssListFirst, &bss, ai->bssListRidLen, 0); - if ((rc) || (bss.index == cpu_to_le16(0xffff))) { - /* No scan results */ - goto out; - } - - /* Read and parse all entries */ - tmp_net = NULL; - while ((!rc) && (bss.index != cpu_to_le16(0xffff))) { - /* Grab a network off the free list */ - if (!list_empty(&ai->network_free_list)) { - tmp_net = list_entry(ai->network_free_list.next, - BSSListElement, list); - list_del(ai->network_free_list.next); - } - - if (tmp_net != NULL) { - memcpy(tmp_net, &bss, sizeof(tmp_net->bss)); - list_add_tail(&tmp_net->list, &ai->network_list); - tmp_net = NULL; - } - - /* Read next entry */ - rc = PC4500_readrid(ai, ai->bssListNext, - &bss, ai->bssListRidLen, 0); - } - -out: - /* write APList back (we cleared it in airo_set_scan) */ - disable_MAC(ai, 2); - writeAPListRid(ai, &ai->APList, 0); - enable_MAC(ai, 0); - - ai->scan_timeout = 0; - clear_bit(JOB_SCAN_RESULTS, &ai->jobs); - up(&ai->sem); - - /* Send an empty event to user space. - * We don't send the received data on - * the event because it would require - * us to do complex transcoding, and - * we want to minimise the work done in - * the irq handler. Use a request to - * extract the data - Jean II */ - wrqu.data.length = 0; - wrqu.data.flags = 0; - wireless_send_event(ai->dev, SIOCGIWSCAN, &wrqu, NULL); -} - -static int airo_thread(void *data) -{ - struct net_device *dev = data; - struct airo_info *ai = dev->ml_priv; - int locked; - - set_freezable(); - while (1) { - /* make swsusp happy with our thread */ - try_to_freeze(); - - if (test_bit(JOB_DIE, &ai->jobs)) - break; - - if (ai->jobs) { - locked = down_interruptible(&ai->sem); - } else { - wait_queue_entry_t wait; - - init_waitqueue_entry(&wait, current); - add_wait_queue(&ai->thr_wait, &wait); - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - if (ai->jobs) - break; - if (ai->expires || ai->scan_timeout) { - if (ai->scan_timeout && - time_after_eq(jiffies, ai->scan_timeout)) { - set_bit(JOB_SCAN_RESULTS, &ai->jobs); - break; - } else if (ai->expires && - time_after_eq(jiffies, ai->expires)) { - set_bit(JOB_AUTOWEP, &ai->jobs); - break; - } - if (!kthread_should_stop() && - !freezing(current)) { - unsigned long wake_at; - if (!ai->expires || !ai->scan_timeout) { - wake_at = max(ai->expires, - ai->scan_timeout); - } else { - wake_at = min(ai->expires, - ai->scan_timeout); - } - schedule_timeout(wake_at - jiffies); - continue; - } - } else if (!kthread_should_stop() && - !freezing(current)) { - schedule(); - continue; - } - break; - } - __set_current_state(TASK_RUNNING); - remove_wait_queue(&ai->thr_wait, &wait); - locked = 1; - } - - if (locked) - continue; - - if (test_bit(JOB_DIE, &ai->jobs)) { - up(&ai->sem); - break; - } - - if (ai->power.event || test_bit(FLAG_FLASHING, &ai->flags)) { - up(&ai->sem); - continue; - } - - if (test_bit(JOB_XMIT, &ai->jobs)) - airo_end_xmit(dev, true); - else if (test_bit(JOB_XMIT11, &ai->jobs)) - airo_end_xmit11(dev, true); - else if (test_bit(JOB_STATS, &ai->jobs)) - airo_read_stats(dev); - else if (test_bit(JOB_PROMISC, &ai->jobs)) - airo_set_promisc(ai, true); - else if (test_bit(JOB_MIC, &ai->jobs)) - micinit(ai); - else if (test_bit(JOB_EVENT, &ai->jobs)) - airo_send_event(dev); - else if (test_bit(JOB_AUTOWEP, &ai->jobs)) - timer_func(dev); - else if (test_bit(JOB_SCAN_RESULTS, &ai->jobs)) - airo_process_scan_results(ai); - else /* Shouldn't get here, but we make sure to unlock */ - up(&ai->sem); - } - - return 0; -} - -static int header_len(__le16 ctl) -{ - u16 fc = le16_to_cpu(ctl); - switch (fc & 0xc) { - case 4: - if ((fc & 0xe0) == 0xc0) - return 10; /* one-address control packet */ - return 16; /* two-address control packet */ - case 8: - if ((fc & 0x300) == 0x300) - return 30; /* WDS packet */ - } - return 24; -} - -static void airo_handle_cisco_mic(struct airo_info *ai) -{ - if (test_bit(FLAG_MIC_CAPABLE, &ai->flags)) { - set_bit(JOB_MIC, &ai->jobs); - wake_up_interruptible(&ai->thr_wait); - } -} - -/* Airo Status codes */ -#define STAT_NOBEACON 0x8000 /* Loss of sync - missed beacons */ -#define STAT_MAXRETRIES 0x8001 /* Loss of sync - max retries */ -#define STAT_MAXARL 0x8002 /* Loss of sync - average retry level exceeded*/ -#define STAT_FORCELOSS 0x8003 /* Loss of sync - host request */ -#define STAT_TSFSYNC 0x8004 /* Loss of sync - TSF synchronization */ -#define STAT_DEAUTH 0x8100 /* low byte is 802.11 reason code */ -#define STAT_DISASSOC 0x8200 /* low byte is 802.11 reason code */ -#define STAT_ASSOC_FAIL 0x8400 /* low byte is 802.11 reason code */ -#define STAT_AUTH_FAIL 0x0300 /* low byte is 802.11 reason code */ -#define STAT_ASSOC 0x0400 /* Associated */ -#define STAT_REASSOC 0x0600 /* Reassociated? Only on firmware >= 5.30.17 */ - -static void airo_print_status(const char *devname, u16 status) -{ - u8 reason = status & 0xFF; - - switch (status & 0xFF00) { - case STAT_NOBEACON: - switch (status) { - case STAT_NOBEACON: - airo_print_dbg(devname, "link lost (missed beacons)"); - break; - case STAT_MAXRETRIES: - case STAT_MAXARL: - airo_print_dbg(devname, "link lost (max retries)"); - break; - case STAT_FORCELOSS: - airo_print_dbg(devname, "link lost (local choice)"); - break; - case STAT_TSFSYNC: - airo_print_dbg(devname, "link lost (TSF sync lost)"); - break; - default: - airo_print_dbg(devname, "unknown status %x\n", status); - break; - } - break; - case STAT_DEAUTH: - airo_print_dbg(devname, "deauthenticated (reason: %d)", reason); - break; - case STAT_DISASSOC: - airo_print_dbg(devname, "disassociated (reason: %d)", reason); - break; - case STAT_ASSOC_FAIL: - airo_print_dbg(devname, "association failed (reason: %d)", - reason); - break; - case STAT_AUTH_FAIL: - airo_print_dbg(devname, "authentication failed (reason: %d)", - reason); - break; - case STAT_ASSOC: - case STAT_REASSOC: - break; - default: - airo_print_dbg(devname, "unknown status %x\n", status); - break; - } -} - -static void airo_handle_link(struct airo_info *ai) -{ - union iwreq_data wrqu; - int scan_forceloss = 0; - u16 status; - - /* Get new status and acknowledge the link change */ - status = le16_to_cpu(IN4500(ai, LINKSTAT)); - OUT4500(ai, EVACK, EV_LINK); - - if ((status == STAT_FORCELOSS) && (ai->scan_timeout > 0)) - scan_forceloss = 1; - - airo_print_status(ai->dev->name, status); - - if ((status == STAT_ASSOC) || (status == STAT_REASSOC)) { - if (auto_wep) - ai->expires = 0; - if (ai->list_bss_task) - wake_up_process(ai->list_bss_task); - set_bit(FLAG_UPDATE_UNI, &ai->flags); - set_bit(FLAG_UPDATE_MULTI, &ai->flags); - - set_bit(JOB_EVENT, &ai->jobs); - wake_up_interruptible(&ai->thr_wait); - - netif_carrier_on(ai->dev); - } else if (!scan_forceloss) { - if (auto_wep && !ai->expires) { - ai->expires = RUN_AT(3*HZ); - wake_up_interruptible(&ai->thr_wait); - } - - /* Send event to user space */ - eth_zero_addr(wrqu.ap_addr.sa_data); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - wireless_send_event(ai->dev, SIOCGIWAP, &wrqu, NULL); - netif_carrier_off(ai->dev); - } else { - netif_carrier_off(ai->dev); - } -} - -static void airo_handle_rx(struct airo_info *ai) -{ - struct sk_buff *skb = NULL; - __le16 fc, v, *buffer, tmpbuf[4]; - u16 len, hdrlen = 0, gap, fid; - struct rx_hdr hdr; - int success = 0; - - if (test_bit(FLAG_MPI, &ai->flags)) { - if (test_bit(FLAG_802_11, &ai->flags)) - mpi_receive_802_11(ai); - else - mpi_receive_802_3(ai); - OUT4500(ai, EVACK, EV_RX); - return; - } - - fid = IN4500(ai, RXFID); - - /* Get the packet length */ - if (test_bit(FLAG_802_11, &ai->flags)) { - bap_setup (ai, fid, 4, BAP0); - bap_read (ai, (__le16*)&hdr, sizeof(hdr), BAP0); - /* Bad CRC. Ignore packet */ - if (le16_to_cpu(hdr.status) & 2) - hdr.len = 0; - if (ai->wifidev == NULL) - hdr.len = 0; - } else { - bap_setup(ai, fid, 0x36, BAP0); - bap_read(ai, &hdr.len, 2, BAP0); - } - len = le16_to_cpu(hdr.len); - - if (len > AIRO_DEF_MTU) { - airo_print_err(ai->dev->name, "Bad size %d", len); - goto done; - } - if (len == 0) - goto done; - - if (test_bit(FLAG_802_11, &ai->flags)) { - bap_read(ai, &fc, sizeof (fc), BAP0); - hdrlen = header_len(fc); - } else - hdrlen = ETH_ALEN * 2; - - skb = dev_alloc_skb(len + hdrlen + 2 + 2); - if (!skb) { - ai->dev->stats.rx_dropped++; - goto done; - } - - skb_reserve(skb, 2); /* This way the IP header is aligned */ - buffer = skb_put(skb, len + hdrlen); - if (test_bit(FLAG_802_11, &ai->flags)) { - buffer[0] = fc; - bap_read(ai, buffer + 1, hdrlen - 2, BAP0); - if (hdrlen == 24) - bap_read(ai, tmpbuf, 6, BAP0); - - bap_read(ai, &v, sizeof(v), BAP0); - gap = le16_to_cpu(v); - if (gap) { - if (gap <= 8) { - bap_read(ai, tmpbuf, gap, BAP0); - } else { - airo_print_err(ai->dev->name, "gaplen too " - "big. Problems will follow..."); - } - } - bap_read(ai, buffer + hdrlen/2, len, BAP0); - } else { - MICBuffer micbuf; - - bap_read(ai, buffer, ETH_ALEN * 2, BAP0); - if (ai->micstats.enabled) { - bap_read(ai, (__le16 *) &micbuf, sizeof (micbuf), BAP0); - if (ntohs(micbuf.typelen) > 0x05DC) - bap_setup(ai, fid, 0x44, BAP0); - else { - if (len <= sizeof (micbuf)) { - dev_kfree_skb_irq(skb); - goto done; - } - - len -= sizeof(micbuf); - skb_trim(skb, len + hdrlen); - } - } - - bap_read(ai, buffer + ETH_ALEN, len, BAP0); - if (decapsulate(ai, &micbuf, (etherHead*) buffer, len)) - dev_kfree_skb_irq (skb); - else - success = 1; - } - -#ifdef WIRELESS_SPY - if (success && (ai->spy_data.spy_number > 0)) { - char *sa; - struct iw_quality wstats; - - /* Prepare spy data : addr + qual */ - if (!test_bit(FLAG_802_11, &ai->flags)) { - sa = (char *) buffer + 6; - bap_setup(ai, fid, 8, BAP0); - bap_read(ai, (__le16 *) hdr.rssi, 2, BAP0); - } else - sa = (char *) buffer + 10; - wstats.qual = hdr.rssi[0]; - if (ai->rssi) - wstats.level = 0x100 - ai->rssi[hdr.rssi[1]].rssidBm; - else - wstats.level = (hdr.rssi[1] + 321) / 2; - wstats.noise = ai->wstats.qual.noise; - wstats.updated = IW_QUAL_LEVEL_UPDATED - | IW_QUAL_QUAL_UPDATED - | IW_QUAL_DBM; - /* Update spy records */ - wireless_spy_update(ai->dev, sa, &wstats); - } -#endif /* WIRELESS_SPY */ - -done: - OUT4500(ai, EVACK, EV_RX); - - if (success) { - if (test_bit(FLAG_802_11, &ai->flags)) { - skb_reset_mac_header(skb); - skb->pkt_type = PACKET_OTHERHOST; - skb->dev = ai->wifidev; - skb->protocol = htons(ETH_P_802_2); - } else - skb->protocol = eth_type_trans(skb, ai->dev); - skb->ip_summed = CHECKSUM_NONE; - - netif_rx(skb); - } -} - -static void airo_handle_tx(struct airo_info *ai, u16 status) -{ - int i, index = -1; - u16 fid; - - if (test_bit(FLAG_MPI, &ai->flags)) { - unsigned long flags; - - if (status & EV_TXEXC) - get_tx_error(ai, -1); - - spin_lock_irqsave(&ai->aux_lock, flags); - if (!skb_queue_empty(&ai->txq)) { - spin_unlock_irqrestore(&ai->aux_lock, flags); - mpi_send_packet(ai->dev); - } else { - clear_bit(FLAG_PENDING_XMIT, &ai->flags); - spin_unlock_irqrestore(&ai->aux_lock, flags); - netif_wake_queue(ai->dev); - } - OUT4500(ai, EVACK, status & (EV_TX | EV_TXCPY | EV_TXEXC)); - return; - } - - fid = IN4500(ai, TXCOMPLFID); - - for (i = 0; i < MAX_FIDS; i++) { - if ((ai->fids[i] & 0xffff) == fid) - index = i; - } - - if (index != -1) { - if (status & EV_TXEXC) - get_tx_error(ai, index); - - OUT4500(ai, EVACK, status & (EV_TX | EV_TXEXC)); - - /* Set up to be used again */ - ai->fids[index] &= 0xffff; - if (index < MAX_FIDS / 2) { - if (!test_bit(FLAG_PENDING_XMIT, &ai->flags)) - netif_wake_queue(ai->dev); - } else { - if (!test_bit(FLAG_PENDING_XMIT11, &ai->flags)) - netif_wake_queue(ai->wifidev); - } - } else { - OUT4500(ai, EVACK, status & (EV_TX | EV_TXCPY | EV_TXEXC)); - airo_print_err(ai->dev->name, "Unallocated FID was used to xmit"); - } -} - -static irqreturn_t airo_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - u16 status, savedInterrupts = 0; - struct airo_info *ai = dev->ml_priv; - int handled = 0; - - if (!netif_device_present(dev)) - return IRQ_NONE; - - for (;;) { - status = IN4500(ai, EVSTAT); - if (!(status & STATUS_INTS) || (status == 0xffff)) - break; - - handled = 1; - - if (status & EV_AWAKE) { - OUT4500(ai, EVACK, EV_AWAKE); - OUT4500(ai, EVACK, EV_AWAKE); - } - - if (!savedInterrupts) { - savedInterrupts = IN4500(ai, EVINTEN); - OUT4500(ai, EVINTEN, 0); - } - - if (status & EV_MIC) { - OUT4500(ai, EVACK, EV_MIC); - airo_handle_cisco_mic(ai); - } - - if (status & EV_LINK) { - /* Link status changed */ - airo_handle_link(ai); - } - - /* Check to see if there is something to receive */ - if (status & EV_RX) - airo_handle_rx(ai); - - /* Check to see if a packet has been transmitted */ - if (status & (EV_TX | EV_TXCPY | EV_TXEXC)) - airo_handle_tx(ai, status); - - if (status & ~STATUS_INTS & ~IGNORE_INTS) { - airo_print_warn(ai->dev->name, "Got weird status %x", - status & ~STATUS_INTS & ~IGNORE_INTS); - } - } - - if (savedInterrupts) - OUT4500(ai, EVINTEN, savedInterrupts); - - return IRQ_RETVAL(handled); -} - -/* - * Routines to talk to the card - */ - -/* - * This was originally written for the 4500, hence the name - * NOTE: If use with 8bit mode and SMP bad things will happen! - * Why would some one do 8 bit IO in an SMP machine?!? - */ -static void OUT4500(struct airo_info *ai, u16 reg, u16 val) -{ - if (test_bit(FLAG_MPI,&ai->flags)) - reg <<= 1; - if (!do8bitIO) - outw(val, ai->dev->base_addr + reg); - else { - outb(val & 0xff, ai->dev->base_addr + reg); - outb(val >> 8, ai->dev->base_addr + reg + 1); - } -} - -static u16 IN4500(struct airo_info *ai, u16 reg) -{ - unsigned short rc; - - if (test_bit(FLAG_MPI,&ai->flags)) - reg <<= 1; - if (!do8bitIO) - rc = inw(ai->dev->base_addr + reg); - else { - rc = inb(ai->dev->base_addr + reg); - rc += ((int)inb(ai->dev->base_addr + reg + 1)) << 8; - } - return rc; -} - -static int enable_MAC(struct airo_info *ai, int lock) -{ - int rc; - Cmd cmd; - Resp rsp; - - /* FLAG_RADIO_OFF : Radio disabled via /proc or Wireless Extensions - * FLAG_RADIO_DOWN : Radio disabled via "ifconfig ethX down" - * Note : we could try to use !netif_running(dev) in enable_MAC() - * instead of this flag, but I don't trust it *within* the - * open/close functions, and testing both flags together is - * "cheaper" - Jean II */ - if (ai->flags & FLAG_RADIO_MASK) return SUCCESS; - - if (lock && down_interruptible(&ai->sem)) - return -ERESTARTSYS; - - if (!test_bit(FLAG_ENABLED, &ai->flags)) { - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd = MAC_ENABLE; - rc = issuecommand(ai, &cmd, &rsp, true); - if (rc == SUCCESS) - set_bit(FLAG_ENABLED, &ai->flags); - } else - rc = SUCCESS; - - if (lock) - up(&ai->sem); - - if (rc) - airo_print_err(ai->dev->name, "Cannot enable MAC"); - else if ((rsp.status & 0xFF00) != 0) { - airo_print_err(ai->dev->name, "Bad MAC enable reason=%x, " - "rid=%x, offset=%d", rsp.rsp0, rsp.rsp1, rsp.rsp2); - rc = ERROR; - } - return rc; -} - -static void disable_MAC(struct airo_info *ai, int lock) -{ - Cmd cmd; - Resp rsp; - - if (lock == 1 && down_interruptible(&ai->sem)) - return; - - if (test_bit(FLAG_ENABLED, &ai->flags)) { - if (lock != 2) /* lock == 2 means don't disable carrier */ - netif_carrier_off(ai->dev); - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd = MAC_DISABLE; // disable in case already enabled - issuecommand(ai, &cmd, &rsp, true); - clear_bit(FLAG_ENABLED, &ai->flags); - } - if (lock == 1) - up(&ai->sem); -} - -static void enable_interrupts(struct airo_info *ai) -{ - /* Enable the interrupts */ - OUT4500(ai, EVINTEN, STATUS_INTS); -} - -static void disable_interrupts(struct airo_info *ai) -{ - OUT4500(ai, EVINTEN, 0); -} - -static void mpi_receive_802_3(struct airo_info *ai) -{ - RxFid rxd; - int len = 0; - struct sk_buff *skb; - char *buffer; - int off = 0; - MICBuffer micbuf; - - memcpy_fromio(&rxd, ai->rxfids[0].card_ram_off, sizeof(rxd)); - /* Make sure we got something */ - if (rxd.rdy && rxd.valid == 0) { - len = rxd.len + 12; - if (len < 12 || len > 2048) - goto badrx; - - skb = dev_alloc_skb(len); - if (!skb) { - ai->dev->stats.rx_dropped++; - goto badrx; - } - buffer = skb_put(skb, len); - memcpy(buffer, ai->rxfids[0].virtual_host_addr, ETH_ALEN * 2); - if (ai->micstats.enabled) { - memcpy(&micbuf, - ai->rxfids[0].virtual_host_addr + ETH_ALEN * 2, - sizeof(micbuf)); - if (ntohs(micbuf.typelen) <= 0x05DC) { - if (len <= sizeof(micbuf) + ETH_ALEN * 2) - goto badmic; - - off = sizeof(micbuf); - skb_trim (skb, len - off); - } - } - memcpy(buffer + ETH_ALEN * 2, - ai->rxfids[0].virtual_host_addr + ETH_ALEN * 2 + off, - len - ETH_ALEN * 2 - off); - if (decapsulate (ai, &micbuf, (etherHead*)buffer, len - off - ETH_ALEN * 2)) { -badmic: - dev_kfree_skb_irq (skb); - goto badrx; - } -#ifdef WIRELESS_SPY - if (ai->spy_data.spy_number > 0) { - char *sa; - struct iw_quality wstats; - /* Prepare spy data : addr + qual */ - sa = buffer + ETH_ALEN; - wstats.qual = 0; /* XXX Where do I get that info from ??? */ - wstats.level = 0; - wstats.updated = 0; - /* Update spy records */ - wireless_spy_update(ai->dev, sa, &wstats); - } -#endif /* WIRELESS_SPY */ - - skb->ip_summed = CHECKSUM_NONE; - skb->protocol = eth_type_trans(skb, ai->dev); - netif_rx(skb); - } -badrx: - if (rxd.valid == 0) { - rxd.valid = 1; - rxd.rdy = 0; - rxd.len = PKTSIZE; - memcpy_toio(ai->rxfids[0].card_ram_off, &rxd, sizeof(rxd)); - } -} - -static void mpi_receive_802_11(struct airo_info *ai) -{ - RxFid rxd; - struct sk_buff *skb = NULL; - u16 len, hdrlen = 0; - __le16 fc; - struct rx_hdr hdr; - u16 gap; - u16 *buffer; - char *ptr = ai->rxfids[0].virtual_host_addr + 4; - - memcpy_fromio(&rxd, ai->rxfids[0].card_ram_off, sizeof(rxd)); - memcpy ((char *)&hdr, ptr, sizeof(hdr)); - ptr += sizeof(hdr); - /* Bad CRC. Ignore packet */ - if (le16_to_cpu(hdr.status) & 2) - hdr.len = 0; - if (ai->wifidev == NULL) - hdr.len = 0; - len = le16_to_cpu(hdr.len); - if (len > AIRO_DEF_MTU) { - airo_print_err(ai->dev->name, "Bad size %d", len); - goto badrx; - } - if (len == 0) - goto badrx; - - fc = get_unaligned((__le16 *)ptr); - hdrlen = header_len(fc); - - skb = dev_alloc_skb(len + hdrlen + 2); - if (!skb) { - ai->dev->stats.rx_dropped++; - goto badrx; - } - buffer = skb_put(skb, len + hdrlen); - memcpy ((char *)buffer, ptr, hdrlen); - ptr += hdrlen; - if (hdrlen == 24) - ptr += 6; - gap = get_unaligned_le16(ptr); - ptr += sizeof(__le16); - if (gap) { - if (gap <= 8) - ptr += gap; - else - airo_print_err(ai->dev->name, - "gaplen too big. Problems will follow..."); - } - memcpy ((char *)buffer + hdrlen, ptr, len); - ptr += len; -#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ - if (ai->spy_data.spy_number > 0) { - char *sa; - struct iw_quality wstats; - /* Prepare spy data : addr + qual */ - sa = (char*)buffer + 10; - wstats.qual = hdr.rssi[0]; - if (ai->rssi) - wstats.level = 0x100 - ai->rssi[hdr.rssi[1]].rssidBm; - else - wstats.level = (hdr.rssi[1] + 321) / 2; - wstats.noise = ai->wstats.qual.noise; - wstats.updated = IW_QUAL_QUAL_UPDATED - | IW_QUAL_LEVEL_UPDATED - | IW_QUAL_DBM; - /* Update spy records */ - wireless_spy_update(ai->dev, sa, &wstats); - } -#endif /* IW_WIRELESS_SPY */ - skb_reset_mac_header(skb); - skb->pkt_type = PACKET_OTHERHOST; - skb->dev = ai->wifidev; - skb->protocol = htons(ETH_P_802_2); - skb->ip_summed = CHECKSUM_NONE; - netif_rx(skb); - -badrx: - if (rxd.valid == 0) { - rxd.valid = 1; - rxd.rdy = 0; - rxd.len = PKTSIZE; - memcpy_toio(ai->rxfids[0].card_ram_off, &rxd, sizeof(rxd)); - } -} - -static inline void set_auth_type(struct airo_info *local, int auth_type) -{ - local->config.authType = auth_type; - /* Cache the last auth type used (of AUTH_OPEN and AUTH_ENCRYPT). - * Used by airo_set_auth() - */ - if (auth_type == AUTH_OPEN || auth_type == AUTH_ENCRYPT) - local->last_auth = auth_type; -} - -static int noinline_for_stack airo_readconfig(struct airo_info *ai, - struct net_device *dev, int lock) -{ - int i, status; - /* large variables, so don't inline this function, - * maybe change to kmalloc - */ - tdsRssiRid rssi_rid; - CapabilityRid cap_rid; - - kfree(ai->SSID); - ai->SSID = NULL; - // general configuration (read/modify/write) - status = readConfigRid(ai, lock); - if (status != SUCCESS) return ERROR; - - status = readCapabilityRid(ai, &cap_rid, lock); - if (status != SUCCESS) return ERROR; - - status = PC4500_readrid(ai, RID_RSSI, &rssi_rid, sizeof(rssi_rid), lock); - if (status == SUCCESS) { - if (ai->rssi || (ai->rssi = kmalloc(512, GFP_KERNEL)) != NULL) - memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512); /* Skip RID length member */ - } - else { - kfree(ai->rssi); - ai->rssi = NULL; - if (cap_rid.softCap & cpu_to_le16(8)) - ai->config.rmode |= RXMODE_NORMALIZED_RSSI; - else - airo_print_warn(ai->dev->name, "unknown received signal " - "level scale"); - } - ai->config.opmode = adhoc ? MODE_STA_IBSS : MODE_STA_ESS; - set_auth_type(ai, AUTH_OPEN); - ai->config.modulation = MOD_CCK; - - if (le16_to_cpu(cap_rid.len) >= sizeof(cap_rid) && - (cap_rid.extSoftCap & cpu_to_le16(1)) && - micsetup(ai) == SUCCESS) { - ai->config.opmode |= MODE_MIC; - set_bit(FLAG_MIC_CAPABLE, &ai->flags); - } - - /* Save off the MAC */ - eth_hw_addr_set(dev, ai->config.macAddr); - - /* Check to see if there are any insmod configured - rates to add */ - if (rates[0]) { - memset(ai->config.rates, 0, sizeof(ai->config.rates)); - for (i = 0; i < 8 && rates[i]; i++) { - ai->config.rates[i] = rates[i]; - } - } - set_bit (FLAG_COMMIT, &ai->flags); - - return SUCCESS; -} - - -static u16 setup_card(struct airo_info *ai, struct net_device *dev, int lock) -{ - Cmd cmd; - Resp rsp; - int status; - SsidRid mySsid; - __le16 lastindex; - WepKeyRid wkr; - int rc; - - memset(&mySsid, 0, sizeof(mySsid)); - kfree (ai->flash); - ai->flash = NULL; - - /* The NOP is the first step in getting the card going */ - cmd.cmd = NOP; - cmd.parm0 = cmd.parm1 = cmd.parm2 = 0; - if (lock && down_interruptible(&ai->sem)) - return ERROR; - if (issuecommand(ai, &cmd, &rsp, true) != SUCCESS) { - if (lock) - up(&ai->sem); - return ERROR; - } - disable_MAC(ai, 0); - - // Let's figure out if we need to use the AUX port - if (!test_bit(FLAG_MPI,&ai->flags)) { - cmd.cmd = CMD_ENABLEAUX; - if (issuecommand(ai, &cmd, &rsp, true) != SUCCESS) { - if (lock) - up(&ai->sem); - airo_print_err(ai->dev->name, "Error checking for AUX port"); - return ERROR; - } - if (!aux_bap || rsp.status & 0xff00) { - ai->bap_read = fast_bap_read; - airo_print_dbg(ai->dev->name, "Doing fast bap_reads"); - } else { - ai->bap_read = aux_bap_read; - airo_print_dbg(ai->dev->name, "Doing AUX bap_reads"); - } - } - if (lock) - up(&ai->sem); - if (ai->config.len == 0) { - status = airo_readconfig(ai, dev, lock); - if (status != SUCCESS) - return ERROR; - } - - /* Setup the SSIDs if present */ - if (ssids[0]) { - int i; - for (i = 0; i < 3 && ssids[i]; i++) { - size_t len = strlen(ssids[i]); - if (len > 32) - len = 32; - mySsid.ssids[i].len = cpu_to_le16(len); - memcpy(mySsid.ssids[i].ssid, ssids[i], len); - } - mySsid.len = cpu_to_le16(sizeof(mySsid)); - } - - status = writeConfigRid(ai, lock); - if (status != SUCCESS) return ERROR; - - /* Set up the SSID list */ - if (ssids[0]) { - status = writeSsidRid(ai, &mySsid, lock); - if (status != SUCCESS) return ERROR; - } - - status = enable_MAC(ai, lock); - if (status != SUCCESS) - return ERROR; - - /* Grab the initial wep key, we gotta save it for auto_wep */ - rc = readWepKeyRid(ai, &wkr, 1, lock); - if (rc == SUCCESS) do { - lastindex = wkr.kindex; - if (wkr.kindex == cpu_to_le16(0xffff)) { - ai->defindex = wkr.mac[0]; - } - rc = readWepKeyRid(ai, &wkr, 0, lock); - } while (lastindex != wkr.kindex); - - try_auto_wep(ai); - - return SUCCESS; -} - -static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp, - bool may_sleep) -{ - // Im really paranoid about letting it run forever! - int max_tries = 600000; - - if (IN4500(ai, EVSTAT) & EV_CMD) - OUT4500(ai, EVACK, EV_CMD); - - OUT4500(ai, PARAM0, pCmd->parm0); - OUT4500(ai, PARAM1, pCmd->parm1); - OUT4500(ai, PARAM2, pCmd->parm2); - OUT4500(ai, COMMAND, pCmd->cmd); - - while (max_tries-- && (IN4500(ai, EVSTAT) & EV_CMD) == 0) { - if ((IN4500(ai, COMMAND)) == pCmd->cmd) - // PC4500 didn't notice command, try again - OUT4500(ai, COMMAND, pCmd->cmd); - if (may_sleep && (max_tries & 255) == 0) - cond_resched(); - } - - if (max_tries == -1) { - airo_print_err(ai->dev->name, - "Max tries exceeded when issuing command"); - if (IN4500(ai, COMMAND) & COMMAND_BUSY) - OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY); - return ERROR; - } - - // command completed - pRsp->status = IN4500(ai, STATUS); - pRsp->rsp0 = IN4500(ai, RESP0); - pRsp->rsp1 = IN4500(ai, RESP1); - pRsp->rsp2 = IN4500(ai, RESP2); - if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET) - airo_print_err(ai->dev->name, - "cmd:%x status:%x rsp0:%x rsp1:%x rsp2:%x", - pCmd->cmd, pRsp->status, pRsp->rsp0, pRsp->rsp1, - pRsp->rsp2); - - // clear stuck command busy if necessary - if (IN4500(ai, COMMAND) & COMMAND_BUSY) { - OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY); - } - // acknowledge processing the status/response - OUT4500(ai, EVACK, EV_CMD); - - return SUCCESS; -} - -/* Sets up the bap to start exchange data. whichbap should - * be one of the BAP0 or BAP1 defines. Locks should be held before - * calling! */ -static int bap_setup(struct airo_info *ai, u16 rid, u16 offset, int whichbap) -{ - int timeout = 50; - int max_tries = 3; - - OUT4500(ai, SELECT0+whichbap, rid); - OUT4500(ai, OFFSET0+whichbap, offset); - while (1) { - int status = IN4500(ai, OFFSET0+whichbap); - if (status & BAP_BUSY) { - /* This isn't really a timeout, but its kinda - close */ - if (timeout--) { - continue; - } - } else if (status & BAP_ERR) { - /* invalid rid or offset */ - airo_print_err(ai->dev->name, "BAP error %x %d", - status, whichbap); - return ERROR; - } else if (status & BAP_DONE) { // success - return SUCCESS; - } - if (!(max_tries--)) { - airo_print_err(ai->dev->name, - "BAP setup error too many retries\n"); - return ERROR; - } - // -- PC4500 missed it, try again - OUT4500(ai, SELECT0+whichbap, rid); - OUT4500(ai, OFFSET0+whichbap, offset); - timeout = 50; - } -} - -/* should only be called by aux_bap_read. This aux function and the - following use concepts not documented in the developers guide. I - got them from a patch given to my by Aironet */ -static u16 aux_setup(struct airo_info *ai, u16 page, - u16 offset, u16 *len) -{ - u16 next; - - OUT4500(ai, AUXPAGE, page); - OUT4500(ai, AUXOFF, 0); - next = IN4500(ai, AUXDATA); - *len = IN4500(ai, AUXDATA)&0xff; - if (offset != 4) OUT4500(ai, AUXOFF, offset); - return next; -} - -/* requires call to bap_setup() first */ -static int aux_bap_read(struct airo_info *ai, __le16 *pu16Dst, - int bytelen, int whichbap) -{ - u16 len; - u16 page; - u16 offset; - u16 next; - int words; - int i; - unsigned long flags; - - spin_lock_irqsave(&ai->aux_lock, flags); - page = IN4500(ai, SWS0+whichbap); - offset = IN4500(ai, SWS2+whichbap); - next = aux_setup(ai, page, offset, &len); - words = (bytelen+1)>>1; - - for (i = 0; i>1) < (words-i) ? (len>>1) : (words-i); - if (!do8bitIO) - insw(ai->dev->base_addr+DATA0+whichbap, - pu16Dst+i, count); - else - insb(ai->dev->base_addr+DATA0+whichbap, - pu16Dst+i, count << 1); - i += count; - if (iaux_lock, flags); - return SUCCESS; -} - - -/* requires call to bap_setup() first */ -static int fast_bap_read(struct airo_info *ai, __le16 *pu16Dst, - int bytelen, int whichbap) -{ - bytelen = (bytelen + 1) & (~1); // round up to even value - if (!do8bitIO) - insw(ai->dev->base_addr+DATA0+whichbap, pu16Dst, bytelen>>1); - else - insb(ai->dev->base_addr+DATA0+whichbap, pu16Dst, bytelen); - return SUCCESS; -} - -/* requires call to bap_setup() first */ -static int bap_write(struct airo_info *ai, const __le16 *pu16Src, - int bytelen, int whichbap) -{ - bytelen = (bytelen + 1) & (~1); // round up to even value - if (!do8bitIO) - outsw(ai->dev->base_addr+DATA0+whichbap, - pu16Src, bytelen>>1); - else - outsb(ai->dev->base_addr+DATA0+whichbap, pu16Src, bytelen); - return SUCCESS; -} - -static int PC4500_accessrid(struct airo_info *ai, u16 rid, u16 accmd) -{ - Cmd cmd; /* for issuing commands */ - Resp rsp; /* response from commands */ - u16 status; - - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd = accmd; - cmd.parm0 = rid; - status = issuecommand(ai, &cmd, &rsp, true); - if (status != 0) return status; - if ((rsp.status & 0x7F00) != 0) { - return (accmd << 8) + (rsp.rsp0 & 0xFF); - } - return 0; -} - -/* Note, that we are using BAP1 which is also used by transmit, so - * we must get a lock. */ -static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len, int lock) -{ - u16 status; - int rc = SUCCESS; - - if (lock) { - if (down_interruptible(&ai->sem)) - return ERROR; - } - if (test_bit(FLAG_MPI,&ai->flags)) { - Cmd cmd; - Resp rsp; - - memset(&cmd, 0, sizeof(cmd)); - memset(&rsp, 0, sizeof(rsp)); - ai->config_desc.rid_desc.valid = 1; - ai->config_desc.rid_desc.len = RIDSIZE; - ai->config_desc.rid_desc.rid = 0; - ai->config_desc.rid_desc.host_addr = ai->ridbus; - - cmd.cmd = CMD_ACCESS; - cmd.parm0 = rid; - - memcpy_toio(ai->config_desc.card_ram_off, - &ai->config_desc.rid_desc, sizeof(Rid)); - - rc = issuecommand(ai, &cmd, &rsp, true); - - if (rsp.status & 0x7f00) - rc = rsp.rsp0; - if (!rc) - memcpy(pBuf, ai->config_desc.virtual_host_addr, len); - goto done; - } else { - if ((status = PC4500_accessrid(ai, rid, CMD_ACCESS))!=SUCCESS) { - rc = status; - goto done; - } - if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) { - rc = ERROR; - goto done; - } - // read the rid length field - bap_read(ai, pBuf, 2, BAP1); - // length for remaining part of rid - len = min(len, (int)le16_to_cpu(*(__le16*)pBuf)) - 2; - - if (len <= 2) { - airo_print_err(ai->dev->name, - "Rid %x has a length of %d which is too short", - (int)rid, (int)len); - rc = ERROR; - goto done; - } - // read remainder of the rid - rc = bap_read(ai, ((__le16*)pBuf)+1, len, BAP1); - } -done: - if (lock) - up(&ai->sem); - return rc; -} - -/* Note, that we are using BAP1 which is also used by transmit, so - * make sure this isn't called when a transmit is happening */ -static int PC4500_writerid(struct airo_info *ai, u16 rid, - const void *pBuf, int len, int lock) -{ - u16 status; - int rc = SUCCESS; - - *(__le16*)pBuf = cpu_to_le16((u16)len); - - if (lock) { - if (down_interruptible(&ai->sem)) - return ERROR; - } - if (test_bit(FLAG_MPI,&ai->flags)) { - Cmd cmd; - Resp rsp; - - if (test_bit(FLAG_ENABLED, &ai->flags) && (RID_WEP_TEMP != rid)) - airo_print_err(ai->dev->name, - "%s: MAC should be disabled (rid=%04x)", - __func__, rid); - memset(&cmd, 0, sizeof(cmd)); - memset(&rsp, 0, sizeof(rsp)); - - ai->config_desc.rid_desc.valid = 1; - ai->config_desc.rid_desc.len = *((u16 *)pBuf); - ai->config_desc.rid_desc.rid = 0; - - cmd.cmd = CMD_WRITERID; - cmd.parm0 = rid; - - memcpy_toio(ai->config_desc.card_ram_off, - &ai->config_desc.rid_desc, sizeof(Rid)); - - if (len < 4 || len > 2047) { - airo_print_err(ai->dev->name, "%s: len=%d", __func__, len); - rc = -1; - } else { - memcpy(ai->config_desc.virtual_host_addr, - pBuf, len); - - rc = issuecommand(ai, &cmd, &rsp, true); - if ((rc & 0xff00) != 0) { - airo_print_err(ai->dev->name, "%s: Write rid Error %d", - __func__, rc); - airo_print_err(ai->dev->name, "%s: Cmd=%04x", - __func__, cmd.cmd); - } - - if ((rsp.status & 0x7f00)) - rc = rsp.rsp0; - } - } else { - // --- first access so that we can write the rid data - if ((status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != 0) { - rc = status; - goto done; - } - // --- now write the rid data - if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) { - rc = ERROR; - goto done; - } - bap_write(ai, pBuf, len, BAP1); - // ---now commit the rid data - rc = PC4500_accessrid(ai, rid, 0x100|CMD_ACCESS); - } -done: - if (lock) - up(&ai->sem); - return rc; -} - -/* Allocates a FID to be used for transmitting packets. We only use - one for now. */ -static u16 transmit_allocate(struct airo_info *ai, int lenPayload, int raw) -{ - unsigned int loop = 3000; - Cmd cmd; - Resp rsp; - u16 txFid; - __le16 txControl; - - cmd.cmd = CMD_ALLOCATETX; - cmd.parm0 = lenPayload; - if (down_interruptible(&ai->sem)) - return ERROR; - if (issuecommand(ai, &cmd, &rsp, true) != SUCCESS) { - txFid = ERROR; - goto done; - } - if ((rsp.status & 0xFF00) != 0) { - txFid = ERROR; - goto done; - } - /* wait for the allocate event/indication - * It makes me kind of nervous that this can just sit here and spin, - * but in practice it only loops like four times. */ - while (((IN4500(ai, EVSTAT) & EV_ALLOC) == 0) && --loop); - if (!loop) { - txFid = ERROR; - goto done; - } - - // get the allocated fid and acknowledge - txFid = IN4500(ai, TXALLOCFID); - OUT4500(ai, EVACK, EV_ALLOC); - - /* The CARD is pretty cool since it converts the ethernet packet - * into 802.11. Also note that we don't release the FID since we - * will be using the same one over and over again. */ - /* We only have to setup the control once since we are not - * releasing the fid. */ - if (raw) - txControl = cpu_to_le16(TXCTL_TXOK | TXCTL_TXEX | TXCTL_802_11 - | TXCTL_ETHERNET | TXCTL_NORELEASE); - else - txControl = cpu_to_le16(TXCTL_TXOK | TXCTL_TXEX | TXCTL_802_3 - | TXCTL_ETHERNET | TXCTL_NORELEASE); - if (bap_setup(ai, txFid, 0x0008, BAP1) != SUCCESS) - txFid = ERROR; - else - bap_write(ai, &txControl, sizeof(txControl), BAP1); - -done: - up(&ai->sem); - - return txFid; -} - -/* In general BAP1 is dedicated to transmiting packets. However, - since we need a BAP when accessing RIDs, we also use BAP1 for that. - Make sure the BAP1 spinlock is held when this is called. */ -static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket, - bool may_sleep) -{ - __le16 payloadLen; - Cmd cmd; - Resp rsp; - int miclen = 0; - u16 txFid = len; - MICBuffer pMic; - - len >>= 16; - - if (len <= ETH_ALEN * 2) { - airo_print_warn(ai->dev->name, "Short packet %d", len); - return ERROR; - } - len -= ETH_ALEN * 2; - - if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled && - (ntohs(((__be16 *)pPacket)[6]) != 0x888E)) { - if (encapsulate(ai, (etherHead *)pPacket,&pMic, len) != SUCCESS) - return ERROR; - miclen = sizeof(pMic); - } - // packet is destination[6], source[6], payload[len-12] - // write the payload length and dst/src/payload - if (bap_setup(ai, txFid, 0x0036, BAP1) != SUCCESS) return ERROR; - /* The hardware addresses aren't counted as part of the payload, so - * we have to subtract the 12 bytes for the addresses off */ - payloadLen = cpu_to_le16(len + miclen); - bap_write(ai, &payloadLen, sizeof(payloadLen), BAP1); - bap_write(ai, (__le16*)pPacket, sizeof(etherHead), BAP1); - if (miclen) - bap_write(ai, (__le16*)&pMic, miclen, BAP1); - bap_write(ai, (__le16*)(pPacket + sizeof(etherHead)), len, BAP1); - // issue the transmit command - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd = CMD_TRANSMIT; - cmd.parm0 = txFid; - if (issuecommand(ai, &cmd, &rsp, may_sleep) != SUCCESS) - return ERROR; - if ((rsp.status & 0xFF00) != 0) return ERROR; - return SUCCESS; -} - -static int transmit_802_11_packet(struct airo_info *ai, int len, char *pPacket, - bool may_sleep) -{ - __le16 fc, payloadLen; - Cmd cmd; - Resp rsp; - int hdrlen; - static u8 tail[(30-10) + 2 + 6] = {[30-10] = 6}; - /* padding of header to full size + le16 gaplen (6) + gaplen bytes */ - u16 txFid = len; - len >>= 16; - - fc = *(__le16*)pPacket; - hdrlen = header_len(fc); - - if (len < hdrlen) { - airo_print_warn(ai->dev->name, "Short packet %d", len); - return ERROR; - } - - /* packet is 802.11 header + payload - * write the payload length and dst/src/payload */ - if (bap_setup(ai, txFid, 6, BAP1) != SUCCESS) return ERROR; - /* The 802.11 header aren't counted as part of the payload, so - * we have to subtract the header bytes off */ - payloadLen = cpu_to_le16(len-hdrlen); - bap_write(ai, &payloadLen, sizeof(payloadLen), BAP1); - if (bap_setup(ai, txFid, 0x0014, BAP1) != SUCCESS) return ERROR; - bap_write(ai, (__le16 *)pPacket, hdrlen, BAP1); - bap_write(ai, (__le16 *)(tail + (hdrlen - 10)), 38 - hdrlen, BAP1); - - bap_write(ai, (__le16 *)(pPacket + hdrlen), len - hdrlen, BAP1); - // issue the transmit command - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd = CMD_TRANSMIT; - cmd.parm0 = txFid; - if (issuecommand(ai, &cmd, &rsp, may_sleep) != SUCCESS) - return ERROR; - if ((rsp.status & 0xFF00) != 0) return ERROR; - return SUCCESS; -} - -/* - * This is the proc_fs routines. It is a bit messier than I would - * like! Feel free to clean it up! - */ - -static ssize_t proc_read(struct file *file, - char __user *buffer, - size_t len, - loff_t *offset); - -static ssize_t proc_write(struct file *file, - const char __user *buffer, - size_t len, - loff_t *offset); -static int proc_close(struct inode *inode, struct file *file); - -static int proc_stats_open(struct inode *inode, struct file *file); -static int proc_statsdelta_open(struct inode *inode, struct file *file); -static int proc_status_open(struct inode *inode, struct file *file); -static int proc_SSID_open(struct inode *inode, struct file *file); -static int proc_APList_open(struct inode *inode, struct file *file); -static int proc_BSSList_open(struct inode *inode, struct file *file); -static int proc_config_open(struct inode *inode, struct file *file); -static int proc_wepkey_open(struct inode *inode, struct file *file); - -static const struct proc_ops proc_statsdelta_ops = { - .proc_read = proc_read, - .proc_open = proc_statsdelta_open, - .proc_release = proc_close, - .proc_lseek = default_llseek, -}; - -static const struct proc_ops proc_stats_ops = { - .proc_read = proc_read, - .proc_open = proc_stats_open, - .proc_release = proc_close, - .proc_lseek = default_llseek, -}; - -static const struct proc_ops proc_status_ops = { - .proc_read = proc_read, - .proc_open = proc_status_open, - .proc_release = proc_close, - .proc_lseek = default_llseek, -}; - -static const struct proc_ops proc_SSID_ops = { - .proc_read = proc_read, - .proc_write = proc_write, - .proc_open = proc_SSID_open, - .proc_release = proc_close, - .proc_lseek = default_llseek, -}; - -static const struct proc_ops proc_BSSList_ops = { - .proc_read = proc_read, - .proc_write = proc_write, - .proc_open = proc_BSSList_open, - .proc_release = proc_close, - .proc_lseek = default_llseek, -}; - -static const struct proc_ops proc_APList_ops = { - .proc_read = proc_read, - .proc_write = proc_write, - .proc_open = proc_APList_open, - .proc_release = proc_close, - .proc_lseek = default_llseek, -}; - -static const struct proc_ops proc_config_ops = { - .proc_read = proc_read, - .proc_write = proc_write, - .proc_open = proc_config_open, - .proc_release = proc_close, - .proc_lseek = default_llseek, -}; - -static const struct proc_ops proc_wepkey_ops = { - .proc_read = proc_read, - .proc_write = proc_write, - .proc_open = proc_wepkey_open, - .proc_release = proc_close, - .proc_lseek = default_llseek, -}; - -static struct proc_dir_entry *airo_entry; - -struct proc_data { - int release_buffer; - int readlen; - char *rbuffer; - int writelen; - int maxwritelen; - char *wbuffer; - void (*on_close) (struct inode *, struct file *); -}; - -static int setup_proc_entry(struct net_device *dev, - struct airo_info *apriv) -{ - struct proc_dir_entry *entry; - - /* First setup the device directory */ - strcpy(apriv->proc_name, dev->name); - apriv->proc_entry = proc_mkdir_mode(apriv->proc_name, airo_perm, - airo_entry); - if (!apriv->proc_entry) - return -ENOMEM; - proc_set_user(apriv->proc_entry, proc_kuid, proc_kgid); - - /* Setup the StatsDelta */ - entry = proc_create_data("StatsDelta", 0444 & proc_perm, - apriv->proc_entry, &proc_statsdelta_ops, dev); - if (!entry) - goto fail; - proc_set_user(entry, proc_kuid, proc_kgid); - - /* Setup the Stats */ - entry = proc_create_data("Stats", 0444 & proc_perm, - apriv->proc_entry, &proc_stats_ops, dev); - if (!entry) - goto fail; - proc_set_user(entry, proc_kuid, proc_kgid); - - /* Setup the Status */ - entry = proc_create_data("Status", 0444 & proc_perm, - apriv->proc_entry, &proc_status_ops, dev); - if (!entry) - goto fail; - proc_set_user(entry, proc_kuid, proc_kgid); - - /* Setup the Config */ - entry = proc_create_data("Config", proc_perm, - apriv->proc_entry, &proc_config_ops, dev); - if (!entry) - goto fail; - proc_set_user(entry, proc_kuid, proc_kgid); - - /* Setup the SSID */ - entry = proc_create_data("SSID", proc_perm, - apriv->proc_entry, &proc_SSID_ops, dev); - if (!entry) - goto fail; - proc_set_user(entry, proc_kuid, proc_kgid); - - /* Setup the APList */ - entry = proc_create_data("APList", proc_perm, - apriv->proc_entry, &proc_APList_ops, dev); - if (!entry) - goto fail; - proc_set_user(entry, proc_kuid, proc_kgid); - - /* Setup the BSSList */ - entry = proc_create_data("BSSList", proc_perm, - apriv->proc_entry, &proc_BSSList_ops, dev); - if (!entry) - goto fail; - proc_set_user(entry, proc_kuid, proc_kgid); - - /* Setup the WepKey */ - entry = proc_create_data("WepKey", proc_perm, - apriv->proc_entry, &proc_wepkey_ops, dev); - if (!entry) - goto fail; - proc_set_user(entry, proc_kuid, proc_kgid); - return 0; - -fail: - remove_proc_subtree(apriv->proc_name, airo_entry); - return -ENOMEM; -} - -static int takedown_proc_entry(struct net_device *dev, - struct airo_info *apriv) -{ - remove_proc_subtree(apriv->proc_name, airo_entry); - return 0; -} - -/* - * What we want from the proc_fs is to be able to efficiently read - * and write the configuration. To do this, we want to read the - * configuration when the file is opened and write it when the file is - * closed. So basically we allocate a read buffer at open and fill it - * with data, and allocate a write buffer and read it at close. - */ - -/* - * The read routine is generic, it relies on the preallocated rbuffer - * to supply the data. - */ -static ssize_t proc_read(struct file *file, - char __user *buffer, - size_t len, - loff_t *offset) -{ - struct proc_data *priv = file->private_data; - - if (!priv->rbuffer) - return -EINVAL; - - return simple_read_from_buffer(buffer, len, offset, priv->rbuffer, - priv->readlen); -} - -/* - * The write routine is generic, it fills in a preallocated rbuffer - * to supply the data. - */ -static ssize_t proc_write(struct file *file, - const char __user *buffer, - size_t len, - loff_t *offset) -{ - ssize_t ret; - struct proc_data *priv = file->private_data; - - if (!priv->wbuffer) - return -EINVAL; - - ret = simple_write_to_buffer(priv->wbuffer, priv->maxwritelen, offset, - buffer, len); - if (ret > 0) - priv->writelen = max_t(int, priv->writelen, *offset); - - return ret; -} - -static int proc_status_open(struct inode *inode, struct file *file) -{ - struct proc_data *data; - struct net_device *dev = pde_data(inode); - struct airo_info *apriv = dev->ml_priv; - CapabilityRid cap_rid; - StatusRid status_rid; - u16 mode; - int i; - - if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL) - return -ENOMEM; - data = file->private_data; - if ((data->rbuffer = kmalloc(2048, GFP_KERNEL)) == NULL) { - kfree (file->private_data); - return -ENOMEM; - } - - readStatusRid(apriv, &status_rid, 1); - readCapabilityRid(apriv, &cap_rid, 1); - - mode = le16_to_cpu(status_rid.mode); - - i = sprintf(data->rbuffer, "Status: %s%s%s%s%s%s%s%s%s\n", - mode & 1 ? "CFG ": "", - mode & 2 ? "ACT ": "", - mode & 0x10 ? "SYN ": "", - mode & 0x20 ? "LNK ": "", - mode & 0x40 ? "LEAP ": "", - mode & 0x80 ? "PRIV ": "", - mode & 0x100 ? "KEY ": "", - mode & 0x200 ? "WEP ": "", - mode & 0x8000 ? "ERR ": ""); - sprintf(data->rbuffer+i, "Mode: %x\n" - "Signal Strength: %d\n" - "Signal Quality: %d\n" - "SSID: %-.*s\n" - "AP: %-.16s\n" - "Freq: %d\n" - "BitRate: %dmbs\n" - "Driver Version: %s\n" - "Device: %s\nManufacturer: %s\nFirmware Version: %s\n" - "Radio type: %x\nCountry: %x\nHardware Version: %x\n" - "Software Version: %x\nSoftware Subversion: %x\n" - "Boot block version: %x\n", - le16_to_cpu(status_rid.mode), - le16_to_cpu(status_rid.normalizedSignalStrength), - le16_to_cpu(status_rid.signalQuality), - le16_to_cpu(status_rid.SSIDlen), - status_rid.SSID, - status_rid.apName, - le16_to_cpu(status_rid.channel), - le16_to_cpu(status_rid.currentXmitRate) / 2, - version, - cap_rid.prodName, - cap_rid.manName, - cap_rid.prodVer, - le16_to_cpu(cap_rid.radioType), - le16_to_cpu(cap_rid.country), - le16_to_cpu(cap_rid.hardVer), - le16_to_cpu(cap_rid.softVer), - le16_to_cpu(cap_rid.softSubVer), - le16_to_cpu(cap_rid.bootBlockVer)); - data->readlen = strlen(data->rbuffer); - return 0; -} - -static int proc_stats_rid_open(struct inode*, struct file*, u16); -static int proc_statsdelta_open(struct inode *inode, - struct file *file) -{ - if (file->f_mode&FMODE_WRITE) { - return proc_stats_rid_open(inode, file, RID_STATSDELTACLEAR); - } - return proc_stats_rid_open(inode, file, RID_STATSDELTA); -} - -static int proc_stats_open(struct inode *inode, struct file *file) -{ - return proc_stats_rid_open(inode, file, RID_STATS); -} - -static int proc_stats_rid_open(struct inode *inode, - struct file *file, - u16 rid) -{ - struct proc_data *data; - struct net_device *dev = pde_data(inode); - struct airo_info *apriv = dev->ml_priv; - StatsRid stats; - int i, j; - __le32 *vals = stats.vals; - int len; - - if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL) - return -ENOMEM; - data = file->private_data; - if ((data->rbuffer = kmalloc(4096, GFP_KERNEL)) == NULL) { - kfree (file->private_data); - return -ENOMEM; - } - - readStatsRid(apriv, &stats, rid, 1); - len = le16_to_cpu(stats.len); - - j = 0; - for (i = 0; statsLabels[i]!=(char *)-1 && i*44096) { - airo_print_warn(apriv->dev->name, - "Potentially disastrous buffer overflow averted!"); - break; - } - j+=sprintf(data->rbuffer+j, "%s: %u\n", statsLabels[i], - le32_to_cpu(vals[i])); - } - if (i*4 >= len) { - airo_print_warn(apriv->dev->name, "Got a short rid"); - } - data->readlen = j; - return 0; -} - -static int get_dec_u16(char *buffer, int *start, int limit) -{ - u16 value; - int valid = 0; - for (value = 0; *start < limit && buffer[*start] >= '0' && - buffer[*start] <= '9'; (*start)++) { - valid = 1; - value *= 10; - value += buffer[*start] - '0'; - } - if (!valid) return -1; - return value; -} - -static int airo_config_commit(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra); - -static inline int sniffing_mode(struct airo_info *ai) -{ - return (le16_to_cpu(ai->config.rmode) & le16_to_cpu(RXMODE_MASK)) >= - le16_to_cpu(RXMODE_RFMON); -} - -static void proc_config_on_close(struct inode *inode, struct file *file) -{ - struct proc_data *data = file->private_data; - struct net_device *dev = pde_data(inode); - struct airo_info *ai = dev->ml_priv; - char *line; - - if (!data->writelen) return; - - readConfigRid(ai, 1); - set_bit (FLAG_COMMIT, &ai->flags); - - line = data->wbuffer; - while (line[0]) { -/*** Mode processing */ - if (!strncmp(line, "Mode: ", 6)) { - line += 6; - if (sniffing_mode(ai)) - set_bit (FLAG_RESET, &ai->flags); - ai->config.rmode &= ~RXMODE_FULL_MASK; - clear_bit (FLAG_802_11, &ai->flags); - ai->config.opmode &= ~MODE_CFG_MASK; - ai->config.scanMode = SCANMODE_ACTIVE; - if (line[0] == 'a') { - ai->config.opmode |= MODE_STA_IBSS; - } else { - ai->config.opmode |= MODE_STA_ESS; - if (line[0] == 'r') { - ai->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER; - ai->config.scanMode = SCANMODE_PASSIVE; - set_bit (FLAG_802_11, &ai->flags); - } else if (line[0] == 'y') { - ai->config.rmode |= RXMODE_RFMON_ANYBSS | RXMODE_DISABLE_802_3_HEADER; - ai->config.scanMode = SCANMODE_PASSIVE; - set_bit (FLAG_802_11, &ai->flags); - } else if (line[0] == 'l') - ai->config.rmode |= RXMODE_LANMON; - } - set_bit (FLAG_COMMIT, &ai->flags); - } - -/*** Radio status */ - else if (!strncmp(line,"Radio: ", 7)) { - line += 7; - if (!strncmp(line,"off", 3)) { - set_bit (FLAG_RADIO_OFF, &ai->flags); - } else { - clear_bit (FLAG_RADIO_OFF, &ai->flags); - } - } -/*** NodeName processing */ - else if (!strncmp(line, "NodeName: ", 10)) { - int j; - - line += 10; - memset(ai->config.nodeName, 0, 16); -/* Do the name, assume a space between the mode and node name */ - for (j = 0; j < 16 && line[j] != '\n'; j++) { - ai->config.nodeName[j] = line[j]; - } - set_bit (FLAG_COMMIT, &ai->flags); - } - -/*** PowerMode processing */ - else if (!strncmp(line, "PowerMode: ", 11)) { - line += 11; - if (!strncmp(line, "PSPCAM", 6)) { - ai->config.powerSaveMode = POWERSAVE_PSPCAM; - set_bit (FLAG_COMMIT, &ai->flags); - } else if (!strncmp(line, "PSP", 3)) { - ai->config.powerSaveMode = POWERSAVE_PSP; - set_bit (FLAG_COMMIT, &ai->flags); - } else { - ai->config.powerSaveMode = POWERSAVE_CAM; - set_bit (FLAG_COMMIT, &ai->flags); - } - } else if (!strncmp(line, "DataRates: ", 11)) { - int v, i = 0, k = 0; /* i is index into line, - k is index to rates */ - - line += 11; - while ((v = get_dec_u16(line, &i, 3))!=-1) { - ai->config.rates[k++] = (u8)v; - line += i + 1; - i = 0; - } - set_bit (FLAG_COMMIT, &ai->flags); - } else if (!strncmp(line, "Channel: ", 9)) { - int v, i = 0; - line += 9; - v = get_dec_u16(line, &i, i+3); - if (v != -1) { - ai->config.channelSet = cpu_to_le16(v); - set_bit (FLAG_COMMIT, &ai->flags); - } - } else if (!strncmp(line, "XmitPower: ", 11)) { - int v, i = 0; - line += 11; - v = get_dec_u16(line, &i, i+3); - if (v != -1) { - ai->config.txPower = cpu_to_le16(v); - set_bit (FLAG_COMMIT, &ai->flags); - } - } else if (!strncmp(line, "WEP: ", 5)) { - line += 5; - switch(line[0]) { - case 's': - set_auth_type(ai, AUTH_SHAREDKEY); - break; - case 'e': - set_auth_type(ai, AUTH_ENCRYPT); - break; - default: - set_auth_type(ai, AUTH_OPEN); - break; - } - set_bit (FLAG_COMMIT, &ai->flags); - } else if (!strncmp(line, "LongRetryLimit: ", 16)) { - int v, i = 0; - - line += 16; - v = get_dec_u16(line, &i, 3); - v = (v<0) ? 0 : ((v>255) ? 255 : v); - ai->config.longRetryLimit = cpu_to_le16(v); - set_bit (FLAG_COMMIT, &ai->flags); - } else if (!strncmp(line, "ShortRetryLimit: ", 17)) { - int v, i = 0; - - line += 17; - v = get_dec_u16(line, &i, 3); - v = (v<0) ? 0 : ((v>255) ? 255 : v); - ai->config.shortRetryLimit = cpu_to_le16(v); - set_bit (FLAG_COMMIT, &ai->flags); - } else if (!strncmp(line, "RTSThreshold: ", 14)) { - int v, i = 0; - - line += 14; - v = get_dec_u16(line, &i, 4); - v = (v<0) ? 0 : ((v>AIRO_DEF_MTU) ? AIRO_DEF_MTU : v); - ai->config.rtsThres = cpu_to_le16(v); - set_bit (FLAG_COMMIT, &ai->flags); - } else if (!strncmp(line, "TXMSDULifetime: ", 16)) { - int v, i = 0; - - line += 16; - v = get_dec_u16(line, &i, 5); - v = (v<0) ? 0 : v; - ai->config.txLifetime = cpu_to_le16(v); - set_bit (FLAG_COMMIT, &ai->flags); - } else if (!strncmp(line, "RXMSDULifetime: ", 16)) { - int v, i = 0; - - line += 16; - v = get_dec_u16(line, &i, 5); - v = (v<0) ? 0 : v; - ai->config.rxLifetime = cpu_to_le16(v); - set_bit (FLAG_COMMIT, &ai->flags); - } else if (!strncmp(line, "TXDiversity: ", 13)) { - ai->config.txDiversity = - (line[13]=='l') ? 1 : - ((line[13]=='r')? 2: 3); - set_bit (FLAG_COMMIT, &ai->flags); - } else if (!strncmp(line, "RXDiversity: ", 13)) { - ai->config.rxDiversity = - (line[13]=='l') ? 1 : - ((line[13]=='r')? 2: 3); - set_bit (FLAG_COMMIT, &ai->flags); - } else if (!strncmp(line, "FragThreshold: ", 15)) { - int v, i = 0; - - line += 15; - v = get_dec_u16(line, &i, 4); - v = (v<256) ? 256 : ((v>AIRO_DEF_MTU) ? AIRO_DEF_MTU : v); - v = v & 0xfffe; /* Make sure its even */ - ai->config.fragThresh = cpu_to_le16(v); - set_bit (FLAG_COMMIT, &ai->flags); - } else if (!strncmp(line, "Modulation: ", 12)) { - line += 12; - switch(*line) { - case 'd': ai->config.modulation = MOD_DEFAULT; set_bit(FLAG_COMMIT, &ai->flags); break; - case 'c': ai->config.modulation = MOD_CCK; set_bit(FLAG_COMMIT, &ai->flags); break; - case 'm': ai->config.modulation = MOD_MOK; set_bit(FLAG_COMMIT, &ai->flags); break; - default: airo_print_warn(ai->dev->name, "Unknown modulation"); - } - } else if (!strncmp(line, "Preamble: ", 10)) { - line += 10; - switch(*line) { - case 'a': ai->config.preamble = PREAMBLE_AUTO; set_bit(FLAG_COMMIT, &ai->flags); break; - case 'l': ai->config.preamble = PREAMBLE_LONG; set_bit(FLAG_COMMIT, &ai->flags); break; - case 's': ai->config.preamble = PREAMBLE_SHORT; set_bit(FLAG_COMMIT, &ai->flags); break; - default: airo_print_warn(ai->dev->name, "Unknown preamble"); - } - } else { - airo_print_warn(ai->dev->name, "Couldn't figure out %s", line); - } - while (line[0] && line[0] != '\n') line++; - if (line[0]) line++; - } - airo_config_commit(dev, NULL, NULL, NULL); -} - -static const char *get_rmode(__le16 mode) -{ - switch(mode & RXMODE_MASK) { - case RXMODE_RFMON: return "rfmon"; - case RXMODE_RFMON_ANYBSS: return "yna (any) bss rfmon"; - case RXMODE_LANMON: return "lanmon"; - } - return "ESS"; -} - -static int proc_config_open(struct inode *inode, struct file *file) -{ - struct proc_data *data; - struct net_device *dev = pde_data(inode); - struct airo_info *ai = dev->ml_priv; - int i; - __le16 mode; - - if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL) - return -ENOMEM; - data = file->private_data; - if ((data->rbuffer = kmalloc(2048, GFP_KERNEL)) == NULL) { - kfree (file->private_data); - return -ENOMEM; - } - if ((data->wbuffer = kzalloc(2048, GFP_KERNEL)) == NULL) { - kfree (data->rbuffer); - kfree (file->private_data); - return -ENOMEM; - } - data->maxwritelen = 2048; - data->on_close = proc_config_on_close; - - readConfigRid(ai, 1); - - mode = ai->config.opmode & MODE_CFG_MASK; - i = sprintf(data->rbuffer, - "Mode: %s\n" - "Radio: %s\n" - "NodeName: %-16s\n" - "PowerMode: %s\n" - "DataRates: %d %d %d %d %d %d %d %d\n" - "Channel: %d\n" - "XmitPower: %d\n", - mode == MODE_STA_IBSS ? "adhoc" : - mode == MODE_STA_ESS ? get_rmode(ai->config.rmode): - mode == MODE_AP ? "AP" : - mode == MODE_AP_RPTR ? "AP RPTR" : "Error", - test_bit(FLAG_RADIO_OFF, &ai->flags) ? "off" : "on", - ai->config.nodeName, - ai->config.powerSaveMode == POWERSAVE_CAM ? "CAM" : - ai->config.powerSaveMode == POWERSAVE_PSP ? "PSP" : - ai->config.powerSaveMode == POWERSAVE_PSPCAM ? "PSPCAM" : - "Error", - (int)ai->config.rates[0], - (int)ai->config.rates[1], - (int)ai->config.rates[2], - (int)ai->config.rates[3], - (int)ai->config.rates[4], - (int)ai->config.rates[5], - (int)ai->config.rates[6], - (int)ai->config.rates[7], - le16_to_cpu(ai->config.channelSet), - le16_to_cpu(ai->config.txPower) - ); - sprintf(data->rbuffer + i, - "LongRetryLimit: %d\n" - "ShortRetryLimit: %d\n" - "RTSThreshold: %d\n" - "TXMSDULifetime: %d\n" - "RXMSDULifetime: %d\n" - "TXDiversity: %s\n" - "RXDiversity: %s\n" - "FragThreshold: %d\n" - "WEP: %s\n" - "Modulation: %s\n" - "Preamble: %s\n", - le16_to_cpu(ai->config.longRetryLimit), - le16_to_cpu(ai->config.shortRetryLimit), - le16_to_cpu(ai->config.rtsThres), - le16_to_cpu(ai->config.txLifetime), - le16_to_cpu(ai->config.rxLifetime), - ai->config.txDiversity == 1 ? "left" : - ai->config.txDiversity == 2 ? "right" : "both", - ai->config.rxDiversity == 1 ? "left" : - ai->config.rxDiversity == 2 ? "right" : "both", - le16_to_cpu(ai->config.fragThresh), - ai->config.authType == AUTH_ENCRYPT ? "encrypt" : - ai->config.authType == AUTH_SHAREDKEY ? "shared" : "open", - ai->config.modulation == MOD_DEFAULT ? "default" : - ai->config.modulation == MOD_CCK ? "cck" : - ai->config.modulation == MOD_MOK ? "mok" : "error", - ai->config.preamble == PREAMBLE_AUTO ? "auto" : - ai->config.preamble == PREAMBLE_LONG ? "long" : - ai->config.preamble == PREAMBLE_SHORT ? "short" : "error" - ); - data->readlen = strlen(data->rbuffer); - return 0; -} - -static void proc_SSID_on_close(struct inode *inode, struct file *file) -{ - struct proc_data *data = file->private_data; - struct net_device *dev = pde_data(inode); - struct airo_info *ai = dev->ml_priv; - SsidRid SSID_rid; - int i; - char *p = data->wbuffer; - char *end = p + data->writelen; - - if (!data->writelen) - return; - - *end = '\n'; /* sentinel; we have space for it */ - - memset(&SSID_rid, 0, sizeof(SSID_rid)); - - for (i = 0; i < 3 && p < end; i++) { - int j = 0; - /* copy up to 32 characters from this line */ - while (*p != '\n' && j < 32) - SSID_rid.ssids[i].ssid[j++] = *p++; - if (j == 0) - break; - SSID_rid.ssids[i].len = cpu_to_le16(j); - /* skip to the beginning of the next line */ - while (*p++ != '\n') - ; - } - if (i) - SSID_rid.len = cpu_to_le16(sizeof(SSID_rid)); - disable_MAC(ai, 1); - writeSsidRid(ai, &SSID_rid, 1); - enable_MAC(ai, 1); -} - -static void proc_APList_on_close(struct inode *inode, struct file *file) -{ - struct proc_data *data = file->private_data; - struct net_device *dev = pde_data(inode); - struct airo_info *ai = dev->ml_priv; - APListRid *APList_rid = &ai->APList; - int i; - - if (!data->writelen) return; - - memset(APList_rid, 0, sizeof(*APList_rid)); - APList_rid->len = cpu_to_le16(sizeof(*APList_rid)); - - for (i = 0; i < 4 && data->writelen >= (i + 1) * 6 * 3; i++) - mac_pton(data->wbuffer + i * 6 * 3, APList_rid->ap[i]); - - disable_MAC(ai, 1); - writeAPListRid(ai, APList_rid, 1); - enable_MAC(ai, 1); -} - -/* This function wraps PC4500_writerid with a MAC disable */ -static int do_writerid(struct airo_info *ai, u16 rid, const void *rid_data, - int len, int dummy) -{ - int rc; - - disable_MAC(ai, 1); - rc = PC4500_writerid(ai, rid, rid_data, len, 1); - enable_MAC(ai, 1); - return rc; -} - -/* Returns the WEP key at the specified index, or -1 if that key does - * not exist. The buffer is assumed to be at least 16 bytes in length. - */ -static int get_wep_key(struct airo_info *ai, u16 index, char *buf, u16 buflen) -{ - WepKeyRid wkr; - int rc; - __le16 lastindex; - - rc = readWepKeyRid(ai, &wkr, 1, 1); - if (rc != SUCCESS) - return -1; - do { - lastindex = wkr.kindex; - if (le16_to_cpu(wkr.kindex) == index) { - int klen = min_t(int, buflen, le16_to_cpu(wkr.klen)); - memcpy(buf, wkr.key, klen); - return klen; - } - rc = readWepKeyRid(ai, &wkr, 0, 1); - if (rc != SUCCESS) - return -1; - } while (lastindex != wkr.kindex); - return -1; -} - -static int get_wep_tx_idx(struct airo_info *ai) -{ - WepKeyRid wkr; - int rc; - __le16 lastindex; - - rc = readWepKeyRid(ai, &wkr, 1, 1); - if (rc != SUCCESS) - return -1; - do { - lastindex = wkr.kindex; - if (wkr.kindex == cpu_to_le16(0xffff)) - return wkr.mac[0]; - rc = readWepKeyRid(ai, &wkr, 0, 1); - if (rc != SUCCESS) - return -1; - } while (lastindex != wkr.kindex); - return -1; -} - -static int set_wep_key(struct airo_info *ai, u16 index, const u8 *key, - u16 keylen, int perm, int lock) -{ - static const unsigned char macaddr[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 }; - WepKeyRid wkr; - int rc; - - if (WARN_ON(keylen == 0)) - return -1; - - memset(&wkr, 0, sizeof(wkr)); - wkr.len = cpu_to_le16(sizeof(wkr)); - wkr.kindex = cpu_to_le16(index); - wkr.klen = cpu_to_le16(keylen); - memcpy(wkr.key, key, keylen); - memcpy(wkr.mac, macaddr, ETH_ALEN); - - if (perm) disable_MAC(ai, lock); - rc = writeWepKeyRid(ai, &wkr, perm, lock); - if (perm) enable_MAC(ai, lock); - return rc; -} - -static int set_wep_tx_idx(struct airo_info *ai, u16 index, int perm, int lock) -{ - WepKeyRid wkr; - int rc; - - memset(&wkr, 0, sizeof(wkr)); - wkr.len = cpu_to_le16(sizeof(wkr)); - wkr.kindex = cpu_to_le16(0xffff); - wkr.mac[0] = (char)index; - - if (perm) { - ai->defindex = (char)index; - disable_MAC(ai, lock); - } - - rc = writeWepKeyRid(ai, &wkr, perm, lock); - - if (perm) - enable_MAC(ai, lock); - return rc; -} - -static void proc_wepkey_on_close(struct inode *inode, struct file *file) -{ - struct proc_data *data; - struct net_device *dev = pde_data(inode); - struct airo_info *ai = dev->ml_priv; - int i, rc; - u8 key[16]; - u16 index = 0; - int j = 0; - - memset(key, 0, sizeof(key)); - - data = file->private_data; - if (!data->writelen) return; - - if (data->wbuffer[0] >= '0' && data->wbuffer[0] <= '3' && - (data->wbuffer[1] == ' ' || data->wbuffer[1] == '\n')) { - index = data->wbuffer[0] - '0'; - if (data->wbuffer[1] == '\n') { - rc = set_wep_tx_idx(ai, index, 1, 1); - if (rc < 0) { - airo_print_err(ai->dev->name, "failed to set " - "WEP transmit index to %d: %d.", - index, rc); - } - return; - } - j = 2; - } else { - airo_print_err(ai->dev->name, "WepKey passed invalid key index"); - return; - } - - for (i = 0; i < 16*3 && data->wbuffer[i+j]; i++) { - int val; - - if (i % 3 == 2) - continue; - - val = hex_to_bin(data->wbuffer[i+j]); - if (val < 0) { - airo_print_err(ai->dev->name, "WebKey passed invalid key hex"); - return; - } - switch(i%3) { - case 0: - key[i/3] = (u8)val << 4; - break; - case 1: - key[i/3] |= (u8)val; - break; - } - } - - rc = set_wep_key(ai, index, key, i/3, 1, 1); - if (rc < 0) { - airo_print_err(ai->dev->name, "failed to set WEP key at index " - "%d: %d.", index, rc); - } -} - -static int proc_wepkey_open(struct inode *inode, struct file *file) -{ - struct proc_data *data; - struct net_device *dev = pde_data(inode); - struct airo_info *ai = dev->ml_priv; - char *ptr; - WepKeyRid wkr; - __le16 lastindex; - int j = 0; - int rc; - - if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL) - return -ENOMEM; - memset(&wkr, 0, sizeof(wkr)); - data = file->private_data; - if ((data->rbuffer = kzalloc(180, GFP_KERNEL)) == NULL) { - kfree (file->private_data); - return -ENOMEM; - } - data->writelen = 0; - data->maxwritelen = 80; - if ((data->wbuffer = kzalloc(80, GFP_KERNEL)) == NULL) { - kfree (data->rbuffer); - kfree (file->private_data); - return -ENOMEM; - } - data->on_close = proc_wepkey_on_close; - - ptr = data->rbuffer; - strcpy(ptr, "No wep keys\n"); - rc = readWepKeyRid(ai, &wkr, 1, 1); - if (rc == SUCCESS) do { - lastindex = wkr.kindex; - if (wkr.kindex == cpu_to_le16(0xffff)) { - j += sprintf(ptr+j, "Tx key = %d\n", - (int)wkr.mac[0]); - } else { - j += sprintf(ptr+j, "Key %d set with length = %d\n", - le16_to_cpu(wkr.kindex), - le16_to_cpu(wkr.klen)); - } - readWepKeyRid(ai, &wkr, 0, 1); - } while ((lastindex != wkr.kindex) && (j < 180-30)); - - data->readlen = strlen(data->rbuffer); - return 0; -} - -static int proc_SSID_open(struct inode *inode, struct file *file) -{ - struct proc_data *data; - struct net_device *dev = pde_data(inode); - struct airo_info *ai = dev->ml_priv; - int i; - char *ptr; - SsidRid SSID_rid; - - if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL) - return -ENOMEM; - data = file->private_data; - if ((data->rbuffer = kmalloc(104, GFP_KERNEL)) == NULL) { - kfree (file->private_data); - return -ENOMEM; - } - data->writelen = 0; - data->maxwritelen = 33*3; - /* allocate maxwritelen + 1; we'll want a sentinel */ - if ((data->wbuffer = kzalloc(33*3 + 1, GFP_KERNEL)) == NULL) { - kfree (data->rbuffer); - kfree (file->private_data); - return -ENOMEM; - } - data->on_close = proc_SSID_on_close; - - readSsidRid(ai, &SSID_rid); - ptr = data->rbuffer; - for (i = 0; i < 3; i++) { - int j; - size_t len = le16_to_cpu(SSID_rid.ssids[i].len); - if (!len) - break; - if (len > 32) - len = 32; - for (j = 0; j < len && SSID_rid.ssids[i].ssid[j]; j++) - *ptr++ = SSID_rid.ssids[i].ssid[j]; - *ptr++ = '\n'; - } - *ptr = '\0'; - data->readlen = strlen(data->rbuffer); - return 0; -} - -static int proc_APList_open(struct inode *inode, struct file *file) -{ - struct proc_data *data; - struct net_device *dev = pde_data(inode); - struct airo_info *ai = dev->ml_priv; - int i; - char *ptr; - APListRid *APList_rid = &ai->APList; - - if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL) - return -ENOMEM; - data = file->private_data; - if ((data->rbuffer = kmalloc(104, GFP_KERNEL)) == NULL) { - kfree (file->private_data); - return -ENOMEM; - } - data->writelen = 0; - data->maxwritelen = 4*6*3; - if ((data->wbuffer = kzalloc(data->maxwritelen, GFP_KERNEL)) == NULL) { - kfree (data->rbuffer); - kfree (file->private_data); - return -ENOMEM; - } - data->on_close = proc_APList_on_close; - - ptr = data->rbuffer; - for (i = 0; i < 4; i++) { -// We end when we find a zero MAC - if (!*(int*)APList_rid->ap[i] && - !*(int*)&APList_rid->ap[i][2]) break; - ptr += sprintf(ptr, "%pM\n", APList_rid->ap[i]); - } - if (i==0) ptr += sprintf(ptr, "Not using specific APs\n"); - - *ptr = '\0'; - data->readlen = strlen(data->rbuffer); - return 0; -} - -static int proc_BSSList_open(struct inode *inode, struct file *file) -{ - struct proc_data *data; - struct net_device *dev = pde_data(inode); - struct airo_info *ai = dev->ml_priv; - char *ptr; - BSSListRid BSSList_rid; - int rc; - /* If doLoseSync is not 1, we won't do a Lose Sync */ - int doLoseSync = -1; - - if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL) - return -ENOMEM; - data = file->private_data; - if ((data->rbuffer = kmalloc(1024, GFP_KERNEL)) == NULL) { - kfree (file->private_data); - return -ENOMEM; - } - data->writelen = 0; - data->maxwritelen = 0; - data->wbuffer = NULL; - data->on_close = NULL; - - if (file->f_mode & FMODE_WRITE) { - if (!(file->f_mode & FMODE_READ)) { - Cmd cmd; - Resp rsp; - - if (ai->flags & FLAG_RADIO_MASK) { - kfree(data->rbuffer); - kfree(file->private_data); - return -ENETDOWN; - } - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd = CMD_LISTBSS; - if (down_interruptible(&ai->sem)) { - kfree(data->rbuffer); - kfree(file->private_data); - return -ERESTARTSYS; - } - issuecommand(ai, &cmd, &rsp, true); - up(&ai->sem); - data->readlen = 0; - return 0; - } - doLoseSync = 1; - } - ptr = data->rbuffer; - /* There is a race condition here if there are concurrent opens. - Since it is a rare condition, we'll just live with it, otherwise - we have to add a spin lock... */ - rc = readBSSListRid(ai, doLoseSync, &BSSList_rid); - while (rc == 0 && BSSList_rid.index != cpu_to_le16(0xffff)) { - ptr += sprintf(ptr, "%pM %.*s rssi = %d", - BSSList_rid.bssid, - (int)BSSList_rid.ssidLen, - BSSList_rid.ssid, - le16_to_cpu(BSSList_rid.dBm)); - ptr += sprintf(ptr, " channel = %d %s %s %s %s\n", - le16_to_cpu(BSSList_rid.dsChannel), - BSSList_rid.cap & CAP_ESS ? "ESS" : "", - BSSList_rid.cap & CAP_IBSS ? "adhoc" : "", - BSSList_rid.cap & CAP_PRIVACY ? "wep" : "", - BSSList_rid.cap & CAP_SHORTHDR ? "shorthdr" : ""); - rc = readBSSListRid(ai, 0, &BSSList_rid); - } - *ptr = '\0'; - data->readlen = strlen(data->rbuffer); - return 0; -} - -static int proc_close(struct inode *inode, struct file *file) -{ - struct proc_data *data = file->private_data; - - if (data->on_close != NULL) - data->on_close(inode, file); - kfree(data->rbuffer); - kfree(data->wbuffer); - kfree(data); - return 0; -} - -/* Since the card doesn't automatically switch to the right WEP mode, - we will make it do it. If the card isn't associated, every secs we - will switch WEP modes to see if that will help. If the card is - associated we will check every minute to see if anything has - changed. */ -static void timer_func(struct net_device *dev) -{ - struct airo_info *apriv = dev->ml_priv; - -/* We don't have a link so try changing the authtype */ - readConfigRid(apriv, 0); - disable_MAC(apriv, 0); - switch(apriv->config.authType) { - case AUTH_ENCRYPT: -/* So drop to OPEN */ - apriv->config.authType = AUTH_OPEN; - break; - case AUTH_SHAREDKEY: - if (apriv->keyindex < auto_wep) { - set_wep_tx_idx(apriv, apriv->keyindex, 0, 0); - apriv->config.authType = AUTH_SHAREDKEY; - apriv->keyindex++; - } else { - /* Drop to ENCRYPT */ - apriv->keyindex = 0; - set_wep_tx_idx(apriv, apriv->defindex, 0, 0); - apriv->config.authType = AUTH_ENCRYPT; - } - break; - default: /* We'll escalate to SHAREDKEY */ - apriv->config.authType = AUTH_SHAREDKEY; - } - set_bit (FLAG_COMMIT, &apriv->flags); - writeConfigRid(apriv, 0); - enable_MAC(apriv, 0); - up(&apriv->sem); - -/* Schedule check to see if the change worked */ - clear_bit(JOB_AUTOWEP, &apriv->jobs); - apriv->expires = RUN_AT(HZ*3); -} - -#ifdef CONFIG_PCI -static int airo_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *pent) -{ - struct net_device *dev; - - if (pci_enable_device(pdev)) - return -ENODEV; - pci_set_master(pdev); - - if (pdev->device == 0x5000 || pdev->device == 0xa504) - dev = _init_airo_card(pdev->irq, pdev->resource[0].start, 0, pdev, &pdev->dev); - else - dev = _init_airo_card(pdev->irq, pdev->resource[2].start, 0, pdev, &pdev->dev); - if (!dev) { - pci_disable_device(pdev); - return -ENODEV; - } - - pci_set_drvdata(pdev, dev); - return 0; -} - -static void airo_pci_remove(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - - airo_print_info(dev->name, "Unregistering..."); - stop_airo_card(dev, 1); - pci_disable_device(pdev); -} - -static int __maybe_unused airo_pci_suspend(struct device *dev_d) -{ - struct net_device *dev = dev_get_drvdata(dev_d); - struct airo_info *ai = dev->ml_priv; - Cmd cmd; - Resp rsp; - - if (!ai->SSID) - ai->SSID = kmalloc(sizeof(SsidRid), GFP_KERNEL); - if (!ai->SSID) - return -ENOMEM; - readSsidRid(ai, ai->SSID); - memset(&cmd, 0, sizeof(cmd)); - /* the lock will be released at the end of the resume callback */ - if (down_interruptible(&ai->sem)) - return -EAGAIN; - disable_MAC(ai, 0); - netif_device_detach(dev); - ai->power = PMSG_SUSPEND; - cmd.cmd = HOSTSLEEP; - issuecommand(ai, &cmd, &rsp, true); - - device_wakeup_enable(dev_d); - return 0; -} - -static int __maybe_unused airo_pci_resume(struct device *dev_d) -{ - struct net_device *dev = dev_get_drvdata(dev_d); - struct airo_info *ai = dev->ml_priv; - pci_power_t prev_state = to_pci_dev(dev_d)->current_state; - - device_wakeup_disable(dev_d); - - if (prev_state != PCI_D1) { - reset_card(dev, 0); - mpi_init_descriptors(ai); - setup_card(ai, dev, 0); - clear_bit(FLAG_RADIO_OFF, &ai->flags); - clear_bit(FLAG_PENDING_XMIT, &ai->flags); - } else { - OUT4500(ai, EVACK, EV_AWAKEN); - OUT4500(ai, EVACK, EV_AWAKEN); - msleep(100); - } - - set_bit(FLAG_COMMIT, &ai->flags); - disable_MAC(ai, 0); - msleep(200); - if (ai->SSID) { - writeSsidRid(ai, ai->SSID, 0); - kfree(ai->SSID); - ai->SSID = NULL; - } - writeAPListRid(ai, &ai->APList, 0); - writeConfigRid(ai, 0); - enable_MAC(ai, 0); - ai->power = PMSG_ON; - netif_device_attach(dev); - netif_wake_queue(dev); - enable_interrupts(ai); - up(&ai->sem); - return 0; -} -#endif - -static int __init airo_init_module(void) -{ - int i; - - proc_kuid = make_kuid(&init_user_ns, proc_uid); - proc_kgid = make_kgid(&init_user_ns, proc_gid); - if (!uid_valid(proc_kuid) || !gid_valid(proc_kgid)) - return -EINVAL; - - airo_entry = proc_mkdir_mode("driver/aironet", airo_perm, NULL); - - if (airo_entry) - proc_set_user(airo_entry, proc_kuid, proc_kgid); - - for (i = 0; i < 4 && io[i] && irq[i]; i++) { - airo_print_info("", "Trying to configure ISA adapter at irq=%d " - "io = 0x%x", irq[i], io[i]); - if (init_airo_card(irq[i], io[i], 0, NULL)) { - /* do nothing */ ; - } - } - -#ifdef CONFIG_PCI - airo_print_info("", "Probing for PCI adapters"); - i = pci_register_driver(&airo_driver); - airo_print_info("", "Finished probing for PCI adapters"); - - if (i) { - remove_proc_entry("driver/aironet", NULL); - return i; - } -#endif - - /* Always exit with success, as we are a library module - * as well as a driver module - */ - return 0; -} - -static void __exit airo_cleanup_module(void) -{ - struct airo_info *ai; - while (!list_empty(&airo_devices)) { - ai = list_entry(airo_devices.next, struct airo_info, dev_list); - airo_print_info(ai->dev->name, "Unregistering..."); - stop_airo_card(ai->dev, 1); - } -#ifdef CONFIG_PCI - pci_unregister_driver(&airo_driver); -#endif - remove_proc_entry("driver/aironet", NULL); -} - -/* - * Initial Wireless Extension code for Aironet driver by : - * Jean Tourrilhes - HPL - 17 November 00 - * Conversion to new driver API by : - * Jean Tourrilhes - HPL - 26 March 02 - * Javier also did a good amount of work here, adding some new extensions - * and fixing my code. Let's just say that without him this code just - * would not work at all... - Jean II - */ - -static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi) -{ - if (!rssi_rid) - return 0; - - return (0x100 - rssi_rid[rssi].rssidBm); -} - -static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm) -{ - int i; - - if (!rssi_rid) - return 0; - - for (i = 0; i < 256; i++) - if (rssi_rid[i].rssidBm == dbm) - return rssi_rid[i].rssipct; - - return 0; -} - - -static int airo_get_quality (StatusRid *status_rid, CapabilityRid *cap_rid) -{ - int quality = 0; - u16 sq; - - if ((status_rid->mode & cpu_to_le16(0x3f)) != cpu_to_le16(0x3f)) - return 0; - - if (!(cap_rid->hardCap & cpu_to_le16(8))) - return 0; - - sq = le16_to_cpu(status_rid->signalQuality); - if (memcmp(cap_rid->prodName, "350", 3)) - if (sq > 0x20) - quality = 0; - else - quality = 0x20 - sq; - else - if (sq > 0xb0) - quality = 0; - else if (sq < 0x10) - quality = 0xa0; - else - quality = 0xb0 - sq; - return quality; -} - -#define airo_get_max_quality(cap_rid) (memcmp((cap_rid)->prodName, "350", 3) ? 0x20 : 0xa0) -#define airo_get_avg_quality(cap_rid) (memcmp((cap_rid)->prodName, "350", 3) ? 0x10 : 0x50) - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get protocol name - */ -static int airo_get_name(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *cwrq, - char *extra) -{ - strcpy(cwrq->name, "IEEE 802.11-DS"); - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set frequency - */ -static int airo_set_freq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_freq *fwrq = &wrqu->freq; - struct airo_info *local = dev->ml_priv; - int rc = -EINPROGRESS; /* Call commit handler */ - - /* If setting by frequency, convert to a channel */ - if (fwrq->e == 1) { - int f = fwrq->m / 100000; - - /* Hack to fall through... */ - fwrq->e = 0; - fwrq->m = ieee80211_frequency_to_channel(f); - } - /* Setting by channel number */ - if (fwrq->m < 0 || fwrq->m > 1000 || fwrq->e > 0) - rc = -EOPNOTSUPP; - else { - int channel = fwrq->m; - /* We should do a better check than that, - * based on the card capability !!! */ - if ((channel < 1) || (channel > 14)) { - airo_print_dbg(dev->name, "New channel value of %d is invalid!", - fwrq->m); - rc = -EINVAL; - } else { - readConfigRid(local, 1); - /* Yes ! We can set it !!! */ - local->config.channelSet = cpu_to_le16(channel); - set_bit (FLAG_COMMIT, &local->flags); - } - } - return rc; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get frequency - */ -static int airo_get_freq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_freq *fwrq = &wrqu->freq; - struct airo_info *local = dev->ml_priv; - StatusRid status_rid; /* Card status info */ - int ch; - - readConfigRid(local, 1); - if ((local->config.opmode & MODE_CFG_MASK) == MODE_STA_ESS) - status_rid.channel = local->config.channelSet; - else - readStatusRid(local, &status_rid, 1); - - ch = le16_to_cpu(status_rid.channel); - if ((ch > 0) && (ch < 15)) { - fwrq->m = 100000 * - ieee80211_channel_to_frequency(ch, NL80211_BAND_2GHZ); - fwrq->e = 1; - } else { - fwrq->m = ch; - fwrq->e = 0; - } - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set ESSID - */ -static int airo_set_essid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->essid; - struct airo_info *local = dev->ml_priv; - SsidRid SSID_rid; /* SSIDs */ - - /* Reload the list of current SSID */ - readSsidRid(local, &SSID_rid); - - /* Check if we asked for `any' */ - if (dwrq->flags == 0) { - /* Just send an empty SSID list */ - memset(&SSID_rid, 0, sizeof(SSID_rid)); - } else { - unsigned index = (dwrq->flags & IW_ENCODE_INDEX) - 1; - - /* Check the size of the string */ - if (dwrq->length > IW_ESSID_MAX_SIZE) - return -E2BIG ; - - /* Check if index is valid */ - if (index >= ARRAY_SIZE(SSID_rid.ssids)) - return -EINVAL; - - /* Set the SSID */ - memset(SSID_rid.ssids[index].ssid, 0, - sizeof(SSID_rid.ssids[index].ssid)); - memcpy(SSID_rid.ssids[index].ssid, extra, dwrq->length); - SSID_rid.ssids[index].len = cpu_to_le16(dwrq->length); - } - SSID_rid.len = cpu_to_le16(sizeof(SSID_rid)); - /* Write it to the card */ - disable_MAC(local, 1); - writeSsidRid(local, &SSID_rid, 1); - enable_MAC(local, 1); - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get ESSID - */ -static int airo_get_essid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->essid; - struct airo_info *local = dev->ml_priv; - StatusRid status_rid; /* Card status info */ - - readStatusRid(local, &status_rid, 1); - - /* Note : if dwrq->flags != 0, we should - * get the relevant SSID from the SSID list... */ - - /* Get the current SSID */ - memcpy(extra, status_rid.SSID, le16_to_cpu(status_rid.SSIDlen)); - /* If none, we may want to get the one that was set */ - - /* Push it out ! */ - dwrq->length = le16_to_cpu(status_rid.SSIDlen); - dwrq->flags = 1; /* active */ - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set AP address - */ -static int airo_set_wap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct sockaddr *awrq = &wrqu->ap_addr; - struct airo_info *local = dev->ml_priv; - Cmd cmd; - Resp rsp; - APListRid *APList_rid = &local->APList; - - if (awrq->sa_family != ARPHRD_ETHER) - return -EINVAL; - else if (is_broadcast_ether_addr(awrq->sa_data) || - is_zero_ether_addr(awrq->sa_data)) { - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd = CMD_LOSE_SYNC; - if (down_interruptible(&local->sem)) - return -ERESTARTSYS; - issuecommand(local, &cmd, &rsp, true); - up(&local->sem); - } else { - memset(APList_rid, 0, sizeof(*APList_rid)); - APList_rid->len = cpu_to_le16(sizeof(*APList_rid)); - memcpy(APList_rid->ap[0], awrq->sa_data, ETH_ALEN); - disable_MAC(local, 1); - writeAPListRid(local, APList_rid, 1); - enable_MAC(local, 1); - } - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get AP address - */ -static int airo_get_wap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct sockaddr *awrq = &wrqu->ap_addr; - struct airo_info *local = dev->ml_priv; - StatusRid status_rid; /* Card status info */ - - readStatusRid(local, &status_rid, 1); - - /* Tentative. This seems to work, wow, I'm lucky !!! */ - memcpy(awrq->sa_data, status_rid.bssid[0], ETH_ALEN); - awrq->sa_family = ARPHRD_ETHER; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Nickname - */ -static int airo_set_nick(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->data; - struct airo_info *local = dev->ml_priv; - - /* Check the size of the string */ - if (dwrq->length > 16) { - return -E2BIG; - } - readConfigRid(local, 1); - memset(local->config.nodeName, 0, sizeof(local->config.nodeName)); - memcpy(local->config.nodeName, extra, dwrq->length); - set_bit (FLAG_COMMIT, &local->flags); - - return -EINPROGRESS; /* Call commit handler */ -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Nickname - */ -static int airo_get_nick(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->data; - struct airo_info *local = dev->ml_priv; - - readConfigRid(local, 1); - strncpy(extra, local->config.nodeName, 16); - extra[16] = '\0'; - dwrq->length = strlen(extra); - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Bit-Rate - */ -static int airo_set_rate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->bitrate; - struct airo_info *local = dev->ml_priv; - CapabilityRid cap_rid; /* Card capability info */ - u8 brate = 0; - int i; - - /* First : get a valid bit rate value */ - readCapabilityRid(local, &cap_rid, 1); - - /* Which type of value ? */ - if ((vwrq->value < 8) && (vwrq->value >= 0)) { - /* Setting by rate index */ - /* Find value in the magic rate table */ - brate = cap_rid.supportedRates[vwrq->value]; - } else { - /* Setting by frequency value */ - u8 normvalue = (u8) (vwrq->value/500000); - - /* Check if rate is valid */ - for (i = 0 ; i < 8 ; i++) { - if (normvalue == cap_rid.supportedRates[i]) { - brate = normvalue; - break; - } - } - } - /* -1 designed the max rate (mostly auto mode) */ - if (vwrq->value == -1) { - /* Get the highest available rate */ - for (i = 0 ; i < 8 ; i++) { - if (cap_rid.supportedRates[i] == 0) - break; - } - if (i != 0) - brate = cap_rid.supportedRates[i - 1]; - } - /* Check that it is valid */ - if (brate == 0) { - return -EINVAL; - } - - readConfigRid(local, 1); - /* Now, check if we want a fixed or auto value */ - if (vwrq->fixed == 0) { - /* Fill all the rates up to this max rate */ - memset(local->config.rates, 0, 8); - for (i = 0 ; i < 8 ; i++) { - local->config.rates[i] = cap_rid.supportedRates[i]; - if (local->config.rates[i] == brate) - break; - } - } else { - /* Fixed mode */ - /* One rate, fixed */ - memset(local->config.rates, 0, 8); - local->config.rates[0] = brate; - } - set_bit (FLAG_COMMIT, &local->flags); - - return -EINPROGRESS; /* Call commit handler */ -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Bit-Rate - */ -static int airo_get_rate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->bitrate; - struct airo_info *local = dev->ml_priv; - StatusRid status_rid; /* Card status info */ - int ret; - - ret = readStatusRid(local, &status_rid, 1); - if (ret) - return -EBUSY; - - vwrq->value = le16_to_cpu(status_rid.currentXmitRate) * 500000; - /* If more than one rate, set auto */ - readConfigRid(local, 1); - vwrq->fixed = (local->config.rates[1] == 0); - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set RTS threshold - */ -static int airo_set_rts(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->rts; - struct airo_info *local = dev->ml_priv; - int rthr = vwrq->value; - - if (vwrq->disabled) - rthr = AIRO_DEF_MTU; - if ((rthr < 0) || (rthr > AIRO_DEF_MTU)) { - return -EINVAL; - } - readConfigRid(local, 1); - local->config.rtsThres = cpu_to_le16(rthr); - set_bit (FLAG_COMMIT, &local->flags); - - return -EINPROGRESS; /* Call commit handler */ -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get RTS threshold - */ -static int airo_get_rts(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->rts; - struct airo_info *local = dev->ml_priv; - - readConfigRid(local, 1); - vwrq->value = le16_to_cpu(local->config.rtsThres); - vwrq->disabled = (vwrq->value >= AIRO_DEF_MTU); - vwrq->fixed = 1; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Fragmentation threshold - */ -static int airo_set_frag(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *vwrq = &wrqu->frag; - struct airo_info *local = dev->ml_priv; - int fthr = vwrq->value; - - if (vwrq->disabled) - fthr = AIRO_DEF_MTU; - if ((fthr < 256) || (fthr > AIRO_DEF_MTU)) { - return -EINVAL; - } - fthr &= ~0x1; /* Get an even value - is it really needed ??? */ - readConfigRid(local, 1); - local->config.fragThresh = cpu_to_le16(fthr); - set_bit (FLAG_COMMIT, &local->flags); - - return -EINPROGRESS; /* Call commit handler */ -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Fragmentation threshold - */ -static int airo_get_frag(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->frag; - struct airo_info *local = dev->ml_priv; - - readConfigRid(local, 1); - vwrq->value = le16_to_cpu(local->config.fragThresh); - vwrq->disabled = (vwrq->value >= AIRO_DEF_MTU); - vwrq->fixed = 1; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Mode of Operation - */ -static int airo_set_mode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *uwrq, - char *extra) -{ - __u32 mode = uwrq->mode; - struct airo_info *local = dev->ml_priv; - int reset = 0; - - readConfigRid(local, 1); - if (sniffing_mode(local)) - reset = 1; - - switch (mode) { - case IW_MODE_ADHOC: - local->config.opmode &= ~MODE_CFG_MASK; - local->config.opmode |= MODE_STA_IBSS; - local->config.rmode &= ~RXMODE_FULL_MASK; - local->config.scanMode = SCANMODE_ACTIVE; - clear_bit (FLAG_802_11, &local->flags); - break; - case IW_MODE_INFRA: - local->config.opmode &= ~MODE_CFG_MASK; - local->config.opmode |= MODE_STA_ESS; - local->config.rmode &= ~RXMODE_FULL_MASK; - local->config.scanMode = SCANMODE_ACTIVE; - clear_bit (FLAG_802_11, &local->flags); - break; - case IW_MODE_MASTER: - local->config.opmode &= ~MODE_CFG_MASK; - local->config.opmode |= MODE_AP; - local->config.rmode &= ~RXMODE_FULL_MASK; - local->config.scanMode = SCANMODE_ACTIVE; - clear_bit (FLAG_802_11, &local->flags); - break; - case IW_MODE_REPEAT: - local->config.opmode &= ~MODE_CFG_MASK; - local->config.opmode |= MODE_AP_RPTR; - local->config.rmode &= ~RXMODE_FULL_MASK; - local->config.scanMode = SCANMODE_ACTIVE; - clear_bit (FLAG_802_11, &local->flags); - break; - case IW_MODE_MONITOR: - local->config.opmode &= ~MODE_CFG_MASK; - local->config.opmode |= MODE_STA_ESS; - local->config.rmode &= ~RXMODE_FULL_MASK; - local->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER; - local->config.scanMode = SCANMODE_PASSIVE; - set_bit (FLAG_802_11, &local->flags); - break; - default: - return -EINVAL; - } - if (reset) - set_bit (FLAG_RESET, &local->flags); - set_bit (FLAG_COMMIT, &local->flags); - - return -EINPROGRESS; /* Call commit handler */ -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Mode of Operation - */ -static int airo_get_mode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *uwrq, - char *extra) -{ - struct airo_info *local = dev->ml_priv; - - readConfigRid(local, 1); - /* If not managed, assume it's ad-hoc */ - switch (local->config.opmode & MODE_CFG_MASK) { - case MODE_STA_ESS: - uwrq->mode = IW_MODE_INFRA; - break; - case MODE_AP: - uwrq->mode = IW_MODE_MASTER; - break; - case MODE_AP_RPTR: - uwrq->mode = IW_MODE_REPEAT; - break; - default: - uwrq->mode = IW_MODE_ADHOC; - } - - return 0; -} - -static inline int valid_index(struct airo_info *ai, int index) -{ - return (index >= 0) && (index <= ai->max_wep_idx); -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Encryption Key - */ -static int airo_set_encode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->encoding; - struct airo_info *local = dev->ml_priv; - int perm = (dwrq->flags & IW_ENCODE_TEMP ? 0 : 1); - __le16 currentAuthType = local->config.authType; - int rc = 0; - - if (!local->wep_capable) - return -EOPNOTSUPP; - - readConfigRid(local, 1); - - /* Basic checking: do we have a key to set ? - * Note : with the new API, it's impossible to get a NULL pointer. - * Therefore, we need to check a key size == 0 instead. - * New version of iwconfig properly set the IW_ENCODE_NOKEY flag - * when no key is present (only change flags), but older versions - * don't do it. - Jean II */ - if (dwrq->length > 0) { - wep_key_t key; - int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; - int current_index; - - /* Check the size of the key */ - if (dwrq->length > MAX_KEY_SIZE) { - return -EINVAL; - } - - current_index = get_wep_tx_idx(local); - if (current_index < 0) - current_index = 0; - - /* Check the index (none -> use current) */ - if (!valid_index(local, index)) - index = current_index; - - /* Set the length */ - if (dwrq->length > MIN_KEY_SIZE) - key.len = MAX_KEY_SIZE; - else - key.len = MIN_KEY_SIZE; - /* Check if the key is not marked as invalid */ - if (!(dwrq->flags & IW_ENCODE_NOKEY)) { - /* Cleanup */ - memset(key.key, 0, MAX_KEY_SIZE); - /* Copy the key in the driver */ - memcpy(key.key, extra, dwrq->length); - /* Send the key to the card */ - rc = set_wep_key(local, index, key.key, key.len, perm, 1); - if (rc < 0) { - airo_print_err(local->dev->name, "failed to set" - " WEP key at index %d: %d.", - index, rc); - return rc; - } - } - /* WE specify that if a valid key is set, encryption - * should be enabled (user may turn it off later) - * This is also how "iwconfig ethX key on" works */ - if ((index == current_index) && (key.len > 0) && - (local->config.authType == AUTH_OPEN)) - set_auth_type(local, AUTH_ENCRYPT); - } else { - /* Do we want to just set the transmit key index ? */ - int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; - if (valid_index(local, index)) { - rc = set_wep_tx_idx(local, index, perm, 1); - if (rc < 0) { - airo_print_err(local->dev->name, "failed to set" - " WEP transmit index to %d: %d.", - index, rc); - return rc; - } - } else { - /* Don't complain if only change the mode */ - if (!(dwrq->flags & IW_ENCODE_MODE)) - return -EINVAL; - } - } - /* Read the flags */ - if (dwrq->flags & IW_ENCODE_DISABLED) - set_auth_type(local, AUTH_OPEN); /* disable encryption */ - if (dwrq->flags & IW_ENCODE_RESTRICTED) - set_auth_type(local, AUTH_SHAREDKEY); /* Only Both */ - if (dwrq->flags & IW_ENCODE_OPEN) - set_auth_type(local, AUTH_ENCRYPT); /* Only Wep */ - /* Commit the changes to flags if needed */ - if (local->config.authType != currentAuthType) - set_bit (FLAG_COMMIT, &local->flags); - return -EINPROGRESS; /* Call commit handler */ -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Encryption Key - */ -static int airo_get_encode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->encoding; - struct airo_info *local = dev->ml_priv; - int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; - int wep_key_len; - u8 buf[16]; - - if (!local->wep_capable) - return -EOPNOTSUPP; - - readConfigRid(local, 1); - - /* Check encryption mode */ - switch(local->config.authType) { - case AUTH_ENCRYPT: - dwrq->flags = IW_ENCODE_OPEN; - break; - case AUTH_SHAREDKEY: - dwrq->flags = IW_ENCODE_RESTRICTED; - break; - default: - case AUTH_OPEN: - dwrq->flags = IW_ENCODE_DISABLED; - break; - } - /* We can't return the key, so set the proper flag and return zero */ - dwrq->flags |= IW_ENCODE_NOKEY; - memset(extra, 0, 16); - - /* Which key do we want ? -1 -> tx index */ - if (!valid_index(local, index)) { - index = get_wep_tx_idx(local); - if (index < 0) - index = 0; - } - dwrq->flags |= index + 1; - - /* Copy the key to the user buffer */ - wep_key_len = get_wep_key(local, index, &buf[0], sizeof(buf)); - if (wep_key_len < 0) { - dwrq->length = 0; - } else { - dwrq->length = wep_key_len; - memcpy(extra, buf, dwrq->length); - } - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set extended Encryption parameters - */ -static int airo_set_encodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct airo_info *local = dev->ml_priv; - struct iw_point *encoding = &wrqu->encoding; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - int perm = (encoding->flags & IW_ENCODE_TEMP ? 0 : 1); - __le16 currentAuthType = local->config.authType; - int idx, key_len, alg = ext->alg, set_key = 1, rc; - wep_key_t key; - - if (!local->wep_capable) - return -EOPNOTSUPP; - - readConfigRid(local, 1); - - /* Determine and validate the key index */ - idx = encoding->flags & IW_ENCODE_INDEX; - if (idx) { - if (!valid_index(local, idx - 1)) - return -EINVAL; - idx--; - } else { - idx = get_wep_tx_idx(local); - if (idx < 0) - idx = 0; - } - - if (encoding->flags & IW_ENCODE_DISABLED) - alg = IW_ENCODE_ALG_NONE; - - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { - /* Only set transmit key index here, actual - * key is set below if needed. - */ - rc = set_wep_tx_idx(local, idx, perm, 1); - if (rc < 0) { - airo_print_err(local->dev->name, "failed to set " - "WEP transmit index to %d: %d.", - idx, rc); - return rc; - } - set_key = ext->key_len > 0 ? 1 : 0; - } - - if (set_key) { - /* Set the requested key first */ - memset(key.key, 0, MAX_KEY_SIZE); - switch (alg) { - case IW_ENCODE_ALG_NONE: - key.len = 0; - break; - case IW_ENCODE_ALG_WEP: - if (ext->key_len > MIN_KEY_SIZE) { - key.len = MAX_KEY_SIZE; - } else if (ext->key_len > 0) { - key.len = MIN_KEY_SIZE; - } else { - return -EINVAL; - } - key_len = min (ext->key_len, key.len); - memcpy(key.key, ext->key, key_len); - break; - default: - return -EINVAL; - } - if (key.len == 0) { - rc = set_wep_tx_idx(local, idx, perm, 1); - if (rc < 0) { - airo_print_err(local->dev->name, - "failed to set WEP transmit index to %d: %d.", - idx, rc); - return rc; - } - } else { - rc = set_wep_key(local, idx, key.key, key.len, perm, 1); - if (rc < 0) { - airo_print_err(local->dev->name, - "failed to set WEP key at index %d: %d.", - idx, rc); - return rc; - } - } - } - - /* Read the flags */ - if (encoding->flags & IW_ENCODE_DISABLED) - set_auth_type(local, AUTH_OPEN); /* disable encryption */ - if (encoding->flags & IW_ENCODE_RESTRICTED) - set_auth_type(local, AUTH_SHAREDKEY); /* Only Both */ - if (encoding->flags & IW_ENCODE_OPEN) - set_auth_type(local, AUTH_ENCRYPT); - /* Commit the changes to flags if needed */ - if (local->config.authType != currentAuthType) - set_bit (FLAG_COMMIT, &local->flags); - - return -EINPROGRESS; -} - - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get extended Encryption parameters - */ -static int airo_get_encodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct airo_info *local = dev->ml_priv; - struct iw_point *encoding = &wrqu->encoding; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - int idx, max_key_len, wep_key_len; - u8 buf[16]; - - if (!local->wep_capable) - return -EOPNOTSUPP; - - readConfigRid(local, 1); - - max_key_len = encoding->length - sizeof(*ext); - if (max_key_len < 0) - return -EINVAL; - - idx = encoding->flags & IW_ENCODE_INDEX; - if (idx) { - if (!valid_index(local, idx - 1)) - return -EINVAL; - idx--; - } else { - idx = get_wep_tx_idx(local); - if (idx < 0) - idx = 0; - } - - encoding->flags = idx + 1; - memset(ext, 0, sizeof(*ext)); - - /* Check encryption mode */ - switch(local->config.authType) { - case AUTH_ENCRYPT: - encoding->flags = IW_ENCODE_ALG_WEP | IW_ENCODE_ENABLED; - break; - case AUTH_SHAREDKEY: - encoding->flags = IW_ENCODE_ALG_WEP | IW_ENCODE_ENABLED; - break; - default: - case AUTH_OPEN: - encoding->flags = IW_ENCODE_ALG_NONE | IW_ENCODE_DISABLED; - break; - } - /* We can't return the key, so set the proper flag and return zero */ - encoding->flags |= IW_ENCODE_NOKEY; - memset(extra, 0, 16); - - /* Copy the key to the user buffer */ - wep_key_len = get_wep_key(local, idx, &buf[0], sizeof(buf)); - if (wep_key_len < 0) { - ext->key_len = 0; - } else { - ext->key_len = wep_key_len; - memcpy(extra, buf, ext->key_len); - } - - return 0; -} - - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set extended authentication parameters - */ -static int airo_set_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct airo_info *local = dev->ml_priv; - struct iw_param *param = &wrqu->param; - __le16 currentAuthType = local->config.authType; - - switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - case IW_AUTH_CIPHER_PAIRWISE: - case IW_AUTH_CIPHER_GROUP: - case IW_AUTH_KEY_MGMT: - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - case IW_AUTH_PRIVACY_INVOKED: - /* - * airo does not use these parameters - */ - break; - - case IW_AUTH_DROP_UNENCRYPTED: - if (param->value) { - /* Only change auth type if unencrypted */ - if (currentAuthType == AUTH_OPEN) - set_auth_type(local, AUTH_ENCRYPT); - } else { - set_auth_type(local, AUTH_OPEN); - } - - /* Commit the changes to flags if needed */ - if (local->config.authType != currentAuthType) - set_bit (FLAG_COMMIT, &local->flags); - break; - - case IW_AUTH_80211_AUTH_ALG: { - if (param->value & IW_AUTH_ALG_SHARED_KEY) { - set_auth_type(local, AUTH_SHAREDKEY); - } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) { - /* We don't know here if WEP open system or - * unencrypted mode was requested - so use the - * last mode (of these two) used last time - */ - set_auth_type(local, local->last_auth); - } else - return -EINVAL; - - /* Commit the changes to flags if needed */ - if (local->config.authType != currentAuthType) - set_bit (FLAG_COMMIT, &local->flags); - break; - } - - case IW_AUTH_WPA_ENABLED: - /* Silently accept disable of WPA */ - if (param->value > 0) - return -EOPNOTSUPP; - break; - - default: - return -EOPNOTSUPP; - } - return -EINPROGRESS; -} - - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get extended authentication parameters - */ -static int airo_get_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct airo_info *local = dev->ml_priv; - struct iw_param *param = &wrqu->param; - __le16 currentAuthType = local->config.authType; - - switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_DROP_UNENCRYPTED: - switch (currentAuthType) { - case AUTH_SHAREDKEY: - case AUTH_ENCRYPT: - param->value = 1; - break; - default: - param->value = 0; - break; - } - break; - - case IW_AUTH_80211_AUTH_ALG: - switch (currentAuthType) { - case AUTH_SHAREDKEY: - param->value = IW_AUTH_ALG_SHARED_KEY; - break; - case AUTH_ENCRYPT: - default: - param->value = IW_AUTH_ALG_OPEN_SYSTEM; - break; - } - break; - - case IW_AUTH_WPA_ENABLED: - param->value = 0; - break; - - default: - return -EOPNOTSUPP; - } - return 0; -} - - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Tx-Power - */ -static int airo_set_txpow(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->txpower; - struct airo_info *local = dev->ml_priv; - CapabilityRid cap_rid; /* Card capability info */ - int i; - int rc = -EINVAL; - __le16 v = cpu_to_le16(vwrq->value); - - readCapabilityRid(local, &cap_rid, 1); - - if (vwrq->disabled) { - set_bit (FLAG_RADIO_OFF, &local->flags); - set_bit (FLAG_COMMIT, &local->flags); - return -EINPROGRESS; /* Call commit handler */ - } - if (vwrq->flags != IW_TXPOW_MWATT) { - return -EINVAL; - } - clear_bit (FLAG_RADIO_OFF, &local->flags); - for (i = 0; i < 8 && cap_rid.txPowerLevels[i]; i++) - if (v == cap_rid.txPowerLevels[i]) { - readConfigRid(local, 1); - local->config.txPower = v; - set_bit (FLAG_COMMIT, &local->flags); - rc = -EINPROGRESS; /* Call commit handler */ - break; - } - return rc; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Tx-Power - */ -static int airo_get_txpow(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->txpower; - struct airo_info *local = dev->ml_priv; - - readConfigRid(local, 1); - vwrq->value = le16_to_cpu(local->config.txPower); - vwrq->fixed = 1; /* No power control */ - vwrq->disabled = test_bit(FLAG_RADIO_OFF, &local->flags); - vwrq->flags = IW_TXPOW_MWATT; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Retry limits - */ -static int airo_set_retry(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->retry; - struct airo_info *local = dev->ml_priv; - int rc = -EINVAL; - - if (vwrq->disabled) { - return -EINVAL; - } - readConfigRid(local, 1); - if (vwrq->flags & IW_RETRY_LIMIT) { - __le16 v = cpu_to_le16(vwrq->value); - if (vwrq->flags & IW_RETRY_LONG) - local->config.longRetryLimit = v; - else if (vwrq->flags & IW_RETRY_SHORT) - local->config.shortRetryLimit = v; - else { - /* No modifier : set both */ - local->config.longRetryLimit = v; - local->config.shortRetryLimit = v; - } - set_bit (FLAG_COMMIT, &local->flags); - rc = -EINPROGRESS; /* Call commit handler */ - } - if (vwrq->flags & IW_RETRY_LIFETIME) { - local->config.txLifetime = cpu_to_le16(vwrq->value / 1024); - set_bit (FLAG_COMMIT, &local->flags); - rc = -EINPROGRESS; /* Call commit handler */ - } - return rc; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Retry limits - */ -static int airo_get_retry(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->retry; - struct airo_info *local = dev->ml_priv; - - vwrq->disabled = 0; /* Can't be disabled */ - - readConfigRid(local, 1); - /* Note : by default, display the min retry number */ - if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { - vwrq->flags = IW_RETRY_LIFETIME; - vwrq->value = le16_to_cpu(local->config.txLifetime) * 1024; - } else if ((vwrq->flags & IW_RETRY_LONG)) { - vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; - vwrq->value = le16_to_cpu(local->config.longRetryLimit); - } else { - vwrq->flags = IW_RETRY_LIMIT; - vwrq->value = le16_to_cpu(local->config.shortRetryLimit); - if (local->config.shortRetryLimit != local->config.longRetryLimit) - vwrq->flags |= IW_RETRY_SHORT; - } - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get range info - */ -static int airo_get_range(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->data; - struct airo_info *local = dev->ml_priv; - struct iw_range *range = (struct iw_range *) extra; - CapabilityRid cap_rid; /* Card capability info */ - int i; - int k; - - readCapabilityRid(local, &cap_rid, 1); - - dwrq->length = sizeof(struct iw_range); - memset(range, 0, sizeof(*range)); - range->min_nwid = 0x0000; - range->max_nwid = 0x0000; - range->num_channels = 14; - /* Should be based on cap_rid.country to give only - * what the current card support */ - k = 0; - for (i = 0; i < 14; i++) { - range->freq[k].i = i + 1; /* List index */ - range->freq[k].m = 100000 * - ieee80211_channel_to_frequency(i + 1, NL80211_BAND_2GHZ); - range->freq[k++].e = 1; /* Values in MHz -> * 10^5 * 10 */ - } - range->num_frequency = k; - - range->sensitivity = 65535; - - /* Hum... Should put the right values there */ - if (local->rssi) - range->max_qual.qual = 100; /* % */ - else - range->max_qual.qual = airo_get_max_quality(&cap_rid); - range->max_qual.level = 0x100 - 120; /* -120 dBm */ - range->max_qual.noise = 0x100 - 120; /* -120 dBm */ - - /* Experimental measurements - boundary 11/5.5 Mb/s */ - /* Note : with or without the (local->rssi), results - * are somewhat different. - Jean II */ - if (local->rssi) { - range->avg_qual.qual = 50; /* % */ - range->avg_qual.level = 0x100 - 70; /* -70 dBm */ - } else { - range->avg_qual.qual = airo_get_avg_quality(&cap_rid); - range->avg_qual.level = 0x100 - 80; /* -80 dBm */ - } - range->avg_qual.noise = 0x100 - 85; /* -85 dBm */ - - for (i = 0 ; i < 8 ; i++) { - range->bitrate[i] = cap_rid.supportedRates[i] * 500000; - if (range->bitrate[i] == 0) - break; - } - range->num_bitrates = i; - - /* Set an indication of the max TCP throughput - * in bit/s that we can expect using this interface. - * May be use for QoS stuff... Jean II */ - if (i > 2) - range->throughput = 5000 * 1000; - else - range->throughput = 1500 * 1000; - - range->min_rts = 0; - range->max_rts = AIRO_DEF_MTU; - range->min_frag = 256; - range->max_frag = AIRO_DEF_MTU; - - if (cap_rid.softCap & cpu_to_le16(2)) { - // WEP: RC4 40 bits - range->encoding_size[0] = 5; - // RC4 ~128 bits - if (cap_rid.softCap & cpu_to_le16(0x100)) { - range->encoding_size[1] = 13; - range->num_encoding_sizes = 2; - } else - range->num_encoding_sizes = 1; - range->max_encoding_tokens = - cap_rid.softCap & cpu_to_le16(0x80) ? 4 : 1; - } else { - range->num_encoding_sizes = 0; - range->max_encoding_tokens = 0; - } - range->min_pmp = 0; - range->max_pmp = 5000000; /* 5 secs */ - range->min_pmt = 0; - range->max_pmt = 65535 * 1024; /* ??? */ - range->pmp_flags = IW_POWER_PERIOD; - range->pmt_flags = IW_POWER_TIMEOUT; - range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R; - - /* Transmit Power - values are in mW */ - for (i = 0 ; i < 8 ; i++) { - range->txpower[i] = le16_to_cpu(cap_rid.txPowerLevels[i]); - if (range->txpower[i] == 0) - break; - } - range->num_txpower = i; - range->txpower_capa = IW_TXPOW_MWATT; - range->we_version_source = 19; - range->we_version_compiled = WIRELESS_EXT; - range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME; - range->retry_flags = IW_RETRY_LIMIT; - range->r_time_flags = IW_RETRY_LIFETIME; - range->min_retry = 1; - range->max_retry = 65535; - range->min_r_time = 1024; - range->max_r_time = 65535 * 1024; - - /* Event capability (kernel + driver) */ - range->event_capa[0] = (IW_EVENT_CAPA_K_0 | - IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) | - IW_EVENT_CAPA_MASK(SIOCGIWAP) | - IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); - range->event_capa[1] = IW_EVENT_CAPA_K_1; - range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVTXDROP); - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Power Management - */ -static int airo_set_power(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *vwrq = &wrqu->power; - struct airo_info *local = dev->ml_priv; - - readConfigRid(local, 1); - if (vwrq->disabled) { - if (sniffing_mode(local)) - return -EINVAL; - local->config.powerSaveMode = POWERSAVE_CAM; - local->config.rmode &= ~RXMODE_MASK; - local->config.rmode |= RXMODE_BC_MC_ADDR; - set_bit (FLAG_COMMIT, &local->flags); - return -EINPROGRESS; /* Call commit handler */ - } - if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { - local->config.fastListenDelay = cpu_to_le16((vwrq->value + 500) / 1024); - local->config.powerSaveMode = POWERSAVE_PSPCAM; - set_bit (FLAG_COMMIT, &local->flags); - } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) { - local->config.fastListenInterval = - local->config.listenInterval = - cpu_to_le16((vwrq->value + 500) / 1024); - local->config.powerSaveMode = POWERSAVE_PSPCAM; - set_bit (FLAG_COMMIT, &local->flags); - } - switch (vwrq->flags & IW_POWER_MODE) { - case IW_POWER_UNICAST_R: - if (sniffing_mode(local)) - return -EINVAL; - local->config.rmode &= ~RXMODE_MASK; - local->config.rmode |= RXMODE_ADDR; - set_bit (FLAG_COMMIT, &local->flags); - break; - case IW_POWER_ALL_R: - if (sniffing_mode(local)) - return -EINVAL; - local->config.rmode &= ~RXMODE_MASK; - local->config.rmode |= RXMODE_BC_MC_ADDR; - set_bit (FLAG_COMMIT, &local->flags); - break; - case IW_POWER_ON: - /* This is broken, fixme ;-) */ - break; - default: - return -EINVAL; - } - // Note : we may want to factor local->need_commit here - // Note2 : may also want to factor RXMODE_RFMON test - return -EINPROGRESS; /* Call commit handler */ -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Power Management - */ -static int airo_get_power(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->power; - struct airo_info *local = dev->ml_priv; - __le16 mode; - - readConfigRid(local, 1); - mode = local->config.powerSaveMode; - if ((vwrq->disabled = (mode == POWERSAVE_CAM))) - return 0; - if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { - vwrq->value = le16_to_cpu(local->config.fastListenDelay) * 1024; - vwrq->flags = IW_POWER_TIMEOUT; - } else { - vwrq->value = le16_to_cpu(local->config.fastListenInterval) * 1024; - vwrq->flags = IW_POWER_PERIOD; - } - if ((local->config.rmode & RXMODE_MASK) == RXMODE_ADDR) - vwrq->flags |= IW_POWER_UNICAST_R; - else - vwrq->flags |= IW_POWER_ALL_R; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Sensitivity - */ -static int airo_set_sens(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->sens; - struct airo_info *local = dev->ml_priv; - - readConfigRid(local, 1); - local->config.rssiThreshold = - cpu_to_le16(vwrq->disabled ? RSSI_DEFAULT : vwrq->value); - set_bit (FLAG_COMMIT, &local->flags); - - return -EINPROGRESS; /* Call commit handler */ -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Sensitivity - */ -static int airo_get_sens(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->sens; - struct airo_info *local = dev->ml_priv; - - readConfigRid(local, 1); - vwrq->value = le16_to_cpu(local->config.rssiThreshold); - vwrq->disabled = (vwrq->value == 0); - vwrq->fixed = 1; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get AP List - * Note : this is deprecated in favor of IWSCAN - */ -static int airo_get_aplist(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->data; - struct airo_info *local = dev->ml_priv; - struct sockaddr *address = (struct sockaddr *) extra; - struct iw_quality *qual; - BSSListRid BSSList; - int i; - int loseSync = capable(CAP_NET_ADMIN) ? 1: -1; - - qual = kmalloc_array(IW_MAX_AP, sizeof(*qual), GFP_KERNEL); - if (!qual) - return -ENOMEM; - - for (i = 0; i < IW_MAX_AP; i++) { - u16 dBm; - if (readBSSListRid(local, loseSync, &BSSList)) - break; - loseSync = 0; - memcpy(address[i].sa_data, BSSList.bssid, ETH_ALEN); - address[i].sa_family = ARPHRD_ETHER; - dBm = le16_to_cpu(BSSList.dBm); - if (local->rssi) { - qual[i].level = 0x100 - dBm; - qual[i].qual = airo_dbm_to_pct(local->rssi, dBm); - qual[i].updated = IW_QUAL_QUAL_UPDATED - | IW_QUAL_LEVEL_UPDATED - | IW_QUAL_DBM; - } else { - qual[i].level = (dBm + 321) / 2; - qual[i].qual = 0; - qual[i].updated = IW_QUAL_QUAL_INVALID - | IW_QUAL_LEVEL_UPDATED - | IW_QUAL_DBM; - } - qual[i].noise = local->wstats.qual.noise; - if (BSSList.index == cpu_to_le16(0xffff)) - break; - } - if (!i) { - StatusRid status_rid; /* Card status info */ - readStatusRid(local, &status_rid, 1); - for (i = 0; - i < min(IW_MAX_AP, 4) && - (status_rid.bssid[i][0] - & status_rid.bssid[i][1] - & status_rid.bssid[i][2] - & status_rid.bssid[i][3] - & status_rid.bssid[i][4] - & status_rid.bssid[i][5])!=0xff && - (status_rid.bssid[i][0] - | status_rid.bssid[i][1] - | status_rid.bssid[i][2] - | status_rid.bssid[i][3] - | status_rid.bssid[i][4] - | status_rid.bssid[i][5]); - i++) { - memcpy(address[i].sa_data, - status_rid.bssid[i], ETH_ALEN); - address[i].sa_family = ARPHRD_ETHER; - } - } else { - dwrq->flags = 1; /* Should be define'd */ - memcpy(extra + sizeof(struct sockaddr) * i, qual, - sizeof(struct iw_quality) * i); - } - dwrq->length = i; - - kfree(qual); - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : Initiate Scan - */ -static int airo_set_scan(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct airo_info *ai = dev->ml_priv; - Cmd cmd; - Resp rsp; - int wake = 0; - APListRid APList_rid_empty; - - /* Note : you may have realised that, as this is a SET operation, - * this is privileged and therefore a normal user can't - * perform scanning. - * This is not an error, while the device perform scanning, - * traffic doesn't flow, so it's a perfect DoS... - * Jean II */ - if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN; - - if (down_interruptible(&ai->sem)) - return -ERESTARTSYS; - - /* If there's already a scan in progress, don't - * trigger another one. */ - if (ai->scan_timeout > 0) - goto out; - - /* Clear APList as it affects scan results */ - memset(&APList_rid_empty, 0, sizeof(APList_rid_empty)); - APList_rid_empty.len = cpu_to_le16(sizeof(APList_rid_empty)); - disable_MAC(ai, 2); - writeAPListRid(ai, &APList_rid_empty, 0); - enable_MAC(ai, 0); - - /* Initiate a scan command */ - ai->scan_timeout = RUN_AT(3*HZ); - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd = CMD_LISTBSS; - issuecommand(ai, &cmd, &rsp, true); - wake = 1; - -out: - up(&ai->sem); - if (wake) - wake_up_interruptible(&ai->thr_wait); - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Translate scan data returned from the card to a card independent - * format that the Wireless Tools will understand - Jean II - */ -static inline char *airo_translate_scan(struct net_device *dev, - struct iw_request_info *info, - char *current_ev, - char *end_buf, - BSSListRid *bss) -{ - struct airo_info *ai = dev->ml_priv; - struct iw_event iwe; /* Temporary buffer */ - __le16 capabilities; - char * current_val; /* For rates */ - int i; - char * buf; - u16 dBm; - - /* First entry *MUST* be the AP MAC address */ - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN); - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_ADDR_LEN); - - /* Other entries will be displayed in the order we give them */ - - /* Add the ESSID */ - iwe.u.data.length = bss->ssidLen; - if (iwe.u.data.length > 32) - iwe.u.data.length = 32; - iwe.cmd = SIOCGIWESSID; - iwe.u.data.flags = 1; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, bss->ssid); - - /* Add mode */ - iwe.cmd = SIOCGIWMODE; - capabilities = bss->cap; - if (capabilities & (CAP_ESS | CAP_IBSS)) { - if (capabilities & CAP_ESS) - iwe.u.mode = IW_MODE_MASTER; - else - iwe.u.mode = IW_MODE_ADHOC; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_UINT_LEN); - } - - /* Add frequency */ - iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = le16_to_cpu(bss->dsChannel); - iwe.u.freq.m = 100000 * - ieee80211_channel_to_frequency(iwe.u.freq.m, NL80211_BAND_2GHZ); - iwe.u.freq.e = 1; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_FREQ_LEN); - - dBm = le16_to_cpu(bss->dBm); - - /* Add quality statistics */ - iwe.cmd = IWEVQUAL; - if (ai->rssi) { - iwe.u.qual.level = 0x100 - dBm; - iwe.u.qual.qual = airo_dbm_to_pct(ai->rssi, dBm); - iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED - | IW_QUAL_LEVEL_UPDATED - | IW_QUAL_DBM; - } else { - iwe.u.qual.level = (dBm + 321) / 2; - iwe.u.qual.qual = 0; - iwe.u.qual.updated = IW_QUAL_QUAL_INVALID - | IW_QUAL_LEVEL_UPDATED - | IW_QUAL_DBM; - } - iwe.u.qual.noise = ai->wstats.qual.noise; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_QUAL_LEN); - - /* Add encryption capability */ - iwe.cmd = SIOCGIWENCODE; - if (capabilities & CAP_PRIVACY) - iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - iwe.u.data.length = 0; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, bss->ssid); - - /* Rate : stuffing multiple values in a single event require a bit - * more of magic - Jean II */ - current_val = current_ev + iwe_stream_lcp_len(info); - - iwe.cmd = SIOCGIWRATE; - /* Those two flags are ignored... */ - iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; - /* Max 8 values */ - for (i = 0 ; i < 8 ; i++) { - /* NULL terminated */ - if (bss->rates[i] == 0) - break; - /* Bit rate given in 500 kb/s units (+ 0x80) */ - iwe.u.bitrate.value = ((bss->rates[i] & 0x7f) * 500000); - /* Add new value to event */ - current_val = iwe_stream_add_value(info, current_ev, - current_val, end_buf, - &iwe, IW_EV_PARAM_LEN); - } - /* Check if we added any event */ - if ((current_val - current_ev) > iwe_stream_lcp_len(info)) - current_ev = current_val; - - /* Beacon interval */ - buf = kmalloc(30, GFP_KERNEL); - if (buf) { - iwe.cmd = IWEVCUSTOM; - sprintf(buf, "bcn_int=%d", bss->beaconInterval); - iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, buf); - kfree(buf); - } - - /* Put WPA/RSN Information Elements into the event stream */ - if (test_bit(FLAG_WPA_CAPABLE, &ai->flags)) { - unsigned int num_null_ies = 0; - u16 length = sizeof (bss->extra.iep); - u8 *ie = (void *)&bss->extra.iep; - - while ((length >= 2) && (num_null_ies < 2)) { - if (2 + ie[1] > length) { - /* Invalid element, don't continue parsing IE */ - break; - } - - switch (ie[0]) { - case WLAN_EID_SSID: - /* Two zero-length SSID elements - * mean we're done parsing elements */ - if (!ie[1]) - num_null_ies++; - break; - - case WLAN_EID_VENDOR_SPECIFIC: - if (ie[1] >= 4 && - ie[2] == 0x00 && - ie[3] == 0x50 && - ie[4] == 0xf2 && - ie[5] == 0x01) { - iwe.cmd = IWEVGENIE; - /* 64 is an arbitrary cut-off */ - iwe.u.data.length = min(ie[1] + 2, - 64); - current_ev = iwe_stream_add_point( - info, current_ev, - end_buf, &iwe, ie); - } - break; - - case WLAN_EID_RSN: - iwe.cmd = IWEVGENIE; - /* 64 is an arbitrary cut-off */ - iwe.u.data.length = min(ie[1] + 2, 64); - current_ev = iwe_stream_add_point( - info, current_ev, end_buf, - &iwe, ie); - break; - - default: - break; - } - - length -= 2 + ie[1]; - ie += 2 + ie[1]; - } - } - return current_ev; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : Read Scan Results - */ -static int airo_get_scan(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->data; - struct airo_info *ai = dev->ml_priv; - BSSListElement *net; - int err = 0; - char *current_ev = extra; - - /* If a scan is in-progress, return -EAGAIN */ - if (ai->scan_timeout > 0) - return -EAGAIN; - - if (down_interruptible(&ai->sem)) - return -EAGAIN; - - list_for_each_entry (net, &ai->network_list, list) { - /* Translate to WE format this entry */ - current_ev = airo_translate_scan(dev, info, current_ev, - extra + dwrq->length, - &net->bss); - - /* Check if there is space for one more entry */ - if ((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) { - /* Ask user space to try again with a bigger buffer */ - err = -E2BIG; - goto out; - } - } - - /* Length of data */ - dwrq->length = (current_ev - extra); - dwrq->flags = 0; /* todo */ - -out: - up(&ai->sem); - return err; -} - -/*------------------------------------------------------------------*/ -/* - * Commit handler : called after a bunch of SET operations - */ -static int airo_config_commit(struct net_device *dev, - struct iw_request_info *info, /* NULL */ - union iwreq_data *wrqu, /* NULL */ - char *extra) /* NULL */ -{ - struct airo_info *local = dev->ml_priv; - - if (!test_bit (FLAG_COMMIT, &local->flags)) - return 0; - - /* Some of the "SET" function may have modified some of the - * parameters. It's now time to commit them in the card */ - disable_MAC(local, 1); - if (test_bit (FLAG_RESET, &local->flags)) { - SsidRid SSID_rid; - - readSsidRid(local, &SSID_rid); - if (test_bit(FLAG_MPI,&local->flags)) - setup_card(local, dev, 1); - else - reset_airo_card(dev); - disable_MAC(local, 1); - writeSsidRid(local, &SSID_rid, 1); - writeAPListRid(local, &local->APList, 1); - } - if (down_interruptible(&local->sem)) - return -ERESTARTSYS; - writeConfigRid(local, 0); - enable_MAC(local, 0); - if (test_bit (FLAG_RESET, &local->flags)) - airo_set_promisc(local, true); - else - up(&local->sem); - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Structures to export the Wireless Handlers - */ - -static const struct iw_priv_args airo_private_args[] = { -/*{ cmd, set_args, get_args, name } */ - { AIROIOCTL, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (aironet_ioctl), - IW_PRIV_TYPE_BYTE | 2047, "airoioctl" }, - { AIROIDIFC, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (aironet_ioctl), - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "airoidifc" }, -}; - -static const iw_handler airo_handler[] = -{ - IW_HANDLER(SIOCSIWCOMMIT, airo_config_commit), - IW_HANDLER(SIOCGIWNAME, airo_get_name), - IW_HANDLER(SIOCSIWFREQ, airo_set_freq), - IW_HANDLER(SIOCGIWFREQ, airo_get_freq), - IW_HANDLER(SIOCSIWMODE, airo_set_mode), - IW_HANDLER(SIOCGIWMODE, airo_get_mode), - IW_HANDLER(SIOCSIWSENS, airo_set_sens), - IW_HANDLER(SIOCGIWSENS, airo_get_sens), - IW_HANDLER(SIOCGIWRANGE, airo_get_range), - IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy), - IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy), - IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy), - IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy), - IW_HANDLER(SIOCSIWAP, airo_set_wap), - IW_HANDLER(SIOCGIWAP, airo_get_wap), - IW_HANDLER(SIOCGIWAPLIST, airo_get_aplist), - IW_HANDLER(SIOCSIWSCAN, airo_set_scan), - IW_HANDLER(SIOCGIWSCAN, airo_get_scan), - IW_HANDLER(SIOCSIWESSID, airo_set_essid), - IW_HANDLER(SIOCGIWESSID, airo_get_essid), - IW_HANDLER(SIOCSIWNICKN, airo_set_nick), - IW_HANDLER(SIOCGIWNICKN, airo_get_nick), - IW_HANDLER(SIOCSIWRATE, airo_set_rate), - IW_HANDLER(SIOCGIWRATE, airo_get_rate), - IW_HANDLER(SIOCSIWRTS, airo_set_rts), - IW_HANDLER(SIOCGIWRTS, airo_get_rts), - IW_HANDLER(SIOCSIWFRAG, airo_set_frag), - IW_HANDLER(SIOCGIWFRAG, airo_get_frag), - IW_HANDLER(SIOCSIWTXPOW, airo_set_txpow), - IW_HANDLER(SIOCGIWTXPOW, airo_get_txpow), - IW_HANDLER(SIOCSIWRETRY, airo_set_retry), - IW_HANDLER(SIOCGIWRETRY, airo_get_retry), - IW_HANDLER(SIOCSIWENCODE, airo_set_encode), - IW_HANDLER(SIOCGIWENCODE, airo_get_encode), - IW_HANDLER(SIOCSIWPOWER, airo_set_power), - IW_HANDLER(SIOCGIWPOWER, airo_get_power), - IW_HANDLER(SIOCSIWAUTH, airo_set_auth), - IW_HANDLER(SIOCGIWAUTH, airo_get_auth), - IW_HANDLER(SIOCSIWENCODEEXT, airo_set_encodeext), - IW_HANDLER(SIOCGIWENCODEEXT, airo_get_encodeext), -}; - -/* Note : don't describe AIROIDIFC and AIROOLDIDIFC in here. - * We want to force the use of the ioctl code, because those can't be - * won't work the iw_handler code (because they simultaneously read - * and write data and iw_handler can't do that). - * Note that it's perfectly legal to read/write on a single ioctl command, - * you just can't use iwpriv and need to force it via the ioctl handler. - * Jean II */ -static const iw_handler airo_private_handler[] = -{ - NULL, /* SIOCIWFIRSTPRIV */ -}; - -static const struct iw_handler_def airo_handler_def = -{ - .num_standard = ARRAY_SIZE(airo_handler), - .num_private = ARRAY_SIZE(airo_private_handler), - .num_private_args = ARRAY_SIZE(airo_private_args), - .standard = airo_handler, - .private = airo_private_handler, - .private_args = airo_private_args, - .get_wireless_stats = airo_get_wireless_stats, -}; - -/* - * This defines the configuration part of the Wireless Extensions - * Note : irq and spinlock protection will occur in the subroutines - * - * TODO : - * o Check input value more carefully and fill correct values in range - * o Test and shakeout the bugs (if any) - * - * Jean II - * - * Javier Achirica did a great job of merging code from the unnamed CISCO - * developer that added support for flashing the card. - */ -static int airo_siocdevprivate(struct net_device *dev, struct ifreq *rq, - void __user *data, int cmd) -{ - int rc = 0; - struct airo_info *ai = dev->ml_priv; - - if (ai->power.event) - return 0; - - switch (cmd) { -#ifdef CISCO_EXT - case AIROIDIFC: -#ifdef AIROOLDIDIFC - case AIROOLDIDIFC: -#endif - { - int val = AIROMAGIC; - aironet_ioctl com; - if (copy_from_user(&com, data, sizeof(com))) - rc = -EFAULT; - else if (copy_to_user(com.data, (char *)&val, sizeof(val))) - rc = -EFAULT; - } - break; - - case AIROIOCTL: -#ifdef AIROOLDIOCTL - case AIROOLDIOCTL: -#endif - /* Get the command struct and hand it off for evaluation by - * the proper subfunction - */ - { - aironet_ioctl com; - if (copy_from_user(&com, data, sizeof(com))) { - rc = -EFAULT; - break; - } - - /* Separate R/W functions bracket legality here - */ - if (com.command == AIRORSWVERSION) { - if (copy_to_user(com.data, swversion, sizeof(swversion))) - rc = -EFAULT; - else - rc = 0; - } - else if (com.command <= AIRORRID) - rc = readrids(dev,&com); - else if (com.command >= AIROPCAP && com.command <= (AIROPLEAPUSR+2)) - rc = writerids(dev,&com); - else if (com.command >= AIROFLSHRST && com.command <= AIRORESTART) - rc = flashcard(dev,&com); - else - rc = -EINVAL; /* Bad command in ioctl */ - } - break; -#endif /* CISCO_EXT */ - - // All other calls are currently unsupported - default: - rc = -EOPNOTSUPP; - } - return rc; -} - -/* - * Get the Wireless stats out of the driver - * Note : irq and spinlock protection will occur in the subroutines - * - * TODO : - * o Check if work in Ad-Hoc mode (otherwise, use SPY, as in wvlan_cs) - * - * Jean - */ -static void airo_read_wireless_stats(struct airo_info *local) -{ - StatusRid status_rid; - StatsRid stats_rid; - CapabilityRid cap_rid; - __le32 *vals = stats_rid.vals; - - /* Get stats out of the card */ - if (local->power.event) - return; - - readCapabilityRid(local, &cap_rid, 0); - readStatusRid(local, &status_rid, 0); - readStatsRid(local, &stats_rid, RID_STATS, 0); - - /* The status */ - local->wstats.status = le16_to_cpu(status_rid.mode); - - /* Signal quality and co */ - if (local->rssi) { - local->wstats.qual.level = - airo_rssi_to_dbm(local->rssi, - le16_to_cpu(status_rid.sigQuality)); - /* normalizedSignalStrength appears to be a percentage */ - local->wstats.qual.qual = - le16_to_cpu(status_rid.normalizedSignalStrength); - } else { - local->wstats.qual.level = - (le16_to_cpu(status_rid.normalizedSignalStrength) + 321) / 2; - local->wstats.qual.qual = airo_get_quality(&status_rid, &cap_rid); - } - if (le16_to_cpu(status_rid.len) >= 124) { - local->wstats.qual.noise = 0x100 - status_rid.noisedBm; - local->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; - } else { - local->wstats.qual.noise = 0; - local->wstats.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_INVALID | IW_QUAL_DBM; - } - - /* Packets discarded in the wireless adapter due to wireless - * specific problems */ - local->wstats.discard.nwid = le32_to_cpu(vals[56]) + - le32_to_cpu(vals[57]) + - le32_to_cpu(vals[58]); /* SSID Mismatch */ - local->wstats.discard.code = le32_to_cpu(vals[6]);/* RxWepErr */ - local->wstats.discard.fragment = le32_to_cpu(vals[30]); - local->wstats.discard.retries = le32_to_cpu(vals[10]); - local->wstats.discard.misc = le32_to_cpu(vals[1]) + - le32_to_cpu(vals[32]); - local->wstats.miss.beacon = le32_to_cpu(vals[34]); -} - -static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev) -{ - struct airo_info *local = dev->ml_priv; - - if (!down_interruptible(&local->sem)) { - airo_read_wireless_stats(local); - up(&local->sem); - } - return &local->wstats; -} - -#ifdef CISCO_EXT -/* - * This just translates from driver IOCTL codes to the command codes to - * feed to the radio's host interface. Things can be added/deleted - * as needed. This represents the READ side of control I/O to - * the card - */ -static int readrids(struct net_device *dev, aironet_ioctl *comp) -{ - unsigned short ridcode; - unsigned char *iobuf; - int len; - struct airo_info *ai = dev->ml_priv; - - if (test_bit(FLAG_FLASHING, &ai->flags)) - return -EIO; - - switch(comp->command) - { - case AIROGCAP: ridcode = RID_CAPABILITIES; break; - case AIROGCFG: ridcode = RID_CONFIG; - if (test_bit(FLAG_COMMIT, &ai->flags)) { - disable_MAC (ai, 1); - writeConfigRid (ai, 1); - enable_MAC(ai, 1); - } - break; - case AIROGSLIST: ridcode = RID_SSID; break; - case AIROGVLIST: ridcode = RID_APLIST; break; - case AIROGDRVNAM: ridcode = RID_DRVNAME; break; - case AIROGEHTENC: ridcode = RID_ETHERENCAP; break; - case AIROGWEPKTMP: ridcode = RID_WEP_TEMP; break; - case AIROGWEPKNV: ridcode = RID_WEP_PERM; break; - case AIROGSTAT: ridcode = RID_STATUS; break; - case AIROGSTATSD32: ridcode = RID_STATSDELTA; break; - case AIROGSTATSC32: ridcode = RID_STATS; break; - case AIROGMICSTATS: - if (copy_to_user(comp->data, &ai->micstats, - min((int)comp->len, (int)sizeof(ai->micstats)))) - return -EFAULT; - return 0; - case AIRORRID: ridcode = comp->ridnum; break; - default: - return -EINVAL; - } - - if (ridcode == RID_WEP_TEMP || ridcode == RID_WEP_PERM) { - /* Only super-user can read WEP keys */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - } - - if ((iobuf = kzalloc(RIDSIZE, GFP_KERNEL)) == NULL) - return -ENOMEM; - - PC4500_readrid(ai, ridcode, iobuf, RIDSIZE, 1); - /* get the count of bytes in the rid docs say 1st 2 bytes is it. - * then return it to the user - * 9/22/2000 Honor user given length - */ - len = comp->len; - - if (copy_to_user(comp->data, iobuf, min(len, (int)RIDSIZE))) { - kfree (iobuf); - return -EFAULT; - } - kfree (iobuf); - return 0; -} - -/* - * Danger Will Robinson write the rids here - */ - -static int writerids(struct net_device *dev, aironet_ioctl *comp) -{ - struct airo_info *ai = dev->ml_priv; - int ridcode; - int enabled; - int (*writer)(struct airo_info *, u16 rid, const void *, int, int); - unsigned char *iobuf; - - /* Only super-user can write RIDs */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - if (test_bit(FLAG_FLASHING, &ai->flags)) - return -EIO; - - ridcode = 0; - writer = do_writerid; - - switch(comp->command) - { - case AIROPSIDS: ridcode = RID_SSID; break; - case AIROPCAP: ridcode = RID_CAPABILITIES; break; - case AIROPAPLIST: ridcode = RID_APLIST; break; - case AIROPCFG: ai->config.len = 0; - clear_bit(FLAG_COMMIT, &ai->flags); - ridcode = RID_CONFIG; break; - case AIROPWEPKEYNV: ridcode = RID_WEP_PERM; break; - case AIROPLEAPUSR: ridcode = RID_LEAPUSERNAME; break; - case AIROPLEAPPWD: ridcode = RID_LEAPPASSWORD; break; - case AIROPWEPKEY: ridcode = RID_WEP_TEMP; writer = PC4500_writerid; - break; - case AIROPLEAPUSR+1: ridcode = 0xFF2A; break; - case AIROPLEAPUSR+2: ridcode = 0xFF2B; break; - - /* this is not really a rid but a command given to the card - * same with MAC off - */ - case AIROPMACON: - if (enable_MAC(ai, 1) != 0) - return -EIO; - return 0; - - /* - * Evidently this code in the airo driver does not get a symbol - * as disable_MAC. it's probably so short the compiler does not gen one. - */ - case AIROPMACOFF: - disable_MAC(ai, 1); - return 0; - - /* This command merely clears the counts does not actually store any data - * only reads rid. But as it changes the cards state, I put it in the - * writerid routines. - */ - case AIROPSTCLR: - if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL) - return -ENOMEM; - - PC4500_readrid(ai, RID_STATSDELTACLEAR, iobuf, RIDSIZE, 1); - - enabled = ai->micstats.enabled; - memset(&ai->micstats, 0, sizeof(ai->micstats)); - ai->micstats.enabled = enabled; - - if (copy_to_user(comp->data, iobuf, - min((int)comp->len, (int)RIDSIZE))) { - kfree (iobuf); - return -EFAULT; - } - kfree (iobuf); - return 0; - - default: - return -EOPNOTSUPP; /* Blarg! */ - } - if (comp->len > RIDSIZE) - return -EINVAL; - - if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL) - return -ENOMEM; - - if (copy_from_user(iobuf, comp->data, comp->len)) { - kfree (iobuf); - return -EFAULT; - } - - if (comp->command == AIROPCFG) { - ConfigRid *cfg = (ConfigRid *)iobuf; - - if (test_bit(FLAG_MIC_CAPABLE, &ai->flags)) - cfg->opmode |= MODE_MIC; - - if ((cfg->opmode & MODE_CFG_MASK) == MODE_STA_IBSS) - set_bit (FLAG_ADHOC, &ai->flags); - else - clear_bit (FLAG_ADHOC, &ai->flags); - } - - if ((*writer)(ai, ridcode, iobuf, comp->len, 1)) { - kfree (iobuf); - return -EIO; - } - kfree (iobuf); - return 0; -} - -/***************************************************************************** - * Ancillary flash / mod functions much black magic lurkes here * - ***************************************************************************** - */ - -/* - * Flash command switch table - */ - -static int flashcard(struct net_device *dev, aironet_ioctl *comp) -{ - int z; - - /* Only super-user can modify flash */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - switch(comp->command) - { - case AIROFLSHRST: - return cmdreset((struct airo_info *)dev->ml_priv); - - case AIROFLSHSTFL: - if (!AIRO_FLASH(dev) && - (AIRO_FLASH(dev) = kmalloc(FLASHSIZE, GFP_KERNEL)) == NULL) - return -ENOMEM; - return setflashmode((struct airo_info *)dev->ml_priv); - - case AIROFLSHGCHR: /* Get char from aux */ - if (comp->len != sizeof(int)) - return -EINVAL; - if (copy_from_user(&z, comp->data, comp->len)) - return -EFAULT; - return flashgchar((struct airo_info *)dev->ml_priv, z, 8000); - - case AIROFLSHPCHR: /* Send char to card. */ - if (comp->len != sizeof(int)) - return -EINVAL; - if (copy_from_user(&z, comp->data, comp->len)) - return -EFAULT; - return flashpchar((struct airo_info *)dev->ml_priv, z, 8000); - - case AIROFLPUTBUF: /* Send 32k to card */ - if (!AIRO_FLASH(dev)) - return -ENOMEM; - if (comp->len > FLASHSIZE) - return -EINVAL; - if (copy_from_user(AIRO_FLASH(dev), comp->data, comp->len)) - return -EFAULT; - - flashputbuf((struct airo_info *)dev->ml_priv); - return 0; - - case AIRORESTART: - if (flashrestart((struct airo_info *)dev->ml_priv, dev)) - return -EIO; - return 0; - } - return -EINVAL; -} - -#define FLASH_COMMAND 0x7e7e - -/* - * STEP 1) - * Disable MAC and do soft reset on - * card. - */ - -static int cmdreset(struct airo_info *ai) -{ - disable_MAC(ai, 1); - - if (!waitbusy (ai)) { - airo_print_info(ai->dev->name, "Waitbusy hang before RESET"); - return -EBUSY; - } - - OUT4500(ai, COMMAND, CMD_SOFTRESET); - - ssleep(1); /* WAS 600 12/7/00 */ - - if (!waitbusy (ai)) { - airo_print_info(ai->dev->name, "Waitbusy hang AFTER RESET"); - return -EBUSY; - } - return 0; -} - -/* STEP 2) - * Put the card in legendary flash - * mode - */ - -static int setflashmode (struct airo_info *ai) -{ - set_bit (FLAG_FLASHING, &ai->flags); - - OUT4500(ai, SWS0, FLASH_COMMAND); - OUT4500(ai, SWS1, FLASH_COMMAND); - if (probe) { - OUT4500(ai, SWS0, FLASH_COMMAND); - OUT4500(ai, COMMAND, 0x10); - } else { - OUT4500(ai, SWS2, FLASH_COMMAND); - OUT4500(ai, SWS3, FLASH_COMMAND); - OUT4500(ai, COMMAND, 0); - } - msleep(500); /* 500ms delay */ - - if (!waitbusy(ai)) { - clear_bit (FLAG_FLASHING, &ai->flags); - airo_print_info(ai->dev->name, "Waitbusy hang after setflash mode"); - return -EIO; - } - return 0; -} - -/* Put character to SWS0 wait for dwelltime - * x 50us for echo . - */ - -static int flashpchar(struct airo_info *ai, int byte, int dwelltime) -{ - int echo; - int waittime; - - byte |= 0x8000; - - if (dwelltime == 0) - dwelltime = 200; - - waittime = dwelltime; - - /* Wait for busy bit d15 to go false indicating buffer empty */ - while ((IN4500 (ai, SWS0) & 0x8000) && waittime > 0) { - udelay (50); - waittime -= 50; - } - - /* timeout for busy clear wait */ - if (waittime <= 0) { - airo_print_info(ai->dev->name, "flash putchar busywait timeout!"); - return -EBUSY; - } - - /* Port is clear now write byte and wait for it to echo back */ - do { - OUT4500(ai, SWS0, byte); - udelay(50); - dwelltime -= 50; - echo = IN4500(ai, SWS1); - } while (dwelltime >= 0 && echo != byte); - - OUT4500(ai, SWS1, 0); - - return (echo == byte) ? 0 : -EIO; -} - -/* - * Get a character from the card matching matchbyte - * Step 3) - */ -static int flashgchar(struct airo_info *ai, int matchbyte, int dwelltime) -{ - int rchar; - unsigned char rbyte = 0; - - do { - rchar = IN4500(ai, SWS1); - - if (dwelltime && !(0x8000 & rchar)) { - dwelltime -= 10; - mdelay(10); - continue; - } - rbyte = 0xff & rchar; - - if ((rbyte == matchbyte) && (0x8000 & rchar)) { - OUT4500(ai, SWS1, 0); - return 0; - } - if (rbyte == 0x81 || rbyte == 0x82 || rbyte == 0x83 || rbyte == 0x1a || 0xffff == rchar) - break; - OUT4500(ai, SWS1, 0); - - } while (dwelltime > 0); - return -EIO; -} - -/* - * Transfer 32k of firmware data from user buffer to our buffer and - * send to the card - */ - -static int flashputbuf(struct airo_info *ai) -{ - int nwords; - - /* Write stuff */ - if (test_bit(FLAG_MPI,&ai->flags)) - memcpy_toio(ai->pciaux + 0x8000, ai->flash, FLASHSIZE); - else { - OUT4500(ai, AUXPAGE, 0x100); - OUT4500(ai, AUXOFF, 0); - - for (nwords = 0; nwords != FLASHSIZE / 2; nwords++) { - OUT4500(ai, AUXDATA, ai->flash[nwords] & 0xffff); - } - } - OUT4500(ai, SWS0, 0x8000); - - return 0; -} - -/* - * - */ -static int flashrestart(struct airo_info *ai, struct net_device *dev) -{ - int i, status; - - ssleep(1); /* Added 12/7/00 */ - clear_bit (FLAG_FLASHING, &ai->flags); - if (test_bit(FLAG_MPI, &ai->flags)) { - status = mpi_init_descriptors(ai); - if (status != SUCCESS) - return status; - } - status = setup_card(ai, dev, 1); - - if (!test_bit(FLAG_MPI,&ai->flags)) - for (i = 0; i < MAX_FIDS; i++) { - ai->fids[i] = transmit_allocate - (ai, AIRO_DEF_MTU, i >= MAX_FIDS / 2); - } - - ssleep(1); /* Added 12/7/00 */ - return status; -} -#endif /* CISCO_EXT */ - -/* - 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. - - In addition: - - 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. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -*/ - -module_init(airo_init_module); -module_exit(airo_cleanup_module); diff --git a/drivers/net/wireless/cisco/airo.h b/drivers/net/wireless/cisco/airo.h deleted file mode 100644 index 8a02977a2e2ba..0000000000000 --- a/drivers/net/wireless/cisco/airo.h +++ /dev/null @@ -1,10 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _AIRO_H_ -#define _AIRO_H_ - -struct net_device *init_airo_card(unsigned short irq, int port, int is_pcmcia, - struct device *dmdev); -int reset_airo_card(struct net_device *dev); -void stop_airo_card(struct net_device *dev, int freeres); - -#endif /* _AIRO_H_ */ diff --git a/drivers/net/wireless/cisco/airo_cs.c b/drivers/net/wireless/cisco/airo_cs.c deleted file mode 100644 index fcfe4c6d62f04..0000000000000 --- a/drivers/net/wireless/cisco/airo_cs.c +++ /dev/null @@ -1,218 +0,0 @@ -/*====================================================================== - - Aironet driver for 4500 and 4800 series cards - - This code is released under both the GPL version 2 and BSD licenses. - Either license may be used. The respective licenses are found at - the end of this file. - - This code was developed by Benjamin Reed - including portions of which come from the Aironet PC4500 - Developer's Reference Manual and used with permission. Copyright - (C) 1999 Benjamin Reed. All Rights Reserved. Permission to use - code in the Developer's manual was granted for this driver by - Aironet. - - In addition this module was derived from dummy_cs. - The initial developer of dummy_cs is David A. Hinds - . Portions created by David A. Hinds - are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - -======================================================================*/ - -#ifdef __IN_PCMCIA_PACKAGE__ -#include -#endif -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include "airo.h" - - -/*====================================================================*/ - -MODULE_AUTHOR("Benjamin Reed"); -MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet " - "cards. This is the module that links the PCMCIA card " - "with the airo module."); -MODULE_LICENSE("Dual BSD/GPL"); - -/*====================================================================*/ - -static int airo_config(struct pcmcia_device *link); -static void airo_release(struct pcmcia_device *link); - -static void airo_detach(struct pcmcia_device *p_dev); - -struct local_info { - struct net_device *eth_dev; -}; - -static int airo_probe(struct pcmcia_device *p_dev) -{ - struct local_info *local; - - dev_dbg(&p_dev->dev, "airo_attach()\n"); - - /* Allocate space for private device-specific data */ - local = kzalloc(sizeof(*local), GFP_KERNEL); - if (!local) - return -ENOMEM; - - p_dev->priv = local; - - return airo_config(p_dev); -} /* airo_attach */ - -static void airo_detach(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "airo_detach\n"); - - airo_release(link); - - if (((struct local_info *)link->priv)->eth_dev) { - stop_airo_card(((struct local_info *)link->priv)->eth_dev, - 0); - } - ((struct local_info *)link->priv)->eth_dev = NULL; - - kfree(link->priv); -} /* airo_detach */ - -static int airo_cs_config_check(struct pcmcia_device *p_dev, void *priv_data) -{ - if (p_dev->config_index == 0) - return -EINVAL; - - return pcmcia_request_io(p_dev); -} - - -static int airo_config(struct pcmcia_device *link) -{ - int ret; - - dev_dbg(&link->dev, "airo_config\n"); - - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP | - CONF_AUTO_AUDIO | CONF_AUTO_SET_IO; - - ret = pcmcia_loop_config(link, airo_cs_config_check, NULL); - if (ret) - goto failed; - - if (!link->irq) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - ((struct local_info *)link->priv)->eth_dev = - init_airo_card(link->irq, - link->resource[0]->start, 1, &link->dev); - if (!((struct local_info *)link->priv)->eth_dev) - goto failed; - - return 0; - - failed: - airo_release(link); - return -ENODEV; -} /* airo_config */ - -static void airo_release(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "airo_release\n"); - pcmcia_disable_device(link); -} - -static int airo_suspend(struct pcmcia_device *link) -{ - struct local_info *local = link->priv; - - netif_device_detach(local->eth_dev); - - return 0; -} - -static int airo_resume(struct pcmcia_device *link) -{ - struct local_info *local = link->priv; - - if (link->open) { - reset_airo_card(local->eth_dev); - netif_device_attach(local->eth_dev); - } - - return 0; -} - -static const struct pcmcia_device_id airo_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0x015f, 0x000a), - PCMCIA_DEVICE_MANF_CARD(0x015f, 0x0005), - PCMCIA_DEVICE_MANF_CARD(0x015f, 0x0007), - PCMCIA_DEVICE_MANF_CARD(0x0105, 0x0007), - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, airo_ids); - -static struct pcmcia_driver airo_driver = { - .owner = THIS_MODULE, - .name = "airo_cs", - .probe = airo_probe, - .remove = airo_detach, - .id_table = airo_ids, - .suspend = airo_suspend, - .resume = airo_resume, -}; -module_pcmcia_driver(airo_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. - - In addition: - - 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. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -*/ diff --git a/drivers/net/wireless/intel/iwlegacy/4965-mac.c b/drivers/net/wireless/intel/iwlegacy/4965-mac.c index 69276266ce6f4..70e420df16438 100644 --- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c @@ -4231,8 +4231,6 @@ il4965_rx_handle(struct il_priv *il) fill_rx = 1; while (i != r) { - int len; - rxb = rxq->queue[i]; /* If an RXB doesn't have a Rx queue slot associated with it, @@ -4246,10 +4244,6 @@ il4965_rx_handle(struct il_priv *il) PAGE_SIZE << il->hw_params.rx_page_order, DMA_FROM_DEVICE); pkt = rxb_addr(rxb); - - len = le32_to_cpu(pkt->len_n_flags) & IL_RX_FRAME_SIZE_MSK; - len += sizeof(u32); /* account for status word */ - reclaim = il_need_reclaim(il, pkt); /* Based on type of command response or notification, diff --git a/drivers/net/wireless/intersil/Kconfig b/drivers/net/wireless/intersil/Kconfig index bd6bf70ece03d..201b1534a9ca2 100644 --- a/drivers/net/wireless/intersil/Kconfig +++ b/drivers/net/wireless/intersil/Kconfig @@ -12,8 +12,6 @@ config WLAN_VENDOR_INTERSIL if WLAN_VENDOR_INTERSIL -source "drivers/net/wireless/intersil/hostap/Kconfig" -source "drivers/net/wireless/intersil/orinoco/Kconfig" source "drivers/net/wireless/intersil/p54/Kconfig" endif # WLAN_VENDOR_INTERSIL diff --git a/drivers/net/wireless/intersil/Makefile b/drivers/net/wireless/intersil/Makefile index 65281d1b3d852..27e9b2869da1a 100644 --- a/drivers/net/wireless/intersil/Makefile +++ b/drivers/net/wireless/intersil/Makefile @@ -1,4 +1,2 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_HOSTAP) += hostap/ -obj-$(CONFIG_HERMES) += orinoco/ obj-$(CONFIG_P54_COMMON) += p54/ diff --git a/drivers/net/wireless/intersil/hostap/Kconfig b/drivers/net/wireless/intersil/hostap/Kconfig deleted file mode 100644 index 2edff8efbcbb1..0000000000000 --- a/drivers/net/wireless/intersil/hostap/Kconfig +++ /dev/null @@ -1,95 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config HOSTAP - tristate "IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP)" - select WIRELESS_EXT - select WEXT_SPY - select WEXT_PRIV - select CRYPTO - select CRYPTO_MICHAEL_MIC - select CRC32 - select LIB80211 - select LIB80211_CRYPT_WEP - select LIB80211_CRYPT_TKIP - select LIB80211_CRYPT_CCMP - help - Shared driver code for IEEE 802.11b wireless cards based on - Intersil Prism2/2.5/3 chipset. This driver supports so called - Host AP mode that allows the card to act as an IEEE 802.11 - access point. - - See for more information about the - Host AP driver configuration and tools. This site includes - information and tools (hostapd and wpa_supplicant) for WPA/WPA2 - support. - - This option includes the base Host AP driver code that is shared by - different hardware models. You will also need to enable support for - PLX/PCI/CS version of the driver to actually use the driver. - - The driver can be compiled as a module and it will be called - hostap. - -config HOSTAP_FIRMWARE - bool "Support downloading firmware images with Host AP driver" - depends on HOSTAP - help - Configure Host AP driver to include support for firmware image - download. This option by itself only enables downloading to the - volatile memory, i.e. the card RAM. This option is required to - support cards that don't have firmware in flash, such as D-Link - DWL-520 rev E and D-Link DWL-650 rev P. - - Firmware image downloading needs a user space tool, prism2_srec. - It is available from http://hostap.epitest.fi/. - -config HOSTAP_FIRMWARE_NVRAM - bool "Support for non-volatile firmware download" - depends on HOSTAP_FIRMWARE - help - Allow Host AP driver to write firmware images to the non-volatile - card memory, i.e. flash memory that survives power cycling. - Enable this option if you want to be able to change card firmware - permanently. - - Firmware image downloading needs a user space tool, prism2_srec. - It is available from http://hostap.epitest.fi/. - -config HOSTAP_PLX - tristate "Host AP driver for Prism2/2.5/3 in PLX9052 PCI adaptors" - depends on PCI && HOSTAP && HAS_IOPORT - help - Host AP driver's version for Prism2/2.5/3 PC Cards in PLX9052 based - PCI adaptors. - - "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this - driver and its help text includes more information about the Host AP - driver. - - The driver can be compiled as a module and will be named - hostap_plx. - -config HOSTAP_PCI - tristate "Host AP driver for Prism2.5 PCI adaptors" - depends on PCI && HOSTAP - help - Host AP driver's version for Prism2.5 PCI adaptors. - - "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this - driver and its help text includes more information about the Host AP - driver. - - The driver can be compiled as a module and will be named - hostap_pci. - -config HOSTAP_CS - tristate "Host AP driver for Prism2/2.5/3 PC Cards" - depends on PCMCIA && HOSTAP - help - Host AP driver's version for Prism2/2.5/3 PC Cards. - - "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this - driver and its help text includes more information about the Host AP - driver. - - The driver can be compiled as a module and will be named - hostap_cs. diff --git a/drivers/net/wireless/intersil/hostap/Makefile b/drivers/net/wireless/intersil/hostap/Makefile deleted file mode 100644 index ae3bb73b2d99d..0000000000000 --- a/drivers/net/wireless/intersil/hostap/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -hostap-y := hostap_80211_rx.o hostap_80211_tx.o hostap_ap.o hostap_info.o \ - hostap_ioctl.o hostap_main.o hostap_proc.o -obj-$(CONFIG_HOSTAP) += hostap.o - -obj-$(CONFIG_HOSTAP_CS) += hostap_cs.o -obj-$(CONFIG_HOSTAP_PLX) += hostap_plx.o -obj-$(CONFIG_HOSTAP_PCI) += hostap_pci.o diff --git a/drivers/net/wireless/intersil/hostap/hostap.h b/drivers/net/wireless/intersil/hostap/hostap.h deleted file mode 100644 index 552ae33d78751..0000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap.h +++ /dev/null @@ -1,98 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef HOSTAP_H -#define HOSTAP_H - -#include -#include - -#include "hostap_wlan.h" -#include "hostap_ap.h" - -static const long __maybe_unused freq_list[] = { - 2412, 2417, 2422, 2427, 2432, 2437, 2442, - 2447, 2452, 2457, 2462, 2467, 2472, 2484 -}; -#define FREQ_COUNT ARRAY_SIZE(freq_list) - -/* hostap.c */ - -extern struct proc_dir_entry *hostap_proc; - -u16 hostap_tx_callback_register(local_info_t *local, - void (*func)(struct sk_buff *, int ok, void *), - void *data); -int hostap_tx_callback_unregister(local_info_t *local, u16 idx); -int hostap_set_word(struct net_device *dev, int rid, u16 val); -int hostap_set_string(struct net_device *dev, int rid, const char *val); -u16 hostap_get_porttype(local_info_t *local); -int hostap_set_encryption(local_info_t *local); -int hostap_set_antsel(local_info_t *local); -int hostap_set_roaming(local_info_t *local); -int hostap_set_auth_algs(local_info_t *local); -void hostap_dump_rx_header(const char *name, - const struct hfa384x_rx_frame *rx); -void hostap_dump_tx_header(const char *name, - const struct hfa384x_tx_frame *tx); -extern const struct header_ops hostap_80211_ops; -int hostap_80211_get_hdrlen(__le16 fc); -struct net_device_stats *hostap_get_stats(struct net_device *dev); -void hostap_setup_dev(struct net_device *dev, local_info_t *local, - int type); -void hostap_set_multicast_list_queue(struct work_struct *work); -int hostap_set_hostapd(local_info_t *local, int val, int rtnl_locked); -int hostap_set_hostapd_sta(local_info_t *local, int val, int rtnl_locked); -void hostap_cleanup(local_info_t *local); -void hostap_cleanup_handler(void *data); -struct net_device * hostap_add_interface(struct local_info *local, - int type, int rtnl_locked, - const char *prefix, const char *name); -void hostap_remove_interface(struct net_device *dev, int rtnl_locked, - int remove_from_list); -int prism2_update_comms_qual(struct net_device *dev); -int prism2_sta_send_mgmt(local_info_t *local, u8 *dst, u16 stype, - u8 *body, size_t bodylen); -int prism2_sta_deauth(local_info_t *local, u16 reason); -int prism2_wds_add(local_info_t *local, u8 *remote_addr, - int rtnl_locked); -int prism2_wds_del(local_info_t *local, u8 *remote_addr, - int rtnl_locked, int do_not_remove); - - -/* hostap_ap.c */ - -int ap_control_add_mac(struct mac_restrictions *mac_restrictions, u8 *mac); -int ap_control_del_mac(struct mac_restrictions *mac_restrictions, u8 *mac); -void ap_control_flush_macs(struct mac_restrictions *mac_restrictions); -int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, u8 *mac); -void ap_control_kickall(struct ap_data *ap); -void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent, - struct lib80211_crypt_data ***crypt); -int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[], - struct iw_quality qual[], int buf_size, - int aplist); -int prism2_ap_translate_scan(struct net_device *dev, - struct iw_request_info *info, char *buffer); -int prism2_hostapd(struct ap_data *ap, struct prism2_hostapd_param *param); - - -/* hostap_proc.c */ - -void hostap_init_proc(local_info_t *local); -void hostap_remove_proc(local_info_t *local); - - -/* hostap_info.c */ - -void hostap_info_init(local_info_t *local); -void hostap_info_process(local_info_t *local, struct sk_buff *skb); - - -/* hostap_ioctl.c */ - -extern const struct iw_handler_def hostap_iw_handler_def; -extern const struct ethtool_ops prism2_ethtool_ops; - -int hostap_siocdevprivate(struct net_device *dev, struct ifreq *ifr, - void __user *data, int cmd); - -#endif /* HOSTAP_H */ diff --git a/drivers/net/wireless/intersil/hostap/hostap_80211.h b/drivers/net/wireless/intersil/hostap/hostap_80211.h deleted file mode 100644 index 1452cf6ecb07e..0000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_80211.h +++ /dev/null @@ -1,97 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef HOSTAP_80211_H -#define HOSTAP_80211_H - -#include -#include -#include - -struct hostap_ieee80211_mgmt { - __le16 frame_control; - __le16 duration; - u8 da[6]; - u8 sa[6]; - u8 bssid[6]; - __le16 seq_ctrl; - union { - struct { - __le16 auth_alg; - __le16 auth_transaction; - __le16 status_code; - /* possibly followed by Challenge text */ - u8 variable[0]; - } __packed auth; - struct { - __le16 reason_code; - } __packed deauth; - struct { - __le16 capab_info; - __le16 listen_interval; - /* followed by SSID and Supported rates */ - u8 variable[0]; - } __packed assoc_req; - struct { - __le16 capab_info; - __le16 status_code; - __le16 aid; - /* followed by Supported rates */ - u8 variable[0]; - } __packed assoc_resp, reassoc_resp; - struct { - __le16 capab_info; - __le16 listen_interval; - u8 current_ap[6]; - /* followed by SSID and Supported rates */ - u8 variable[0]; - } __packed reassoc_req; - struct { - __le16 reason_code; - } __packed disassoc; - struct { - } __packed probe_req; - struct { - u8 timestamp[8]; - __le16 beacon_int; - __le16 capab_info; - /* followed by some of SSID, Supported rates, - * FH Params, DS Params, CF Params, IBSS Params, TIM */ - u8 variable[0]; - } __packed beacon, probe_resp; - } u; -} __packed; - - -#define IEEE80211_MGMT_HDR_LEN 24 -#define IEEE80211_DATA_HDR3_LEN 24 -#define IEEE80211_DATA_HDR4_LEN 30 - - -struct hostap_80211_rx_status { - u32 mac_time; - u8 signal; - u8 noise; - u16 rate; /* in 100 kbps */ -}; - -/* prism2_rx_80211 'type' argument */ -enum { - PRISM2_RX_MONITOR, PRISM2_RX_MGMT, PRISM2_RX_NON_ASSOC, - PRISM2_RX_NULLFUNC_ACK -}; - -int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats, int type); -void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats); -void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats); - -void hostap_dump_tx_80211(const char *name, struct sk_buff *skb); -netdev_tx_t hostap_data_start_xmit(struct sk_buff *skb, - struct net_device *dev); -netdev_tx_t hostap_mgmt_start_xmit(struct sk_buff *skb, - struct net_device *dev); -netdev_tx_t hostap_master_start_xmit(struct sk_buff *skb, - struct net_device *dev); - -#endif /* HOSTAP_80211_H */ diff --git a/drivers/net/wireless/intersil/hostap/hostap_80211_rx.c b/drivers/net/wireless/intersil/hostap/hostap_80211_rx.c deleted file mode 100644 index 61be822f90b51..0000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_80211_rx.c +++ /dev/null @@ -1,1116 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include -#include -#include -#include - -#include "hostap_80211.h" -#include "hostap.h" -#include "hostap_ap.h" - -/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ -/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ -static unsigned char rfc1042_header[] = -{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; -/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ -static unsigned char bridge_tunnel_header[] = -{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; -/* No encapsulation header if EtherType < 0x600 (=length) */ - -void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats) -{ - struct ieee80211_hdr *hdr; - u16 fc; - - hdr = (struct ieee80211_hdr *) skb->data; - - printk(KERN_DEBUG "%s: RX signal=%d noise=%d rate=%d len=%d " - "jiffies=%ld\n", - name, rx_stats->signal, rx_stats->noise, rx_stats->rate, - skb->len, jiffies); - - if (skb->len < 2) - return; - - fc = le16_to_cpu(hdr->frame_control); - printk(KERN_DEBUG " FC=0x%04x (type=%d:%d)%s%s", - fc, (fc & IEEE80211_FCTL_FTYPE) >> 2, - (fc & IEEE80211_FCTL_STYPE) >> 4, - fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", - fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); - - if (skb->len < IEEE80211_DATA_HDR3_LEN) { - printk("\n"); - return; - } - - printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id), - le16_to_cpu(hdr->seq_ctrl)); - - printk(KERN_DEBUG " A1=%pM", hdr->addr1); - printk(" A2=%pM", hdr->addr2); - printk(" A3=%pM", hdr->addr3); - if (skb->len >= 30) - printk(" A4=%pM", hdr->addr4); - printk("\n"); -} - - -/* Send RX frame to netif with 802.11 (and possible prism) header. - * Called from hardware or software IRQ context. */ -int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats, int type) -{ - struct hostap_interface *iface; - local_info_t *local; - int hdrlen, phdrlen, head_need, tail_need; - u16 fc; - int prism_header, ret; - struct ieee80211_hdr *fhdr; - - iface = netdev_priv(dev); - local = iface->local; - - if (dev->type == ARPHRD_IEEE80211_PRISM) { - if (local->monitor_type == PRISM2_MONITOR_PRISM) { - prism_header = 1; - phdrlen = sizeof(struct linux_wlan_ng_prism_hdr); - } else { /* local->monitor_type == PRISM2_MONITOR_CAPHDR */ - prism_header = 2; - phdrlen = sizeof(struct linux_wlan_ng_cap_hdr); - } - } else if (dev->type == ARPHRD_IEEE80211_RADIOTAP) { - prism_header = 3; - phdrlen = sizeof(struct hostap_radiotap_rx); - } else { - prism_header = 0; - phdrlen = 0; - } - - fhdr = (struct ieee80211_hdr *) skb->data; - fc = le16_to_cpu(fhdr->frame_control); - - if (type == PRISM2_RX_MGMT && (fc & IEEE80211_FCTL_VERS)) { - printk(KERN_DEBUG "%s: dropped management frame with header " - "version %d\n", dev->name, fc & IEEE80211_FCTL_VERS); - dev_kfree_skb_any(skb); - return 0; - } - - hdrlen = hostap_80211_get_hdrlen(fhdr->frame_control); - - /* check if there is enough room for extra data; if not, expand skb - * buffer to be large enough for the changes */ - head_need = phdrlen; - tail_need = 0; -#ifdef PRISM2_ADD_BOGUS_CRC - tail_need += 4; -#endif /* PRISM2_ADD_BOGUS_CRC */ - - head_need -= skb_headroom(skb); - tail_need -= skb_tailroom(skb); - - if (head_need > 0 || tail_need > 0) { - if (pskb_expand_head(skb, head_need > 0 ? head_need : 0, - tail_need > 0 ? tail_need : 0, - GFP_ATOMIC)) { - printk(KERN_DEBUG "%s: prism2_rx_80211 failed to " - "reallocate skb buffer\n", dev->name); - dev_kfree_skb_any(skb); - return 0; - } - } - - /* We now have an skb with enough head and tail room, so just insert - * the extra data */ - -#ifdef PRISM2_ADD_BOGUS_CRC - memset(skb_put(skb, 4), 0xff, 4); /* Prism2 strips CRC */ -#endif /* PRISM2_ADD_BOGUS_CRC */ - - if (prism_header == 1) { - struct linux_wlan_ng_prism_hdr *hdr; - hdr = skb_push(skb, phdrlen); - memset(hdr, 0, phdrlen); - hdr->msgcode = LWNG_CAP_DID_BASE; - hdr->msglen = sizeof(*hdr); - memcpy(hdr->devname, dev->name, sizeof(hdr->devname)); -#define LWNG_SETVAL(f,i,s,l,d) \ -hdr->f.did = LWNG_CAP_DID_BASE | (i << 12); \ -hdr->f.status = s; hdr->f.len = l; hdr->f.data = d - LWNG_SETVAL(hosttime, 1, 0, 4, jiffies); - LWNG_SETVAL(mactime, 2, 0, 4, rx_stats->mac_time); - LWNG_SETVAL(channel, 3, 1 /* no value */, 4, 0); - LWNG_SETVAL(rssi, 4, 1 /* no value */, 4, 0); - LWNG_SETVAL(sq, 5, 1 /* no value */, 4, 0); - LWNG_SETVAL(signal, 6, 0, 4, rx_stats->signal); - LWNG_SETVAL(noise, 7, 0, 4, rx_stats->noise); - LWNG_SETVAL(rate, 8, 0, 4, rx_stats->rate / 5); - LWNG_SETVAL(istx, 9, 0, 4, 0); - LWNG_SETVAL(frmlen, 10, 0, 4, skb->len - phdrlen); -#undef LWNG_SETVAL - } else if (prism_header == 2) { - struct linux_wlan_ng_cap_hdr *hdr; - hdr = skb_push(skb, phdrlen); - memset(hdr, 0, phdrlen); - hdr->version = htonl(LWNG_CAPHDR_VERSION); - hdr->length = htonl(phdrlen); - hdr->mactime = __cpu_to_be64(rx_stats->mac_time); - hdr->hosttime = __cpu_to_be64(jiffies); - hdr->phytype = htonl(4); /* dss_dot11_b */ - hdr->channel = htonl(local->channel); - hdr->datarate = htonl(rx_stats->rate); - hdr->antenna = htonl(0); /* unknown */ - hdr->priority = htonl(0); /* unknown */ - hdr->ssi_type = htonl(3); /* raw */ - hdr->ssi_signal = htonl(rx_stats->signal); - hdr->ssi_noise = htonl(rx_stats->noise); - hdr->preamble = htonl(0); /* unknown */ - hdr->encoding = htonl(1); /* cck */ - } else if (prism_header == 3) { - struct hostap_radiotap_rx *hdr; - hdr = skb_push(skb, phdrlen); - memset(hdr, 0, phdrlen); - hdr->hdr.it_len = cpu_to_le16(phdrlen); - hdr->hdr.it_present = - cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) | - (1 << IEEE80211_RADIOTAP_CHANNEL) | - (1 << IEEE80211_RADIOTAP_RATE) | - (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | - (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE)); - hdr->tsft = cpu_to_le64(rx_stats->mac_time); - hdr->chan_freq = cpu_to_le16(freq_list[local->channel - 1]); - hdr->chan_flags = cpu_to_le16(IEEE80211_CHAN_CCK | - IEEE80211_CHAN_2GHZ); - hdr->rate = rx_stats->rate / 5; - hdr->dbm_antsignal = rx_stats->signal; - hdr->dbm_antnoise = rx_stats->noise; - } - - ret = skb->len - phdrlen; - skb->dev = dev; - skb_reset_mac_header(skb); - skb_pull(skb, hdrlen); - if (prism_header) - skb_pull(skb, phdrlen); - skb->pkt_type = PACKET_OTHERHOST; - skb->protocol = cpu_to_be16(ETH_P_802_2); - memset(skb->cb, 0, sizeof(skb->cb)); - netif_rx(skb); - - return ret; -} - - -/* Called only as a tasklet (software IRQ) */ -static void monitor_rx(struct net_device *dev, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats) -{ - int len; - - len = prism2_rx_80211(dev, skb, rx_stats, PRISM2_RX_MONITOR); - dev->stats.rx_packets++; - dev->stats.rx_bytes += len; -} - - -/* Called only as a tasklet (software IRQ) */ -static struct prism2_frag_entry * -prism2_frag_cache_find(local_info_t *local, unsigned int seq, - unsigned int frag, u8 *src, u8 *dst) -{ - struct prism2_frag_entry *entry; - int i; - - for (i = 0; i < PRISM2_FRAG_CACHE_LEN; i++) { - entry = &local->frag_cache[i]; - if (entry->skb != NULL && - time_after(jiffies, entry->first_frag_time + 2 * HZ)) { - printk(KERN_DEBUG "%s: expiring fragment cache entry " - "seq=%u last_frag=%u\n", - local->dev->name, entry->seq, entry->last_frag); - dev_kfree_skb(entry->skb); - entry->skb = NULL; - } - - if (entry->skb != NULL && entry->seq == seq && - (entry->last_frag + 1 == frag || frag == -1) && - memcmp(entry->src_addr, src, ETH_ALEN) == 0 && - memcmp(entry->dst_addr, dst, ETH_ALEN) == 0) - return entry; - } - - return NULL; -} - - -/* Called only as a tasklet (software IRQ) */ -static struct sk_buff * -prism2_frag_cache_get(local_info_t *local, struct ieee80211_hdr *hdr) -{ - struct sk_buff *skb = NULL; - u16 sc; - unsigned int frag, seq; - struct prism2_frag_entry *entry; - - sc = le16_to_cpu(hdr->seq_ctrl); - frag = sc & IEEE80211_SCTL_FRAG; - seq = (sc & IEEE80211_SCTL_SEQ) >> 4; - - if (frag == 0) { - /* Reserve enough space to fit maximum frame length */ - skb = dev_alloc_skb(local->dev->mtu + - sizeof(struct ieee80211_hdr) + - 8 /* LLC */ + - 2 /* alignment */ + - 8 /* WEP */ + ETH_ALEN /* WDS */); - if (skb == NULL) - return NULL; - - entry = &local->frag_cache[local->frag_next_idx]; - local->frag_next_idx++; - if (local->frag_next_idx >= PRISM2_FRAG_CACHE_LEN) - local->frag_next_idx = 0; - - if (entry->skb != NULL) - dev_kfree_skb(entry->skb); - - entry->first_frag_time = jiffies; - entry->seq = seq; - entry->last_frag = frag; - entry->skb = skb; - memcpy(entry->src_addr, hdr->addr2, ETH_ALEN); - memcpy(entry->dst_addr, hdr->addr1, ETH_ALEN); - } else { - /* received a fragment of a frame for which the head fragment - * should have already been received */ - entry = prism2_frag_cache_find(local, seq, frag, hdr->addr2, - hdr->addr1); - if (entry != NULL) { - entry->last_frag = frag; - skb = entry->skb; - } - } - - return skb; -} - - -/* Called only as a tasklet (software IRQ) */ -static int prism2_frag_cache_invalidate(local_info_t *local, - struct ieee80211_hdr *hdr) -{ - u16 sc; - unsigned int seq; - struct prism2_frag_entry *entry; - - sc = le16_to_cpu(hdr->seq_ctrl); - seq = (sc & IEEE80211_SCTL_SEQ) >> 4; - - entry = prism2_frag_cache_find(local, seq, -1, hdr->addr2, hdr->addr1); - - if (entry == NULL) { - printk(KERN_DEBUG "%s: could not invalidate fragment cache " - "entry (seq=%u)\n", - local->dev->name, seq); - return -1; - } - - entry->skb = NULL; - return 0; -} - - -static struct hostap_bss_info *__hostap_get_bss(local_info_t *local, u8 *bssid, - u8 *ssid, size_t ssid_len) -{ - struct list_head *ptr; - struct hostap_bss_info *bss; - - list_for_each(ptr, &local->bss_list) { - bss = list_entry(ptr, struct hostap_bss_info, list); - if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0 && - (ssid == NULL || - (ssid_len == bss->ssid_len && - memcmp(ssid, bss->ssid, ssid_len) == 0))) { - list_move(&bss->list, &local->bss_list); - return bss; - } - } - - return NULL; -} - - -static struct hostap_bss_info *__hostap_add_bss(local_info_t *local, u8 *bssid, - u8 *ssid, size_t ssid_len) -{ - struct hostap_bss_info *bss; - - if (local->num_bss_info >= HOSTAP_MAX_BSS_COUNT) { - bss = list_entry(local->bss_list.prev, - struct hostap_bss_info, list); - list_del(&bss->list); - local->num_bss_info--; - } else { - bss = kmalloc(sizeof(*bss), GFP_ATOMIC); - if (bss == NULL) - return NULL; - } - - memset(bss, 0, sizeof(*bss)); - memcpy(bss->bssid, bssid, ETH_ALEN); - memcpy(bss->ssid, ssid, ssid_len); - bss->ssid_len = ssid_len; - local->num_bss_info++; - list_add(&bss->list, &local->bss_list); - return bss; -} - - -static void __hostap_expire_bss(local_info_t *local) -{ - struct hostap_bss_info *bss; - - while (local->num_bss_info > 0) { - bss = list_entry(local->bss_list.prev, - struct hostap_bss_info, list); - if (!time_after(jiffies, bss->last_update + 60 * HZ)) - break; - - list_del(&bss->list); - local->num_bss_info--; - kfree(bss); - } -} - - -/* Both IEEE 802.11 Beacon and Probe Response frames have similar structure, so - * the same routine can be used to parse both of them. */ -static void hostap_rx_sta_beacon(local_info_t *local, struct sk_buff *skb, - int stype) -{ - struct hostap_ieee80211_mgmt *mgmt; - int left, chan = 0; - u8 *pos; - u8 *ssid = NULL, *wpa = NULL, *rsn = NULL; - size_t ssid_len = 0, wpa_len = 0, rsn_len = 0; - struct hostap_bss_info *bss; - - if (skb->len < IEEE80211_MGMT_HDR_LEN + sizeof(mgmt->u.beacon)) - return; - - mgmt = (struct hostap_ieee80211_mgmt *) skb->data; - pos = mgmt->u.beacon.variable; - left = skb->len - (pos - skb->data); - - while (left >= 2) { - if (2 + pos[1] > left) - return; /* parse failed */ - switch (*pos) { - case WLAN_EID_SSID: - ssid = pos + 2; - ssid_len = pos[1]; - break; - case WLAN_EID_VENDOR_SPECIFIC: - if (pos[1] >= 4 && - pos[2] == 0x00 && pos[3] == 0x50 && - pos[4] == 0xf2 && pos[5] == 1) { - wpa = pos; - wpa_len = pos[1] + 2; - } - break; - case WLAN_EID_RSN: - rsn = pos; - rsn_len = pos[1] + 2; - break; - case WLAN_EID_DS_PARAMS: - if (pos[1] >= 1) - chan = pos[2]; - break; - } - left -= 2 + pos[1]; - pos += 2 + pos[1]; - } - - if (wpa_len > MAX_WPA_IE_LEN) - wpa_len = MAX_WPA_IE_LEN; - if (rsn_len > MAX_WPA_IE_LEN) - rsn_len = MAX_WPA_IE_LEN; - if (ssid_len > sizeof(bss->ssid)) - ssid_len = sizeof(bss->ssid); - - spin_lock(&local->lock); - bss = __hostap_get_bss(local, mgmt->bssid, ssid, ssid_len); - if (bss == NULL) - bss = __hostap_add_bss(local, mgmt->bssid, ssid, ssid_len); - if (bss) { - bss->last_update = jiffies; - bss->count++; - bss->capab_info = le16_to_cpu(mgmt->u.beacon.capab_info); - if (wpa) { - memcpy(bss->wpa_ie, wpa, wpa_len); - bss->wpa_ie_len = wpa_len; - } else - bss->wpa_ie_len = 0; - if (rsn) { - memcpy(bss->rsn_ie, rsn, rsn_len); - bss->rsn_ie_len = rsn_len; - } else - bss->rsn_ie_len = 0; - bss->chan = chan; - } - __hostap_expire_bss(local); - spin_unlock(&local->lock); -} - - -static int -hostap_rx_frame_mgmt(local_info_t *local, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats, u16 type, - u16 stype) -{ - if (local->iw_mode == IW_MODE_MASTER) - hostap_update_sta_ps(local, (struct ieee80211_hdr *) skb->data); - - if (local->hostapd && type == IEEE80211_FTYPE_MGMT) { - if (stype == IEEE80211_STYPE_BEACON && - local->iw_mode == IW_MODE_MASTER) { - struct sk_buff *skb2; - /* Process beacon frames also in kernel driver to - * update STA(AP) table statistics */ - skb2 = skb_clone(skb, GFP_ATOMIC); - if (skb2) - hostap_rx(skb2->dev, skb2, rx_stats); - } - - /* send management frames to the user space daemon for - * processing */ - local->apdevstats.rx_packets++; - local->apdevstats.rx_bytes += skb->len; - if (local->apdev == NULL) - return -1; - prism2_rx_80211(local->apdev, skb, rx_stats, PRISM2_RX_MGMT); - return 0; - } - - if (local->iw_mode == IW_MODE_MASTER) { - if (type != IEEE80211_FTYPE_MGMT && - type != IEEE80211_FTYPE_CTL) { - printk(KERN_DEBUG "%s: unknown management frame " - "(type=0x%02x, stype=0x%02x) dropped\n", - skb->dev->name, type >> 2, stype >> 4); - return -1; - } - - hostap_rx(skb->dev, skb, rx_stats); - return 0; - } else if (type == IEEE80211_FTYPE_MGMT && - (stype == IEEE80211_STYPE_BEACON || - stype == IEEE80211_STYPE_PROBE_RESP)) { - hostap_rx_sta_beacon(local, skb, stype); - return -1; - } else if (type == IEEE80211_FTYPE_MGMT && - (stype == IEEE80211_STYPE_ASSOC_RESP || - stype == IEEE80211_STYPE_REASSOC_RESP)) { - /* Ignore (Re)AssocResp silently since these are not currently - * needed but are still received when WPA/RSN mode is enabled. - */ - return -1; - } else { - printk(KERN_DEBUG "%s: hostap_rx_frame_mgmt: dropped unhandled" - " management frame in non-Host AP mode (type=%d:%d)\n", - skb->dev->name, type >> 2, stype >> 4); - return -1; - } -} - - -/* Called only as a tasklet (software IRQ) */ -static struct net_device *prism2_rx_get_wds(local_info_t *local, - u8 *addr) -{ - struct hostap_interface *iface = NULL; - struct list_head *ptr; - - read_lock_bh(&local->iface_lock); - list_for_each(ptr, &local->hostap_interfaces) { - iface = list_entry(ptr, struct hostap_interface, list); - if (iface->type == HOSTAP_INTERFACE_WDS && - memcmp(iface->u.wds.remote_addr, addr, ETH_ALEN) == 0) - break; - iface = NULL; - } - read_unlock_bh(&local->iface_lock); - - return iface ? iface->dev : NULL; -} - - -static int -hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr *hdr, u16 fc, - struct net_device **wds) -{ - /* FIX: is this really supposed to accept WDS frames only in Master - * mode? What about Repeater or Managed with WDS frames? */ - if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) != - (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS) && - (local->iw_mode != IW_MODE_MASTER || !(fc & IEEE80211_FCTL_TODS))) - return 0; /* not a WDS frame */ - - /* Possible WDS frame: either IEEE 802.11 compliant (if FromDS) - * or own non-standard frame with 4th address after payload */ - if (!ether_addr_equal(hdr->addr1, local->dev->dev_addr) && - (hdr->addr1[0] != 0xff || hdr->addr1[1] != 0xff || - hdr->addr1[2] != 0xff || hdr->addr1[3] != 0xff || - hdr->addr1[4] != 0xff || hdr->addr1[5] != 0xff)) { - /* RA (or BSSID) is not ours - drop */ - PDEBUG(DEBUG_EXTRA2, "%s: received WDS frame with " - "not own or broadcast %s=%pM\n", - local->dev->name, - fc & IEEE80211_FCTL_FROMDS ? "RA" : "BSSID", - hdr->addr1); - return -1; - } - - /* check if the frame came from a registered WDS connection */ - *wds = prism2_rx_get_wds(local, hdr->addr2); - if (*wds == NULL && fc & IEEE80211_FCTL_FROMDS && - (local->iw_mode != IW_MODE_INFRA || - !(local->wds_type & HOSTAP_WDS_AP_CLIENT) || - memcmp(hdr->addr2, local->bssid, ETH_ALEN) != 0)) { - /* require that WDS link has been registered with TA or the - * frame is from current AP when using 'AP client mode' */ - PDEBUG(DEBUG_EXTRA, "%s: received WDS[4 addr] frame " - "from unknown TA=%pM\n", - local->dev->name, hdr->addr2); - if (local->ap && local->ap->autom_ap_wds) - hostap_wds_link_oper(local, hdr->addr2, WDS_ADD); - return -1; - } - - if (*wds && !(fc & IEEE80211_FCTL_FROMDS) && local->ap && - hostap_is_sta_assoc(local->ap, hdr->addr2)) { - /* STA is actually associated with us even though it has a - * registered WDS link. Assume it is in 'AP client' mode. - * Since this is a 3-addr frame, assume it is not (bogus) WDS - * frame and process it like any normal ToDS frame from - * associated STA. */ - *wds = NULL; - } - - return 0; -} - - -static int hostap_is_eapol_frame(local_info_t *local, struct sk_buff *skb) -{ - struct net_device *dev = local->dev; - u16 fc, ethertype; - struct ieee80211_hdr *hdr; - u8 *pos; - - if (skb->len < 24) - return 0; - - hdr = (struct ieee80211_hdr *) skb->data; - fc = le16_to_cpu(hdr->frame_control); - - /* check that the frame is unicast frame to us */ - if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == - IEEE80211_FCTL_TODS && - ether_addr_equal(hdr->addr1, dev->dev_addr) && - ether_addr_equal(hdr->addr3, dev->dev_addr)) { - /* ToDS frame with own addr BSSID and DA */ - } else if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == - IEEE80211_FCTL_FROMDS && - ether_addr_equal(hdr->addr1, dev->dev_addr)) { - /* FromDS frame with own addr as DA */ - } else - return 0; - - if (skb->len < 24 + 8) - return 0; - - /* check for port access entity Ethernet type */ - pos = skb->data + 24; - ethertype = (pos[6] << 8) | pos[7]; - if (ethertype == ETH_P_PAE) - return 1; - - return 0; -} - - -/* Called only as a tasklet (software IRQ) */ -static int -hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb, - struct lib80211_crypt_data *crypt) -{ - struct ieee80211_hdr *hdr; - int res, hdrlen; - - if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL) - return 0; - - hdr = (struct ieee80211_hdr *) skb->data; - hdrlen = hostap_80211_get_hdrlen(hdr->frame_control); - - if (local->tkip_countermeasures && - strcmp(crypt->ops->name, "TKIP") == 0) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " - "received packet from %pM\n", - local->dev->name, hdr->addr2); - } - return -1; - } - - atomic_inc(&crypt->refcnt); - res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv); - atomic_dec(&crypt->refcnt); - if (res < 0) { - printk(KERN_DEBUG "%s: decryption failed (SA=%pM) res=%d\n", - local->dev->name, hdr->addr2, res); - local->comm_tallies.rx_discards_wep_undecryptable++; - return -1; - } - - return res; -} - - -/* Called only as a tasklet (software IRQ) */ -static int -hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb, - int keyidx, struct lib80211_crypt_data *crypt) -{ - struct ieee80211_hdr *hdr; - int res, hdrlen; - - if (crypt == NULL || crypt->ops->decrypt_msdu == NULL) - return 0; - - hdr = (struct ieee80211_hdr *) skb->data; - hdrlen = hostap_80211_get_hdrlen(hdr->frame_control); - - atomic_inc(&crypt->refcnt); - res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv); - atomic_dec(&crypt->refcnt); - if (res < 0) { - printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed" - " (SA=%pM keyidx=%d)\n", - local->dev->name, hdr->addr2, keyidx); - return -1; - } - - return 0; -} - - -/* All received frames are sent to this function. @skb contains the frame in - * IEEE 802.11 format, i.e., in the format it was sent over air. - * This function is called only as a tasklet (software IRQ). */ -void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats) -{ - struct hostap_interface *iface; - local_info_t *local; - struct ieee80211_hdr *hdr; - size_t hdrlen; - u16 fc, type, stype, sc; - struct net_device *wds = NULL; - unsigned int frag; - u8 *payload; - struct sk_buff *skb2 = NULL; - u16 ethertype; - int frame_authorized = 0; - int from_assoc_ap = 0; - u8 dst[ETH_ALEN]; - u8 src[ETH_ALEN]; - struct lib80211_crypt_data *crypt = NULL; - void *sta = NULL; - int keyidx = 0; - - iface = netdev_priv(dev); - local = iface->local; - iface->stats.rx_packets++; - iface->stats.rx_bytes += skb->len; - - /* dev is the master radio device; change this to be the default - * virtual interface (this may be changed to WDS device below) */ - dev = local->ddev; - iface = netdev_priv(dev); - - hdr = (struct ieee80211_hdr *) skb->data; - - if (skb->len < 10) - goto rx_dropped; - - fc = le16_to_cpu(hdr->frame_control); - type = fc & IEEE80211_FCTL_FTYPE; - stype = fc & IEEE80211_FCTL_STYPE; - sc = le16_to_cpu(hdr->seq_ctrl); - frag = sc & IEEE80211_SCTL_FRAG; - hdrlen = hostap_80211_get_hdrlen(hdr->frame_control); - - /* Put this code here so that we avoid duplicating it in all - * Rx paths. - Jean II */ -#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ - /* If spy monitoring on */ - if (iface->spy_data.spy_number > 0) { - struct iw_quality wstats; - wstats.level = rx_stats->signal; - wstats.noise = rx_stats->noise; - wstats.updated = IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_UPDATED - | IW_QUAL_QUAL_INVALID | IW_QUAL_DBM; - /* Update spy records */ - wireless_spy_update(dev, hdr->addr2, &wstats); - } -#endif /* IW_WIRELESS_SPY */ - hostap_update_rx_stats(local->ap, hdr, rx_stats); - - if (local->iw_mode == IW_MODE_MONITOR) { - monitor_rx(dev, skb, rx_stats); - return; - } - - if (local->host_decrypt) { - int idx = 0; - if (skb->len >= hdrlen + 3) - idx = skb->data[hdrlen + 3] >> 6; - crypt = local->crypt_info.crypt[idx]; - sta = NULL; - - /* Use station specific key to override default keys if the - * receiver address is a unicast address ("individual RA"). If - * bcrx_sta_key parameter is set, station specific key is used - * even with broad/multicast targets (this is against IEEE - * 802.11, but makes it easier to use different keys with - * stations that do not support WEP key mapping). */ - - if (!(hdr->addr1[0] & 0x01) || local->bcrx_sta_key) - (void) hostap_handle_sta_crypto(local, hdr, &crypt, - &sta); - - /* allow NULL decrypt to indicate an station specific override - * for default encryption */ - if (crypt && (crypt->ops == NULL || - crypt->ops->decrypt_mpdu == NULL)) - crypt = NULL; - - if (!crypt && (fc & IEEE80211_FCTL_PROTECTED)) { -#if 0 - /* This seems to be triggered by some (multicast?) - * frames from other than current BSS, so just drop the - * frames silently instead of filling system log with - * these reports. */ - printk(KERN_DEBUG "%s: WEP decryption failed (not set)" - " (SA=%pM)\n", - local->dev->name, hdr->addr2); -#endif - local->comm_tallies.rx_discards_wep_undecryptable++; - goto rx_dropped; - } - } - - if (type != IEEE80211_FTYPE_DATA) { - if (type == IEEE80211_FTYPE_MGMT && - stype == IEEE80211_STYPE_AUTH && - fc & IEEE80211_FCTL_PROTECTED && local->host_decrypt && - (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0) - { - printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth " - "from %pM\n", dev->name, hdr->addr2); - /* TODO: could inform hostapd about this so that it - * could send auth failure report */ - goto rx_dropped; - } - - if (hostap_rx_frame_mgmt(local, skb, rx_stats, type, stype)) - goto rx_dropped; - else - goto rx_exit; - } - - /* Data frame - extract src/dst addresses */ - if (skb->len < IEEE80211_DATA_HDR3_LEN) - goto rx_dropped; - - switch (fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { - case IEEE80211_FCTL_FROMDS: - memcpy(dst, hdr->addr1, ETH_ALEN); - memcpy(src, hdr->addr3, ETH_ALEN); - break; - case IEEE80211_FCTL_TODS: - memcpy(dst, hdr->addr3, ETH_ALEN); - memcpy(src, hdr->addr2, ETH_ALEN); - break; - case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS: - if (skb->len < IEEE80211_DATA_HDR4_LEN) - goto rx_dropped; - memcpy(dst, hdr->addr3, ETH_ALEN); - memcpy(src, hdr->addr4, ETH_ALEN); - break; - default: - memcpy(dst, hdr->addr1, ETH_ALEN); - memcpy(src, hdr->addr2, ETH_ALEN); - break; - } - - if (hostap_rx_frame_wds(local, hdr, fc, &wds)) - goto rx_dropped; - if (wds) - skb->dev = dev = wds; - - if (local->iw_mode == IW_MODE_MASTER && !wds && - (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == - IEEE80211_FCTL_FROMDS && - local->stadev && - memcmp(hdr->addr2, local->assoc_ap_addr, ETH_ALEN) == 0) { - /* Frame from BSSID of the AP for which we are a client */ - skb->dev = dev = local->stadev; - from_assoc_ap = 1; - } - - if ((local->iw_mode == IW_MODE_MASTER || - local->iw_mode == IW_MODE_REPEAT) && - !from_assoc_ap) { - switch (hostap_handle_sta_rx(local, dev, skb, rx_stats, - wds != NULL)) { - case AP_RX_CONTINUE_NOT_AUTHORIZED: - frame_authorized = 0; - break; - case AP_RX_CONTINUE: - frame_authorized = 1; - break; - case AP_RX_DROP: - goto rx_dropped; - case AP_RX_EXIT: - goto rx_exit; - } - } - - /* Nullfunc frames may have PS-bit set, so they must be passed to - * hostap_handle_sta_rx() before being dropped here. */ - if (stype != IEEE80211_STYPE_DATA && - stype != IEEE80211_STYPE_DATA_CFACK && - stype != IEEE80211_STYPE_DATA_CFPOLL && - stype != IEEE80211_STYPE_DATA_CFACKPOLL) { - if (stype != IEEE80211_STYPE_NULLFUNC) - printk(KERN_DEBUG "%s: RX: dropped data frame " - "with no data (type=0x%02x, subtype=0x%02x)\n", - dev->name, type >> 2, stype >> 4); - goto rx_dropped; - } - - /* skb: hdr + (possibly fragmented, possibly encrypted) payload */ - - if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) && - (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0) - goto rx_dropped; - hdr = (struct ieee80211_hdr *) skb->data; - - /* skb: hdr + (possibly fragmented) plaintext payload */ - - if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) && - (frag != 0 || (fc & IEEE80211_FCTL_MOREFRAGS))) { - int flen; - struct sk_buff *frag_skb = - prism2_frag_cache_get(local, hdr); - if (!frag_skb) { - printk(KERN_DEBUG "%s: Rx cannot get skb from " - "fragment cache (morefrag=%d seq=%u frag=%u)\n", - dev->name, (fc & IEEE80211_FCTL_MOREFRAGS) != 0, - (sc & IEEE80211_SCTL_SEQ) >> 4, frag); - goto rx_dropped; - } - - flen = skb->len; - if (frag != 0) - flen -= hdrlen; - - if (frag_skb->tail + flen > frag_skb->end) { - printk(KERN_WARNING "%s: host decrypted and " - "reassembled frame did not fit skb\n", - dev->name); - prism2_frag_cache_invalidate(local, hdr); - goto rx_dropped; - } - - if (frag == 0) { - /* copy first fragment (including full headers) into - * beginning of the fragment cache skb */ - skb_copy_from_linear_data(skb, skb_put(frag_skb, flen), - flen); - } else { - /* append frame payload to the end of the fragment - * cache skb */ - skb_copy_from_linear_data_offset(skb, hdrlen, - skb_put(frag_skb, - flen), flen); - } - dev_kfree_skb(skb); - skb = NULL; - - if (fc & IEEE80211_FCTL_MOREFRAGS) { - /* more fragments expected - leave the skb in fragment - * cache for now; it will be delivered to upper layers - * after all fragments have been received */ - goto rx_exit; - } - - /* this was the last fragment and the frame will be - * delivered, so remove skb from fragment cache */ - skb = frag_skb; - hdr = (struct ieee80211_hdr *) skb->data; - prism2_frag_cache_invalidate(local, hdr); - } - - /* skb: hdr + (possible reassembled) full MSDU payload; possibly still - * encrypted/authenticated */ - - if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) && - hostap_rx_frame_decrypt_msdu(local, skb, keyidx, crypt)) - goto rx_dropped; - - hdr = (struct ieee80211_hdr *) skb->data; - if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !local->open_wep) { - if (local->ieee_802_1x && - hostap_is_eapol_frame(local, skb)) { - /* pass unencrypted EAPOL frames even if encryption is - * configured */ - PDEBUG(DEBUG_EXTRA2, "%s: RX: IEEE 802.1X - passing " - "unencrypted EAPOL frame\n", local->dev->name); - } else { - printk(KERN_DEBUG "%s: encryption configured, but RX " - "frame not encrypted (SA=%pM)\n", - local->dev->name, hdr->addr2); - goto rx_dropped; - } - } - - if (local->drop_unencrypted && !(fc & IEEE80211_FCTL_PROTECTED) && - !hostap_is_eapol_frame(local, skb)) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: dropped unencrypted RX data " - "frame from %pM (drop_unencrypted=1)\n", - dev->name, hdr->addr2); - } - goto rx_dropped; - } - - /* skb: hdr + (possible reassembled) full plaintext payload */ - - payload = skb->data + hdrlen; - ethertype = (payload[6] << 8) | payload[7]; - - /* If IEEE 802.1X is used, check whether the port is authorized to send - * the received frame. */ - if (local->ieee_802_1x && local->iw_mode == IW_MODE_MASTER) { - if (ethertype == ETH_P_PAE) { - PDEBUG(DEBUG_EXTRA2, "%s: RX: IEEE 802.1X frame\n", - dev->name); - if (local->hostapd && local->apdev) { - /* Send IEEE 802.1X frames to the user - * space daemon for processing */ - prism2_rx_80211(local->apdev, skb, rx_stats, - PRISM2_RX_MGMT); - local->apdevstats.rx_packets++; - local->apdevstats.rx_bytes += skb->len; - goto rx_exit; - } - } else if (!frame_authorized) { - printk(KERN_DEBUG "%s: dropped frame from " - "unauthorized port (IEEE 802.1X): " - "ethertype=0x%04x\n", - dev->name, ethertype); - goto rx_dropped; - } - } - - /* convert hdr + possible LLC headers into Ethernet header */ - if (skb->len - hdrlen >= 8 && - ((memcmp(payload, rfc1042_header, 6) == 0 && - ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || - memcmp(payload, bridge_tunnel_header, 6) == 0)) { - /* remove RFC1042 or Bridge-Tunnel encapsulation and - * replace EtherType */ - skb_pull(skb, hdrlen + 6); - memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); - memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); - } else { - __be16 len; - /* Leave Ethernet header part of hdr and full payload */ - skb_pull(skb, hdrlen); - len = htons(skb->len); - memcpy(skb_push(skb, 2), &len, 2); - memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); - memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); - } - - if (wds && ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == - IEEE80211_FCTL_TODS) && - skb->len >= ETH_HLEN + ETH_ALEN) { - /* Non-standard frame: get addr4 from its bogus location after - * the payload */ - skb_copy_from_linear_data_offset(skb, skb->len - ETH_ALEN, - skb->data + ETH_ALEN, - ETH_ALEN); - skb_trim(skb, skb->len - ETH_ALEN); - } - - dev->stats.rx_packets++; - dev->stats.rx_bytes += skb->len; - - if (local->iw_mode == IW_MODE_MASTER && !wds && - local->ap->bridge_packets) { - if (dst[0] & 0x01) { - /* copy multicast frame both to the higher layers and - * to the wireless media */ - local->ap->bridged_multicast++; - skb2 = skb_clone(skb, GFP_ATOMIC); - if (skb2 == NULL) - printk(KERN_DEBUG "%s: skb_clone failed for " - "multicast frame\n", dev->name); - } else if (hostap_is_sta_authorized(local->ap, dst)) { - /* send frame directly to the associated STA using - * wireless media and not passing to higher layers */ - local->ap->bridged_unicast++; - skb2 = skb; - skb = NULL; - } - } - - if (skb2 != NULL) { - /* send to wireless media */ - skb2->dev = dev; - skb2->protocol = cpu_to_be16(ETH_P_802_3); - skb_reset_mac_header(skb2); - skb_reset_network_header(skb2); - /* skb2->network_header += ETH_HLEN; */ - dev_queue_xmit(skb2); - } - - if (skb) { - skb->protocol = eth_type_trans(skb, dev); - memset(skb->cb, 0, sizeof(skb->cb)); - netif_rx(skb); - } - - rx_exit: - if (sta) - hostap_handle_sta_release(sta); - return; - - rx_dropped: - dev_kfree_skb(skb); - - dev->stats.rx_dropped++; - goto rx_exit; -} - - -EXPORT_SYMBOL(hostap_80211_rx); diff --git a/drivers/net/wireless/intersil/hostap/hostap_80211_tx.c b/drivers/net/wireless/intersil/hostap/hostap_80211_tx.c deleted file mode 100644 index c47da06945c26..0000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_80211_tx.c +++ /dev/null @@ -1,554 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include -#include - -#include "hostap_80211.h" -#include "hostap_common.h" -#include "hostap_wlan.h" -#include "hostap.h" -#include "hostap_ap.h" - -/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ -/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ -static unsigned char rfc1042_header[] = -{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; -/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ -static unsigned char bridge_tunnel_header[] = -{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; -/* No encapsulation header if EtherType < 0x600 (=length) */ - -void hostap_dump_tx_80211(const char *name, struct sk_buff *skb) -{ - struct ieee80211_hdr *hdr; - u16 fc; - - hdr = (struct ieee80211_hdr *) skb->data; - - printk(KERN_DEBUG "%s: TX len=%d jiffies=%ld\n", - name, skb->len, jiffies); - - if (skb->len < 2) - return; - - fc = le16_to_cpu(hdr->frame_control); - printk(KERN_DEBUG " FC=0x%04x (type=%d:%d)%s%s", - fc, (fc & IEEE80211_FCTL_FTYPE) >> 2, - (fc & IEEE80211_FCTL_STYPE) >> 4, - fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", - fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); - - if (skb->len < IEEE80211_DATA_HDR3_LEN) { - printk("\n"); - return; - } - - printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id), - le16_to_cpu(hdr->seq_ctrl)); - - printk(KERN_DEBUG " A1=%pM", hdr->addr1); - printk(" A2=%pM", hdr->addr2); - printk(" A3=%pM", hdr->addr3); - if (skb->len >= 30) - printk(" A4=%pM", hdr->addr4); - printk("\n"); -} - - -/* hard_start_xmit function for data interfaces (wlan#, wlan#wds#, wlan#sta) - * Convert Ethernet header into a suitable IEEE 802.11 header depending on - * device configuration. */ -netdev_tx_t hostap_data_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - int need_headroom, need_tailroom = 0; - struct ieee80211_hdr hdr; - u16 fc, ethertype = 0; - enum { - WDS_NO = 0, WDS_OWN_FRAME, WDS_COMPLIANT_FRAME - } use_wds = WDS_NO; - u8 *encaps_data; - int hdr_len, encaps_len, skip_header_bytes; - int to_assoc_ap = 0; - struct hostap_skb_tx_data *meta; - - iface = netdev_priv(dev); - local = iface->local; - - if (skb->len < ETH_HLEN) { - printk(KERN_DEBUG "%s: hostap_data_start_xmit: short skb " - "(len=%d)\n", dev->name, skb->len); - kfree_skb(skb); - return NETDEV_TX_OK; - } - - if (local->ddev != dev) { - use_wds = (local->iw_mode == IW_MODE_MASTER && - !(local->wds_type & HOSTAP_WDS_STANDARD_FRAME)) ? - WDS_OWN_FRAME : WDS_COMPLIANT_FRAME; - if (dev == local->stadev) { - to_assoc_ap = 1; - use_wds = WDS_NO; - } else if (dev == local->apdev) { - printk(KERN_DEBUG "%s: prism2_tx: trying to use " - "AP device with Ethernet net dev\n", dev->name); - kfree_skb(skb); - return NETDEV_TX_OK; - } - } else { - if (local->iw_mode == IW_MODE_REPEAT) { - printk(KERN_DEBUG "%s: prism2_tx: trying to use " - "non-WDS link in Repeater mode\n", dev->name); - kfree_skb(skb); - return NETDEV_TX_OK; - } else if (local->iw_mode == IW_MODE_INFRA && - (local->wds_type & HOSTAP_WDS_AP_CLIENT) && - !ether_addr_equal(skb->data + ETH_ALEN, dev->dev_addr)) { - /* AP client mode: send frames with foreign src addr - * using 4-addr WDS frames */ - use_wds = WDS_COMPLIANT_FRAME; - } - } - - /* Incoming skb->data: dst_addr[6], src_addr[6], proto[2], payload - * ==> - * Prism2 TX frame with 802.11 header: - * txdesc (address order depending on used mode; includes dst_addr and - * src_addr), possible encapsulation (RFC1042/Bridge-Tunnel; - * proto[2], payload {, possible addr4[6]} */ - - ethertype = (skb->data[12] << 8) | skb->data[13]; - - memset(&hdr, 0, sizeof(hdr)); - - /* Length of data after IEEE 802.11 header */ - encaps_data = NULL; - encaps_len = 0; - skip_header_bytes = ETH_HLEN; - if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) { - encaps_data = bridge_tunnel_header; - encaps_len = sizeof(bridge_tunnel_header); - skip_header_bytes -= 2; - } else if (ethertype >= 0x600) { - encaps_data = rfc1042_header; - encaps_len = sizeof(rfc1042_header); - skip_header_bytes -= 2; - } - - fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA; - hdr_len = IEEE80211_DATA_HDR3_LEN; - - if (use_wds != WDS_NO) { - /* Note! Prism2 station firmware has problems with sending real - * 802.11 frames with four addresses; until these problems can - * be fixed or worked around, 4-addr frames needed for WDS are - * using incompatible format: FromDS flag is not set and the - * fourth address is added after the frame payload; it is - * assumed, that the receiving station knows how to handle this - * frame format */ - - if (use_wds == WDS_COMPLIANT_FRAME) { - fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS; - /* From&To DS: Addr1 = RA, Addr2 = TA, Addr3 = DA, - * Addr4 = SA */ - skb_copy_from_linear_data_offset(skb, ETH_ALEN, - &hdr.addr4, ETH_ALEN); - hdr_len += ETH_ALEN; - } else { - /* bogus 4-addr format to workaround Prism2 station - * f/w bug */ - fc |= IEEE80211_FCTL_TODS; - /* From DS: Addr1 = DA (used as RA), - * Addr2 = BSSID (used as TA), Addr3 = SA (used as DA), - */ - - /* SA from skb->data + ETH_ALEN will be added after - * frame payload; use hdr.addr4 as a temporary buffer - */ - skb_copy_from_linear_data_offset(skb, ETH_ALEN, - &hdr.addr4, ETH_ALEN); - need_tailroom += ETH_ALEN; - } - - /* send broadcast and multicast frames to broadcast RA, if - * configured; otherwise, use unicast RA of the WDS link */ - if ((local->wds_type & HOSTAP_WDS_BROADCAST_RA) && - is_multicast_ether_addr(skb->data)) - eth_broadcast_addr(hdr.addr1); - else if (iface->type == HOSTAP_INTERFACE_WDS) - memcpy(&hdr.addr1, iface->u.wds.remote_addr, - ETH_ALEN); - else - memcpy(&hdr.addr1, local->bssid, ETH_ALEN); - memcpy(&hdr.addr2, dev->dev_addr, ETH_ALEN); - skb_copy_from_linear_data(skb, &hdr.addr3, ETH_ALEN); - } else if (local->iw_mode == IW_MODE_MASTER && !to_assoc_ap) { - fc |= IEEE80211_FCTL_FROMDS; - /* From DS: Addr1 = DA, Addr2 = BSSID, Addr3 = SA */ - skb_copy_from_linear_data(skb, &hdr.addr1, ETH_ALEN); - memcpy(&hdr.addr2, dev->dev_addr, ETH_ALEN); - skb_copy_from_linear_data_offset(skb, ETH_ALEN, &hdr.addr3, - ETH_ALEN); - } else if (local->iw_mode == IW_MODE_INFRA || to_assoc_ap) { - fc |= IEEE80211_FCTL_TODS; - /* To DS: Addr1 = BSSID, Addr2 = SA, Addr3 = DA */ - memcpy(&hdr.addr1, to_assoc_ap ? - local->assoc_ap_addr : local->bssid, ETH_ALEN); - skb_copy_from_linear_data_offset(skb, ETH_ALEN, &hdr.addr2, - ETH_ALEN); - skb_copy_from_linear_data(skb, &hdr.addr3, ETH_ALEN); - } else if (local->iw_mode == IW_MODE_ADHOC) { - /* not From/To DS: Addr1 = DA, Addr2 = SA, Addr3 = BSSID */ - skb_copy_from_linear_data(skb, &hdr.addr1, ETH_ALEN); - skb_copy_from_linear_data_offset(skb, ETH_ALEN, &hdr.addr2, - ETH_ALEN); - memcpy(&hdr.addr3, local->bssid, ETH_ALEN); - } - - hdr.frame_control = cpu_to_le16(fc); - - skb_pull(skb, skip_header_bytes); - need_headroom = local->func->need_tx_headroom + hdr_len + encaps_len; - if (skb_tailroom(skb) < need_tailroom) { - skb = skb_unshare(skb, GFP_ATOMIC); - if (skb == NULL) { - iface->stats.tx_dropped++; - return NETDEV_TX_OK; - } - if (pskb_expand_head(skb, need_headroom, need_tailroom, - GFP_ATOMIC)) { - kfree_skb(skb); - iface->stats.tx_dropped++; - return NETDEV_TX_OK; - } - } else if (skb_headroom(skb) < need_headroom) { - struct sk_buff *tmp = skb; - skb = skb_realloc_headroom(skb, need_headroom); - kfree_skb(tmp); - if (skb == NULL) { - iface->stats.tx_dropped++; - return NETDEV_TX_OK; - } - } else { - skb = skb_unshare(skb, GFP_ATOMIC); - if (skb == NULL) { - iface->stats.tx_dropped++; - return NETDEV_TX_OK; - } - } - - if (encaps_data) - memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len); - memcpy(skb_push(skb, hdr_len), &hdr, hdr_len); - if (use_wds == WDS_OWN_FRAME) { - skb_put_data(skb, &hdr.addr4, ETH_ALEN); - } - - iface->stats.tx_packets++; - iface->stats.tx_bytes += skb->len; - - skb_reset_mac_header(skb); - meta = (struct hostap_skb_tx_data *) skb->cb; - memset(meta, 0, sizeof(*meta)); - meta->magic = HOSTAP_SKB_TX_DATA_MAGIC; - if (use_wds) - meta->flags |= HOSTAP_TX_FLAGS_WDS; - meta->ethertype = ethertype; - meta->iface = iface; - - /* Send IEEE 802.11 encapsulated frame using the master radio device */ - skb->dev = local->dev; - dev_queue_xmit(skb); - return NETDEV_TX_OK; -} - - -/* hard_start_xmit function for hostapd wlan#ap interfaces */ -netdev_tx_t hostap_mgmt_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - struct hostap_skb_tx_data *meta; - struct ieee80211_hdr *hdr; - u16 fc; - - iface = netdev_priv(dev); - local = iface->local; - - if (skb->len < 10) { - printk(KERN_DEBUG "%s: hostap_mgmt_start_xmit: short skb " - "(len=%d)\n", dev->name, skb->len); - kfree_skb(skb); - return NETDEV_TX_OK; - } - - iface->stats.tx_packets++; - iface->stats.tx_bytes += skb->len; - - meta = (struct hostap_skb_tx_data *) skb->cb; - memset(meta, 0, sizeof(*meta)); - meta->magic = HOSTAP_SKB_TX_DATA_MAGIC; - meta->iface = iface; - - if (skb->len >= IEEE80211_DATA_HDR3_LEN + sizeof(rfc1042_header) + 2) { - hdr = (struct ieee80211_hdr *) skb->data; - fc = le16_to_cpu(hdr->frame_control); - if (ieee80211_is_data(hdr->frame_control) && - (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_DATA) { - u8 *pos = &skb->data[IEEE80211_DATA_HDR3_LEN + - sizeof(rfc1042_header)]; - meta->ethertype = (pos[0] << 8) | pos[1]; - } - } - - /* Send IEEE 802.11 encapsulated frame using the master radio device */ - skb->dev = local->dev; - dev_queue_xmit(skb); - return NETDEV_TX_OK; -} - - -/* Called only from software IRQ */ -static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, - struct lib80211_crypt_data *crypt) -{ - struct hostap_interface *iface; - local_info_t *local; - struct ieee80211_hdr *hdr; - int prefix_len, postfix_len, hdr_len, res; - - iface = netdev_priv(skb->dev); - local = iface->local; - - if (skb->len < IEEE80211_DATA_HDR3_LEN) { - kfree_skb(skb); - return NULL; - } - - if (local->tkip_countermeasures && - strcmp(crypt->ops->name, "TKIP") == 0) { - hdr = (struct ieee80211_hdr *) skb->data; - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " - "TX packet to %pM\n", - local->dev->name, hdr->addr1); - } - kfree_skb(skb); - return NULL; - } - - skb = skb_unshare(skb, GFP_ATOMIC); - if (skb == NULL) - return NULL; - - prefix_len = crypt->ops->extra_mpdu_prefix_len + - crypt->ops->extra_msdu_prefix_len; - postfix_len = crypt->ops->extra_mpdu_postfix_len + - crypt->ops->extra_msdu_postfix_len; - if ((skb_headroom(skb) < prefix_len || - skb_tailroom(skb) < postfix_len) && - pskb_expand_head(skb, prefix_len, postfix_len, GFP_ATOMIC)) { - kfree_skb(skb); - return NULL; - } - - hdr = (struct ieee80211_hdr *) skb->data; - hdr_len = hostap_80211_get_hdrlen(hdr->frame_control); - - /* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so - * call both MSDU and MPDU encryption functions from here. */ - atomic_inc(&crypt->refcnt); - res = 0; - if (crypt->ops->encrypt_msdu) - res = crypt->ops->encrypt_msdu(skb, hdr_len, crypt->priv); - if (res == 0 && crypt->ops->encrypt_mpdu) - res = crypt->ops->encrypt_mpdu(skb, hdr_len, crypt->priv); - atomic_dec(&crypt->refcnt); - if (res < 0) { - kfree_skb(skb); - return NULL; - } - - return skb; -} - - -/* hard_start_xmit function for master radio interface wifi#. - * AP processing (TX rate control, power save buffering, etc.). - * Use hardware TX function to send the frame. */ -netdev_tx_t hostap_master_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - netdev_tx_t ret = NETDEV_TX_BUSY; - u16 fc; - struct hostap_tx_data tx; - ap_tx_ret tx_ret; - struct hostap_skb_tx_data *meta; - int no_encrypt = 0; - struct ieee80211_hdr *hdr; - - iface = netdev_priv(dev); - local = iface->local; - - tx.skb = skb; - tx.sta_ptr = NULL; - - meta = (struct hostap_skb_tx_data *) skb->cb; - if (meta->magic != HOSTAP_SKB_TX_DATA_MAGIC) { - printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, " - "expected 0x%08x)\n", - dev->name, meta->magic, HOSTAP_SKB_TX_DATA_MAGIC); - ret = NETDEV_TX_OK; - iface->stats.tx_dropped++; - goto fail; - } - - if (local->host_encrypt) { - /* Set crypt to default algorithm and key; will be replaced in - * AP code if STA has own alg/key */ - tx.crypt = local->crypt_info.crypt[local->crypt_info.tx_keyidx]; - tx.host_encrypt = 1; - } else { - tx.crypt = NULL; - tx.host_encrypt = 0; - } - - if (skb->len < 24) { - printk(KERN_DEBUG "%s: hostap_master_start_xmit: short skb " - "(len=%d)\n", dev->name, skb->len); - ret = NETDEV_TX_OK; - iface->stats.tx_dropped++; - goto fail; - } - - /* FIX (?): - * Wi-Fi 802.11b test plan suggests that AP should ignore power save - * bit in authentication and (re)association frames and assume tha - * STA remains awake for the response. */ - tx_ret = hostap_handle_sta_tx(local, &tx); - skb = tx.skb; - meta = (struct hostap_skb_tx_data *) skb->cb; - hdr = (struct ieee80211_hdr *) skb->data; - fc = le16_to_cpu(hdr->frame_control); - switch (tx_ret) { - case AP_TX_CONTINUE: - break; - case AP_TX_CONTINUE_NOT_AUTHORIZED: - if (local->ieee_802_1x && - ieee80211_is_data(hdr->frame_control) && - meta->ethertype != ETH_P_PAE && - !(meta->flags & HOSTAP_TX_FLAGS_WDS)) { - printk(KERN_DEBUG "%s: dropped frame to unauthorized " - "port (IEEE 802.1X): ethertype=0x%04x\n", - dev->name, meta->ethertype); - hostap_dump_tx_80211(dev->name, skb); - - ret = NETDEV_TX_OK; /* drop packet */ - iface->stats.tx_dropped++; - goto fail; - } - break; - case AP_TX_DROP: - ret = NETDEV_TX_OK; /* drop packet */ - iface->stats.tx_dropped++; - goto fail; - case AP_TX_RETRY: - goto fail; - case AP_TX_BUFFERED: - /* do not free skb here, it will be freed when the - * buffered frame is sent/timed out */ - ret = NETDEV_TX_OK; - goto tx_exit; - } - - /* Request TX callback if protocol version is 2 in 802.11 header; - * this version 2 is a special case used between hostapd and kernel - * driver */ - if (((fc & IEEE80211_FCTL_VERS) == BIT(1)) && - local->ap && local->ap->tx_callback_idx && meta->tx_cb_idx == 0) { - meta->tx_cb_idx = local->ap->tx_callback_idx; - - /* remove special version from the frame header */ - fc &= ~IEEE80211_FCTL_VERS; - hdr->frame_control = cpu_to_le16(fc); - } - - if (!ieee80211_is_data(hdr->frame_control)) { - no_encrypt = 1; - tx.crypt = NULL; - } - - if (local->ieee_802_1x && meta->ethertype == ETH_P_PAE && tx.crypt && - !(fc & IEEE80211_FCTL_PROTECTED)) { - no_encrypt = 1; - PDEBUG(DEBUG_EXTRA2, "%s: TX: IEEE 802.1X - passing " - "unencrypted EAPOL frame\n", dev->name); - tx.crypt = NULL; /* no encryption for IEEE 802.1X frames */ - } - - if (tx.crypt && (!tx.crypt->ops || !tx.crypt->ops->encrypt_mpdu)) - tx.crypt = NULL; - else if ((tx.crypt || - local->crypt_info.crypt[local->crypt_info.tx_keyidx]) && - !no_encrypt) { - /* Add ISWEP flag both for firmware and host based encryption - */ - fc |= IEEE80211_FCTL_PROTECTED; - hdr->frame_control = cpu_to_le16(fc); - } else if (local->drop_unencrypted && - ieee80211_is_data(hdr->frame_control) && - meta->ethertype != ETH_P_PAE) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: dropped unencrypted TX data " - "frame (drop_unencrypted=1)\n", dev->name); - } - iface->stats.tx_dropped++; - ret = NETDEV_TX_OK; - goto fail; - } - - if (tx.crypt) { - skb = hostap_tx_encrypt(skb, tx.crypt); - if (skb == NULL) { - printk(KERN_DEBUG "%s: TX - encryption failed\n", - dev->name); - ret = NETDEV_TX_OK; - goto fail; - } - meta = (struct hostap_skb_tx_data *) skb->cb; - if (meta->magic != HOSTAP_SKB_TX_DATA_MAGIC) { - printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, " - "expected 0x%08x) after hostap_tx_encrypt\n", - dev->name, meta->magic, - HOSTAP_SKB_TX_DATA_MAGIC); - ret = NETDEV_TX_OK; - iface->stats.tx_dropped++; - goto fail; - } - } - - if (local->func->tx == NULL || local->func->tx(skb, dev)) { - ret = NETDEV_TX_OK; - iface->stats.tx_dropped++; - } else { - ret = NETDEV_TX_OK; - iface->stats.tx_packets++; - iface->stats.tx_bytes += skb->len; - } - - fail: - if (ret == NETDEV_TX_OK && skb) - dev_kfree_skb(skb); - tx_exit: - if (tx.sta_ptr) - hostap_handle_sta_release(tx.sta_ptr); - return ret; -} - - -EXPORT_SYMBOL(hostap_master_start_xmit); diff --git a/drivers/net/wireless/intersil/hostap/hostap_ap.c b/drivers/net/wireless/intersil/hostap/hostap_ap.c deleted file mode 100644 index 9b546a71e7a2e..0000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_ap.c +++ /dev/null @@ -1,3277 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Intersil Prism2 driver with Host AP (software access point) support - * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen - * - * Copyright (c) 2002-2005, Jouni Malinen - * - * This file is to be included into hostap.c when S/W AP functionality is - * compiled. - * - * AP: FIX: - * - if unicast Class 2 (assoc,reassoc,disassoc) frame received from - * unauthenticated STA, send deauth. frame (8802.11: 5.5) - * - if unicast Class 3 (data with to/from DS,deauth,pspoll) frame received - * from authenticated, but unassoc STA, send disassoc frame (8802.11: 5.5) - * - if unicast Class 3 received from unauthenticated STA, send deauth. frame - * (8802.11: 5.5) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "hostap_wlan.h" -#include "hostap.h" -#include "hostap_ap.h" - -static int other_ap_policy[MAX_PARM_DEVICES] = { AP_OTHER_AP_SKIP_ALL, - DEF_INTS }; -module_param_array(other_ap_policy, int, NULL, 0444); -MODULE_PARM_DESC(other_ap_policy, "Other AP beacon monitoring policy (0-3)"); - -static int ap_max_inactivity[MAX_PARM_DEVICES] = { AP_MAX_INACTIVITY_SEC, - DEF_INTS }; -module_param_array(ap_max_inactivity, int, NULL, 0444); -MODULE_PARM_DESC(ap_max_inactivity, "AP timeout (in seconds) for station " - "inactivity"); - -static int ap_bridge_packets[MAX_PARM_DEVICES] = { 1, DEF_INTS }; -module_param_array(ap_bridge_packets, int, NULL, 0444); -MODULE_PARM_DESC(ap_bridge_packets, "Bridge packets directly between " - "stations"); - -static int autom_ap_wds[MAX_PARM_DEVICES] = { 0, DEF_INTS }; -module_param_array(autom_ap_wds, int, NULL, 0444); -MODULE_PARM_DESC(autom_ap_wds, "Add WDS connections to other APs " - "automatically"); - - -static struct sta_info* ap_get_sta(struct ap_data *ap, u8 *sta); -static void hostap_event_expired_sta(struct net_device *dev, - struct sta_info *sta); -static void handle_add_proc_queue(struct work_struct *work); - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT -static void handle_wds_oper_queue(struct work_struct *work); -static void prism2_send_mgmt(struct net_device *dev, - u16 type_subtype, char *body, - int body_len, u8 *addr, u16 tx_cb_idx); -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - -#if !defined(PRISM2_NO_PROCFS_DEBUG) && defined(CONFIG_PROC_FS) -static int ap_debug_proc_show(struct seq_file *m, void *v) -{ - struct ap_data *ap = pde_data(file_inode(m->file)); - - seq_printf(m, "BridgedUnicastFrames=%u\n", ap->bridged_unicast); - seq_printf(m, "BridgedMulticastFrames=%u\n", ap->bridged_multicast); - seq_printf(m, "max_inactivity=%u\n", ap->max_inactivity / HZ); - seq_printf(m, "bridge_packets=%u\n", ap->bridge_packets); - seq_printf(m, "nullfunc_ack=%u\n", ap->nullfunc_ack); - seq_printf(m, "autom_ap_wds=%u\n", ap->autom_ap_wds); - seq_printf(m, "auth_algs=%u\n", ap->local->auth_algs); - seq_printf(m, "tx_drop_nonassoc=%u\n", ap->tx_drop_nonassoc); - return 0; -} -#endif - -static void ap_sta_hash_add(struct ap_data *ap, struct sta_info *sta) -{ - sta->hnext = ap->sta_hash[STA_HASH(sta->addr)]; - ap->sta_hash[STA_HASH(sta->addr)] = sta; -} - -static void ap_sta_hash_del(struct ap_data *ap, struct sta_info *sta) -{ - struct sta_info *s; - - s = ap->sta_hash[STA_HASH(sta->addr)]; - if (s == NULL) return; - if (ether_addr_equal(s->addr, sta->addr)) { - ap->sta_hash[STA_HASH(sta->addr)] = s->hnext; - return; - } - - while (s->hnext != NULL && !ether_addr_equal(s->hnext->addr, sta->addr)) - s = s->hnext; - if (s->hnext != NULL) - s->hnext = s->hnext->hnext; - else - printk("AP: could not remove STA %pM from hash table\n", - sta->addr); -} - -static void ap_free_sta(struct ap_data *ap, struct sta_info *sta) -{ - if (sta->ap && sta->local) - hostap_event_expired_sta(sta->local->dev, sta); - - if (ap->proc != NULL) { - char name[20]; - sprintf(name, "%pM", sta->addr); - remove_proc_entry(name, ap->proc); - } - - if (sta->crypt) { - sta->crypt->ops->deinit(sta->crypt->priv); - kfree(sta->crypt); - sta->crypt = NULL; - } - - skb_queue_purge(&sta->tx_buf); - - ap->num_sta--; -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - if (sta->aid > 0) - ap->sta_aid[sta->aid - 1] = NULL; - - if (!sta->ap) - kfree(sta->u.sta.challenge); - timer_shutdown_sync(&sta->timer); -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - kfree(sta); -} - - -static void hostap_set_tim(local_info_t *local, int aid, int set) -{ - if (local->func->set_tim) - local->func->set_tim(local->dev, aid, set); -} - - -static void hostap_event_new_sta(struct net_device *dev, struct sta_info *sta) -{ - union iwreq_data wrqu; - memset(&wrqu, 0, sizeof(wrqu)); - memcpy(wrqu.addr.sa_data, sta->addr, ETH_ALEN); - wrqu.addr.sa_family = ARPHRD_ETHER; - wireless_send_event(dev, IWEVREGISTERED, &wrqu, NULL); -} - - -static void hostap_event_expired_sta(struct net_device *dev, - struct sta_info *sta) -{ - union iwreq_data wrqu; - memset(&wrqu, 0, sizeof(wrqu)); - memcpy(wrqu.addr.sa_data, sta->addr, ETH_ALEN); - wrqu.addr.sa_family = ARPHRD_ETHER; - wireless_send_event(dev, IWEVEXPIRED, &wrqu, NULL); -} - - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - -static void ap_handle_timer(struct timer_list *t) -{ - struct sta_info *sta = from_timer(sta, t, timer); - local_info_t *local; - struct ap_data *ap; - unsigned long next_time = 0; - int was_assoc; - - if (sta == NULL || sta->local == NULL || sta->local->ap == NULL) { - PDEBUG(DEBUG_AP, "ap_handle_timer() called with NULL data\n"); - return; - } - - local = sta->local; - ap = local->ap; - was_assoc = sta->flags & WLAN_STA_ASSOC; - - if (atomic_read(&sta->users) != 0) - next_time = jiffies + HZ; - else if ((sta->flags & WLAN_STA_PERM) && !(sta->flags & WLAN_STA_AUTH)) - next_time = jiffies + ap->max_inactivity; - - if (time_before(jiffies, sta->last_rx + ap->max_inactivity)) { - /* station activity detected; reset timeout state */ - sta->timeout_next = STA_NULLFUNC; - next_time = sta->last_rx + ap->max_inactivity; - } else if (sta->timeout_next == STA_DISASSOC && - !(sta->flags & WLAN_STA_PENDING_POLL)) { - /* STA ACKed data nullfunc frame poll */ - sta->timeout_next = STA_NULLFUNC; - next_time = jiffies + ap->max_inactivity; - } - - if (next_time) { - sta->timer.expires = next_time; - add_timer(&sta->timer); - return; - } - - if (sta->ap) - sta->timeout_next = STA_DEAUTH; - - if (sta->timeout_next == STA_DEAUTH && !(sta->flags & WLAN_STA_PERM)) { - spin_lock(&ap->sta_table_lock); - ap_sta_hash_del(ap, sta); - list_del(&sta->list); - spin_unlock(&ap->sta_table_lock); - sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); - } else if (sta->timeout_next == STA_DISASSOC) - sta->flags &= ~WLAN_STA_ASSOC; - - if (was_assoc && !(sta->flags & WLAN_STA_ASSOC) && !sta->ap) - hostap_event_expired_sta(local->dev, sta); - - if (sta->timeout_next == STA_DEAUTH && sta->aid > 0 && - !skb_queue_empty(&sta->tx_buf)) { - hostap_set_tim(local, sta->aid, 0); - sta->flags &= ~WLAN_STA_TIM; - } - - if (sta->ap) { - if (ap->autom_ap_wds) { - PDEBUG(DEBUG_AP, "%s: removing automatic WDS " - "connection to AP %pM\n", - local->dev->name, sta->addr); - hostap_wds_link_oper(local, sta->addr, WDS_DEL); - } - } else if (sta->timeout_next == STA_NULLFUNC) { - /* send data frame to poll STA and check whether this frame - * is ACKed */ - /* FIX: IEEE80211_STYPE_NULLFUNC would be more appropriate, but - * it is apparently not retried so TX Exc events are not - * received for it */ - sta->flags |= WLAN_STA_PENDING_POLL; - prism2_send_mgmt(local->dev, IEEE80211_FTYPE_DATA | - IEEE80211_STYPE_DATA, NULL, 0, - sta->addr, ap->tx_callback_poll); - } else { - int deauth = sta->timeout_next == STA_DEAUTH; - __le16 resp; - PDEBUG(DEBUG_AP, "%s: sending %s info to STA %pM" - "(last=%lu, jiffies=%lu)\n", - local->dev->name, - deauth ? "deauthentication" : "disassociation", - sta->addr, sta->last_rx, jiffies); - - resp = cpu_to_le16(deauth ? WLAN_REASON_PREV_AUTH_NOT_VALID : - WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); - prism2_send_mgmt(local->dev, IEEE80211_FTYPE_MGMT | - (deauth ? IEEE80211_STYPE_DEAUTH : - IEEE80211_STYPE_DISASSOC), - (char *) &resp, 2, sta->addr, 0); - } - - if (sta->timeout_next == STA_DEAUTH) { - if (sta->flags & WLAN_STA_PERM) { - PDEBUG(DEBUG_AP, "%s: STA %pM" - " would have been removed, " - "but it has 'perm' flag\n", - local->dev->name, sta->addr); - } else - ap_free_sta(ap, sta); - return; - } - - if (sta->timeout_next == STA_NULLFUNC) { - sta->timeout_next = STA_DISASSOC; - sta->timer.expires = jiffies + AP_DISASSOC_DELAY; - } else { - sta->timeout_next = STA_DEAUTH; - sta->timer.expires = jiffies + AP_DEAUTH_DELAY; - } - - add_timer(&sta->timer); -} - - -void hostap_deauth_all_stas(struct net_device *dev, struct ap_data *ap, - int resend) -{ - u8 addr[ETH_ALEN]; - __le16 resp; - int i; - - PDEBUG(DEBUG_AP, "%s: Deauthenticate all stations\n", dev->name); - eth_broadcast_addr(addr); - - resp = cpu_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); - - /* deauth message sent; try to resend it few times; the message is - * broadcast, so it may be delayed until next DTIM; there is not much - * else we can do at this point since the driver is going to be shut - * down */ - for (i = 0; i < 5; i++) { - prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | - IEEE80211_STYPE_DEAUTH, - (char *) &resp, 2, addr, 0); - - if (!resend || ap->num_sta <= 0) - return; - - mdelay(50); - } -} - - -static int ap_control_proc_show(struct seq_file *m, void *v) -{ - struct ap_data *ap = pde_data(file_inode(m->file)); - char *policy_txt; - struct mac_entry *entry; - - if (v == SEQ_START_TOKEN) { - switch (ap->mac_restrictions.policy) { - case MAC_POLICY_OPEN: - policy_txt = "open"; - break; - case MAC_POLICY_ALLOW: - policy_txt = "allow"; - break; - case MAC_POLICY_DENY: - policy_txt = "deny"; - break; - default: - policy_txt = "unknown"; - break; - } - seq_printf(m, "MAC policy: %s\n", policy_txt); - seq_printf(m, "MAC entries: %u\n", ap->mac_restrictions.entries); - seq_puts(m, "MAC list:\n"); - return 0; - } - - entry = v; - seq_printf(m, "%pM\n", entry->addr); - return 0; -} - -static void *ap_control_proc_start(struct seq_file *m, loff_t *_pos) -{ - struct ap_data *ap = pde_data(file_inode(m->file)); - spin_lock_bh(&ap->mac_restrictions.lock); - return seq_list_start_head(&ap->mac_restrictions.mac_list, *_pos); -} - -static void *ap_control_proc_next(struct seq_file *m, void *v, loff_t *_pos) -{ - struct ap_data *ap = pde_data(file_inode(m->file)); - return seq_list_next(v, &ap->mac_restrictions.mac_list, _pos); -} - -static void ap_control_proc_stop(struct seq_file *m, void *v) -{ - struct ap_data *ap = pde_data(file_inode(m->file)); - spin_unlock_bh(&ap->mac_restrictions.lock); -} - -static const struct seq_operations ap_control_proc_seqops = { - .start = ap_control_proc_start, - .next = ap_control_proc_next, - .stop = ap_control_proc_stop, - .show = ap_control_proc_show, -}; - -int ap_control_add_mac(struct mac_restrictions *mac_restrictions, u8 *mac) -{ - struct mac_entry *entry; - - entry = kmalloc(sizeof(struct mac_entry), GFP_KERNEL); - if (entry == NULL) - return -ENOMEM; - - memcpy(entry->addr, mac, ETH_ALEN); - - spin_lock_bh(&mac_restrictions->lock); - list_add_tail(&entry->list, &mac_restrictions->mac_list); - mac_restrictions->entries++; - spin_unlock_bh(&mac_restrictions->lock); - - return 0; -} - - -int ap_control_del_mac(struct mac_restrictions *mac_restrictions, u8 *mac) -{ - struct list_head *ptr; - struct mac_entry *entry; - - spin_lock_bh(&mac_restrictions->lock); - for (ptr = mac_restrictions->mac_list.next; - ptr != &mac_restrictions->mac_list; ptr = ptr->next) { - entry = list_entry(ptr, struct mac_entry, list); - - if (ether_addr_equal(entry->addr, mac)) { - list_del(ptr); - kfree(entry); - mac_restrictions->entries--; - spin_unlock_bh(&mac_restrictions->lock); - return 0; - } - } - spin_unlock_bh(&mac_restrictions->lock); - return -1; -} - - -static int ap_control_mac_deny(struct mac_restrictions *mac_restrictions, - u8 *mac) -{ - struct mac_entry *entry; - int found = 0; - - if (mac_restrictions->policy == MAC_POLICY_OPEN) - return 0; - - spin_lock_bh(&mac_restrictions->lock); - list_for_each_entry(entry, &mac_restrictions->mac_list, list) { - if (ether_addr_equal(entry->addr, mac)) { - found = 1; - break; - } - } - spin_unlock_bh(&mac_restrictions->lock); - - if (mac_restrictions->policy == MAC_POLICY_ALLOW) - return !found; - else - return found; -} - - -void ap_control_flush_macs(struct mac_restrictions *mac_restrictions) -{ - struct list_head *ptr, *n; - struct mac_entry *entry; - - if (mac_restrictions->entries == 0) - return; - - spin_lock_bh(&mac_restrictions->lock); - for (ptr = mac_restrictions->mac_list.next, n = ptr->next; - ptr != &mac_restrictions->mac_list; - ptr = n, n = ptr->next) { - entry = list_entry(ptr, struct mac_entry, list); - list_del(ptr); - kfree(entry); - } - mac_restrictions->entries = 0; - spin_unlock_bh(&mac_restrictions->lock); -} - - -int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, u8 *mac) -{ - struct sta_info *sta; - __le16 resp; - - spin_lock_bh(&ap->sta_table_lock); - sta = ap_get_sta(ap, mac); - if (sta) { - ap_sta_hash_del(ap, sta); - list_del(&sta->list); - } - spin_unlock_bh(&ap->sta_table_lock); - - if (!sta) - return -EINVAL; - - resp = cpu_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); - prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DEAUTH, - (char *) &resp, 2, sta->addr, 0); - - if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap) - hostap_event_expired_sta(dev, sta); - - ap_free_sta(ap, sta); - - return 0; -} - -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - -void ap_control_kickall(struct ap_data *ap) -{ - struct list_head *ptr, *n; - struct sta_info *sta; - - spin_lock_bh(&ap->sta_table_lock); - for (ptr = ap->sta_list.next, n = ptr->next; ptr != &ap->sta_list; - ptr = n, n = ptr->next) { - sta = list_entry(ptr, struct sta_info, list); - ap_sta_hash_del(ap, sta); - list_del(&sta->list); - if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) - hostap_event_expired_sta(sta->local->dev, sta); - ap_free_sta(ap, sta); - } - spin_unlock_bh(&ap->sta_table_lock); -} - - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - -static int prism2_ap_proc_show(struct seq_file *m, void *v) -{ - struct sta_info *sta = v; - int i; - - if (v == SEQ_START_TOKEN) { - seq_printf(m, "# BSSID CHAN SIGNAL NOISE RATE SSID FLAGS\n"); - return 0; - } - - if (!sta->ap) - return 0; - - seq_printf(m, "%pM %d %d %d %d '", - sta->addr, - sta->u.ap.channel, sta->last_rx_signal, - sta->last_rx_silence, sta->last_rx_rate); - - for (i = 0; i < sta->u.ap.ssid_len; i++) { - if (sta->u.ap.ssid[i] >= 32 && sta->u.ap.ssid[i] < 127) - seq_putc(m, sta->u.ap.ssid[i]); - else - seq_printf(m, "<%02x>", sta->u.ap.ssid[i]); - } - - seq_putc(m, '\''); - if (sta->capability & WLAN_CAPABILITY_ESS) - seq_puts(m, " [ESS]"); - if (sta->capability & WLAN_CAPABILITY_IBSS) - seq_puts(m, " [IBSS]"); - if (sta->capability & WLAN_CAPABILITY_PRIVACY) - seq_puts(m, " [WEP]"); - seq_putc(m, '\n'); - return 0; -} - -static void *prism2_ap_proc_start(struct seq_file *m, loff_t *_pos) -{ - struct ap_data *ap = pde_data(file_inode(m->file)); - spin_lock_bh(&ap->sta_table_lock); - return seq_list_start_head(&ap->sta_list, *_pos); -} - -static void *prism2_ap_proc_next(struct seq_file *m, void *v, loff_t *_pos) -{ - struct ap_data *ap = pde_data(file_inode(m->file)); - return seq_list_next(v, &ap->sta_list, _pos); -} - -static void prism2_ap_proc_stop(struct seq_file *m, void *v) -{ - struct ap_data *ap = pde_data(file_inode(m->file)); - spin_unlock_bh(&ap->sta_table_lock); -} - -static const struct seq_operations prism2_ap_proc_seqops = { - .start = prism2_ap_proc_start, - .next = prism2_ap_proc_next, - .stop = prism2_ap_proc_stop, - .show = prism2_ap_proc_show, -}; -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - -void hostap_check_sta_fw_version(struct ap_data *ap, int sta_fw_ver) -{ - if (!ap) - return; - - if (sta_fw_ver == PRISM2_FW_VER(0,8,0)) { - PDEBUG(DEBUG_AP, "Using data::nullfunc ACK workaround - " - "firmware upgrade recommended\n"); - ap->nullfunc_ack = 1; - } else - ap->nullfunc_ack = 0; - - if (sta_fw_ver == PRISM2_FW_VER(1,4,2)) { - printk(KERN_WARNING "%s: Warning: secondary station firmware " - "version 1.4.2 does not seem to work in Host AP mode\n", - ap->local->dev->name); - } -} - - -/* Called only as a tasklet (software IRQ) */ -static void hostap_ap_tx_cb(struct sk_buff *skb, int ok, void *data) -{ - struct ap_data *ap = data; - struct ieee80211_hdr *hdr; - - if (!ap->local->hostapd || !ap->local->apdev) { - dev_kfree_skb(skb); - return; - } - - /* Pass the TX callback frame to the hostapd; use 802.11 header version - * 1 to indicate failure (no ACK) and 2 success (frame ACKed) */ - - hdr = (struct ieee80211_hdr *) skb->data; - hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_VERS); - hdr->frame_control |= cpu_to_le16(ok ? BIT(1) : BIT(0)); - - skb->dev = ap->local->apdev; - skb_pull(skb, hostap_80211_get_hdrlen(hdr->frame_control)); - skb->pkt_type = PACKET_OTHERHOST; - skb->protocol = cpu_to_be16(ETH_P_802_2); - memset(skb->cb, 0, sizeof(skb->cb)); - netif_rx(skb); -} - - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT -/* Called only as a tasklet (software IRQ) */ -static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data) -{ - struct ap_data *ap = data; - struct net_device *dev = ap->local->dev; - struct ieee80211_hdr *hdr; - u16 auth_alg, auth_transaction, status; - __le16 *pos; - struct sta_info *sta = NULL; - char *txt = NULL; - - if (ap->local->hostapd) { - dev_kfree_skb(skb); - return; - } - - hdr = (struct ieee80211_hdr *) skb->data; - if (!ieee80211_is_auth(hdr->frame_control) || - skb->len < IEEE80211_MGMT_HDR_LEN + 6) { - printk(KERN_DEBUG "%s: hostap_ap_tx_cb_auth received invalid " - "frame\n", dev->name); - dev_kfree_skb(skb); - return; - } - - pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); - auth_alg = le16_to_cpu(*pos++); - auth_transaction = le16_to_cpu(*pos++); - status = le16_to_cpu(*pos++); - - if (!ok) { - txt = "frame was not ACKed"; - goto done; - } - - spin_lock(&ap->sta_table_lock); - sta = ap_get_sta(ap, hdr->addr1); - if (sta) - atomic_inc(&sta->users); - spin_unlock(&ap->sta_table_lock); - - if (!sta) { - txt = "STA not found"; - goto done; - } - - if (status == WLAN_STATUS_SUCCESS && - ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) || - (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) { - txt = "STA authenticated"; - sta->flags |= WLAN_STA_AUTH; - sta->last_auth = jiffies; - } else if (status != WLAN_STATUS_SUCCESS) - txt = "authentication failed"; - - done: - if (sta) - atomic_dec(&sta->users); - if (txt) { - PDEBUG(DEBUG_AP, "%s: %pM auth_cb - alg=%d " - "trans#=%d status=%d - %s\n", - dev->name, hdr->addr1, - auth_alg, auth_transaction, status, txt); - } - dev_kfree_skb(skb); -} - - -/* Called only as a tasklet (software IRQ) */ -static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data) -{ - struct ap_data *ap = data; - struct net_device *dev = ap->local->dev; - struct ieee80211_hdr *hdr; - u16 status; - __le16 *pos; - struct sta_info *sta = NULL; - char *txt = NULL; - - if (ap->local->hostapd) { - dev_kfree_skb(skb); - return; - } - - hdr = (struct ieee80211_hdr *) skb->data; - if ((!ieee80211_is_assoc_resp(hdr->frame_control) && - !ieee80211_is_reassoc_resp(hdr->frame_control)) || - skb->len < IEEE80211_MGMT_HDR_LEN + 4) { - printk(KERN_DEBUG "%s: hostap_ap_tx_cb_assoc received invalid " - "frame\n", dev->name); - dev_kfree_skb(skb); - return; - } - - if (!ok) { - txt = "frame was not ACKed"; - goto done; - } - - spin_lock(&ap->sta_table_lock); - sta = ap_get_sta(ap, hdr->addr1); - if (sta) - atomic_inc(&sta->users); - spin_unlock(&ap->sta_table_lock); - - if (!sta) { - txt = "STA not found"; - goto done; - } - - pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); - pos++; - status = le16_to_cpu(*pos++); - if (status == WLAN_STATUS_SUCCESS) { - if (!(sta->flags & WLAN_STA_ASSOC)) - hostap_event_new_sta(dev, sta); - txt = "STA associated"; - sta->flags |= WLAN_STA_ASSOC; - sta->last_assoc = jiffies; - } else - txt = "association failed"; - - done: - if (sta) - atomic_dec(&sta->users); - if (txt) { - PDEBUG(DEBUG_AP, "%s: %pM assoc_cb - %s\n", - dev->name, hdr->addr1, txt); - } - dev_kfree_skb(skb); -} - -/* Called only as a tasklet (software IRQ); TX callback for poll frames used - * in verifying whether the STA is still present. */ -static void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data) -{ - struct ap_data *ap = data; - struct ieee80211_hdr *hdr; - struct sta_info *sta; - - if (skb->len < 24) - goto fail; - hdr = (struct ieee80211_hdr *) skb->data; - if (ok) { - spin_lock(&ap->sta_table_lock); - sta = ap_get_sta(ap, hdr->addr1); - if (sta) - sta->flags &= ~WLAN_STA_PENDING_POLL; - spin_unlock(&ap->sta_table_lock); - } else { - PDEBUG(DEBUG_AP, - "%s: STA %pM did not ACK activity poll frame\n", - ap->local->dev->name, hdr->addr1); - } - - fail: - dev_kfree_skb(skb); -} -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - -void hostap_init_data(local_info_t *local) -{ - struct ap_data *ap = local->ap; - - if (ap == NULL) { - printk(KERN_WARNING "hostap_init_data: ap == NULL\n"); - return; - } - memset(ap, 0, sizeof(struct ap_data)); - ap->local = local; - - ap->ap_policy = GET_INT_PARM(other_ap_policy, local->card_idx); - ap->bridge_packets = GET_INT_PARM(ap_bridge_packets, local->card_idx); - ap->max_inactivity = - GET_INT_PARM(ap_max_inactivity, local->card_idx) * HZ; - ap->autom_ap_wds = GET_INT_PARM(autom_ap_wds, local->card_idx); - - spin_lock_init(&ap->sta_table_lock); - INIT_LIST_HEAD(&ap->sta_list); - - /* Initialize task queue structure for AP management */ - INIT_WORK(&local->ap->add_sta_proc_queue, handle_add_proc_queue); - - ap->tx_callback_idx = - hostap_tx_callback_register(local, hostap_ap_tx_cb, ap); - if (ap->tx_callback_idx == 0) - printk(KERN_WARNING "%s: failed to register TX callback for " - "AP\n", local->dev->name); -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - INIT_WORK(&local->ap->wds_oper_queue, handle_wds_oper_queue); - - ap->tx_callback_auth = - hostap_tx_callback_register(local, hostap_ap_tx_cb_auth, ap); - ap->tx_callback_assoc = - hostap_tx_callback_register(local, hostap_ap_tx_cb_assoc, ap); - ap->tx_callback_poll = - hostap_tx_callback_register(local, hostap_ap_tx_cb_poll, ap); - if (ap->tx_callback_auth == 0 || ap->tx_callback_assoc == 0 || - ap->tx_callback_poll == 0) - printk(KERN_WARNING "%s: failed to register TX callback for " - "AP\n", local->dev->name); - - spin_lock_init(&ap->mac_restrictions.lock); - INIT_LIST_HEAD(&ap->mac_restrictions.mac_list); -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - ap->initialized = 1; -} - - -void hostap_init_ap_proc(local_info_t *local) -{ - struct ap_data *ap = local->ap; - - ap->proc = local->proc; - if (ap->proc == NULL) - return; - -#ifndef PRISM2_NO_PROCFS_DEBUG - proc_create_single_data("ap_debug", 0, ap->proc, ap_debug_proc_show, ap); -#endif /* PRISM2_NO_PROCFS_DEBUG */ - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - proc_create_seq_data("ap_control", 0, ap->proc, &ap_control_proc_seqops, - ap); - proc_create_seq_data("ap", 0, ap->proc, &prism2_ap_proc_seqops, ap); -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - -} - - -void hostap_free_data(struct ap_data *ap) -{ - struct sta_info *n, *sta; - - if (ap == NULL || !ap->initialized) { - printk(KERN_DEBUG "hostap_free_data: ap has not yet been " - "initialized - skip resource freeing\n"); - return; - } - - flush_work(&ap->add_sta_proc_queue); - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - flush_work(&ap->wds_oper_queue); - if (ap->crypt) - ap->crypt->deinit(ap->crypt_priv); - ap->crypt = ap->crypt_priv = NULL; -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - list_for_each_entry_safe(sta, n, &ap->sta_list, list) { - ap_sta_hash_del(ap, sta); - list_del(&sta->list); - if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) - hostap_event_expired_sta(sta->local->dev, sta); - ap_free_sta(ap, sta); - } - -#ifndef PRISM2_NO_PROCFS_DEBUG - if (ap->proc != NULL) { - remove_proc_entry("ap_debug", ap->proc); - } -#endif /* PRISM2_NO_PROCFS_DEBUG */ - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - if (ap->proc != NULL) { - remove_proc_entry("ap", ap->proc); - remove_proc_entry("ap_control", ap->proc); - } - ap_control_flush_macs(&ap->mac_restrictions); -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - ap->initialized = 0; -} - - -/* caller should have mutex for AP STA list handling */ -static struct sta_info* ap_get_sta(struct ap_data *ap, u8 *sta) -{ - struct sta_info *s; - - s = ap->sta_hash[STA_HASH(sta)]; - while (s != NULL && !ether_addr_equal(s->addr, sta)) - s = s->hnext; - return s; -} - - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - -/* Called from timer handler and from scheduled AP queue handlers */ -static void prism2_send_mgmt(struct net_device *dev, - u16 type_subtype, char *body, - int body_len, u8 *addr, u16 tx_cb_idx) -{ - struct hostap_interface *iface; - local_info_t *local; - struct ieee80211_hdr *hdr; - u16 fc; - struct sk_buff *skb; - struct hostap_skb_tx_data *meta; - int hdrlen; - - iface = netdev_priv(dev); - local = iface->local; - dev = local->dev; /* always use master radio device */ - iface = netdev_priv(dev); - - if (!(dev->flags & IFF_UP)) { - PDEBUG(DEBUG_AP, "%s: prism2_send_mgmt - device is not UP - " - "cannot send frame\n", dev->name); - return; - } - - skb = dev_alloc_skb(sizeof(*hdr) + body_len); - if (skb == NULL) { - PDEBUG(DEBUG_AP, "%s: prism2_send_mgmt failed to allocate " - "skb\n", dev->name); - return; - } - - fc = type_subtype; - hdrlen = hostap_80211_get_hdrlen(cpu_to_le16(type_subtype)); - hdr = skb_put_zero(skb, hdrlen); - if (body) - skb_put_data(skb, body, body_len); - - /* FIX: ctrl::ack sending used special HFA384X_TX_CTRL_802_11 - * tx_control instead of using local->tx_control */ - - - memcpy(hdr->addr1, addr, ETH_ALEN); /* DA / RA */ - if (ieee80211_is_data(hdr->frame_control)) { - fc |= IEEE80211_FCTL_FROMDS; - memcpy(hdr->addr2, dev->dev_addr, ETH_ALEN); /* BSSID */ - memcpy(hdr->addr3, dev->dev_addr, ETH_ALEN); /* SA */ - } else if (ieee80211_is_ctl(hdr->frame_control)) { - /* control:ACK does not have addr2 or addr3 */ - eth_zero_addr(hdr->addr2); - eth_zero_addr(hdr->addr3); - } else { - memcpy(hdr->addr2, dev->dev_addr, ETH_ALEN); /* SA */ - memcpy(hdr->addr3, dev->dev_addr, ETH_ALEN); /* BSSID */ - } - - hdr->frame_control = cpu_to_le16(fc); - - meta = (struct hostap_skb_tx_data *) skb->cb; - memset(meta, 0, sizeof(*meta)); - meta->magic = HOSTAP_SKB_TX_DATA_MAGIC; - meta->iface = iface; - meta->tx_cb_idx = tx_cb_idx; - - skb->dev = dev; - skb_reset_mac_header(skb); - skb_reset_network_header(skb); - dev_queue_xmit(skb); -} -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - -#ifdef CONFIG_PROC_FS -static int prism2_sta_proc_show(struct seq_file *m, void *v) -{ - struct sta_info *sta = m->private; - int i; - - /* FIX: possible race condition.. the STA data could have just expired, - * but proc entry was still here so that the read could have started; - * some locking should be done here.. */ - - seq_printf(m, - "%s=%pM\nusers=%d\naid=%d\n" - "flags=0x%04x%s%s%s%s%s%s%s\n" - "capability=0x%02x\nlisten_interval=%d\nsupported_rates=", - sta->ap ? "AP" : "STA", - sta->addr, atomic_read(&sta->users), sta->aid, - sta->flags, - sta->flags & WLAN_STA_AUTH ? " AUTH" : "", - sta->flags & WLAN_STA_ASSOC ? " ASSOC" : "", - sta->flags & WLAN_STA_PS ? " PS" : "", - sta->flags & WLAN_STA_TIM ? " TIM" : "", - sta->flags & WLAN_STA_PERM ? " PERM" : "", - sta->flags & WLAN_STA_AUTHORIZED ? " AUTHORIZED" : "", - sta->flags & WLAN_STA_PENDING_POLL ? " POLL" : "", - sta->capability, sta->listen_interval); - /* supported_rates: 500 kbit/s units with msb ignored */ - for (i = 0; i < sizeof(sta->supported_rates); i++) - if (sta->supported_rates[i] != 0) - seq_printf(m, "%d%sMbps ", - (sta->supported_rates[i] & 0x7f) / 2, - sta->supported_rates[i] & 1 ? ".5" : ""); - seq_printf(m, - "\njiffies=%lu\nlast_auth=%lu\nlast_assoc=%lu\n" - "last_rx=%lu\nlast_tx=%lu\nrx_packets=%lu\n" - "tx_packets=%lu\n" - "rx_bytes=%lu\ntx_bytes=%lu\nbuffer_count=%d\n" - "last_rx: silence=%d dBm signal=%d dBm rate=%d%s Mbps\n" - "tx_rate=%d\ntx[1M]=%d\ntx[2M]=%d\ntx[5.5M]=%d\n" - "tx[11M]=%d\n" - "rx[1M]=%d\nrx[2M]=%d\nrx[5.5M]=%d\nrx[11M]=%d\n", - jiffies, sta->last_auth, sta->last_assoc, sta->last_rx, - sta->last_tx, - sta->rx_packets, sta->tx_packets, sta->rx_bytes, - sta->tx_bytes, skb_queue_len(&sta->tx_buf), - sta->last_rx_silence, - sta->last_rx_signal, sta->last_rx_rate / 10, - sta->last_rx_rate % 10 ? ".5" : "", - sta->tx_rate, sta->tx_count[0], sta->tx_count[1], - sta->tx_count[2], sta->tx_count[3], sta->rx_count[0], - sta->rx_count[1], sta->rx_count[2], sta->rx_count[3]); - if (sta->crypt && sta->crypt->ops && sta->crypt->ops->print_stats) - sta->crypt->ops->print_stats(m, sta->crypt->priv); -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - if (sta->ap) { - if (sta->u.ap.channel >= 0) - seq_printf(m, "channel=%d\n", sta->u.ap.channel); - seq_puts(m, "ssid="); - for (i = 0; i < sta->u.ap.ssid_len; i++) { - if (sta->u.ap.ssid[i] >= 32 && sta->u.ap.ssid[i] < 127) - seq_putc(m, sta->u.ap.ssid[i]); - else - seq_printf(m, "<%02x>", sta->u.ap.ssid[i]); - } - seq_putc(m, '\n'); - } -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - return 0; -} -#endif - -static void handle_add_proc_queue(struct work_struct *work) -{ - struct ap_data *ap = container_of(work, struct ap_data, - add_sta_proc_queue); - struct sta_info *sta; - char name[20]; - struct add_sta_proc_data *entry, *prev; - - entry = ap->add_sta_proc_entries; - ap->add_sta_proc_entries = NULL; - - while (entry) { - spin_lock_bh(&ap->sta_table_lock); - sta = ap_get_sta(ap, entry->addr); - if (sta) - atomic_inc(&sta->users); - spin_unlock_bh(&ap->sta_table_lock); - - if (sta) { - sprintf(name, "%pM", sta->addr); - sta->proc = proc_create_single_data( - name, 0, ap->proc, - prism2_sta_proc_show, sta); - - atomic_dec(&sta->users); - } - - prev = entry; - entry = entry->next; - kfree(prev); - } -} - - -static struct sta_info * ap_add_sta(struct ap_data *ap, u8 *addr) -{ - struct sta_info *sta; - - sta = kzalloc(sizeof(struct sta_info), GFP_ATOMIC); - if (sta == NULL) { - PDEBUG(DEBUG_AP, "AP: kmalloc failed\n"); - return NULL; - } - - /* initialize STA info data */ - sta->local = ap->local; - skb_queue_head_init(&sta->tx_buf); - memcpy(sta->addr, addr, ETH_ALEN); - - atomic_inc(&sta->users); - spin_lock_bh(&ap->sta_table_lock); - list_add(&sta->list, &ap->sta_list); - ap->num_sta++; - ap_sta_hash_add(ap, sta); - spin_unlock_bh(&ap->sta_table_lock); - - if (ap->proc) { - struct add_sta_proc_data *entry; - /* schedule a non-interrupt context process to add a procfs - * entry for the STA since procfs code use GFP_KERNEL */ - entry = kmalloc(sizeof(*entry), GFP_ATOMIC); - if (entry) { - memcpy(entry->addr, sta->addr, ETH_ALEN); - entry->next = ap->add_sta_proc_entries; - ap->add_sta_proc_entries = entry; - schedule_work(&ap->add_sta_proc_queue); - } else - printk(KERN_DEBUG "Failed to add STA proc data\n"); - } - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - timer_setup(&sta->timer, ap_handle_timer, 0); - sta->timer.expires = jiffies + ap->max_inactivity; - if (!ap->local->hostapd) - add_timer(&sta->timer); -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - return sta; -} - - -static int ap_tx_rate_ok(int rateidx, struct sta_info *sta, - local_info_t *local) -{ - if (rateidx > sta->tx_max_rate || - !(sta->tx_supp_rates & (1 << rateidx))) - return 0; - - if (local->tx_rate_control != 0 && - !(local->tx_rate_control & (1 << rateidx))) - return 0; - - return 1; -} - - -static void prism2_check_tx_rates(struct sta_info *sta) -{ - int i; - - sta->tx_supp_rates = 0; - for (i = 0; i < sizeof(sta->supported_rates); i++) { - if ((sta->supported_rates[i] & 0x7f) == 2) - sta->tx_supp_rates |= WLAN_RATE_1M; - if ((sta->supported_rates[i] & 0x7f) == 4) - sta->tx_supp_rates |= WLAN_RATE_2M; - if ((sta->supported_rates[i] & 0x7f) == 11) - sta->tx_supp_rates |= WLAN_RATE_5M5; - if ((sta->supported_rates[i] & 0x7f) == 22) - sta->tx_supp_rates |= WLAN_RATE_11M; - } - sta->tx_max_rate = sta->tx_rate = sta->tx_rate_idx = 0; - if (sta->tx_supp_rates & WLAN_RATE_1M) { - sta->tx_max_rate = 0; - if (ap_tx_rate_ok(0, sta, sta->local)) { - sta->tx_rate = 10; - sta->tx_rate_idx = 0; - } - } - if (sta->tx_supp_rates & WLAN_RATE_2M) { - sta->tx_max_rate = 1; - if (ap_tx_rate_ok(1, sta, sta->local)) { - sta->tx_rate = 20; - sta->tx_rate_idx = 1; - } - } - if (sta->tx_supp_rates & WLAN_RATE_5M5) { - sta->tx_max_rate = 2; - if (ap_tx_rate_ok(2, sta, sta->local)) { - sta->tx_rate = 55; - sta->tx_rate_idx = 2; - } - } - if (sta->tx_supp_rates & WLAN_RATE_11M) { - sta->tx_max_rate = 3; - if (ap_tx_rate_ok(3, sta, sta->local)) { - sta->tx_rate = 110; - sta->tx_rate_idx = 3; - } - } -} - - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - -static void ap_crypt_init(struct ap_data *ap) -{ - ap->crypt = lib80211_get_crypto_ops("WEP"); - - if (ap->crypt) { - if (ap->crypt->init) { - ap->crypt_priv = ap->crypt->init(0); - if (ap->crypt_priv == NULL) - ap->crypt = NULL; - else { - u8 key[WEP_KEY_LEN]; - get_random_bytes(key, WEP_KEY_LEN); - ap->crypt->set_key(key, WEP_KEY_LEN, NULL, - ap->crypt_priv); - } - } - } - - if (ap->crypt == NULL) { - printk(KERN_WARNING "AP could not initialize WEP: load module " - "lib80211_crypt_wep.ko\n"); - } -} - - -/* Generate challenge data for shared key authentication. IEEE 802.11 specifies - * that WEP algorithm is used for generating challenge. This should be unique, - * but otherwise there is not really need for randomness etc. Initialize WEP - * with pseudo random key and then use increasing IV to get unique challenge - * streams. - * - * Called only as a scheduled task for pending AP frames. - */ -static char * ap_auth_make_challenge(struct ap_data *ap) -{ - char *tmpbuf; - struct sk_buff *skb; - - if (ap->crypt == NULL) { - ap_crypt_init(ap); - if (ap->crypt == NULL) - return NULL; - } - - tmpbuf = kmalloc(WLAN_AUTH_CHALLENGE_LEN, GFP_ATOMIC); - if (tmpbuf == NULL) { - PDEBUG(DEBUG_AP, "AP: kmalloc failed for challenge\n"); - return NULL; - } - - skb = dev_alloc_skb(WLAN_AUTH_CHALLENGE_LEN + - ap->crypt->extra_mpdu_prefix_len + - ap->crypt->extra_mpdu_postfix_len); - if (skb == NULL) { - kfree(tmpbuf); - return NULL; - } - - skb_reserve(skb, ap->crypt->extra_mpdu_prefix_len); - skb_put_zero(skb, WLAN_AUTH_CHALLENGE_LEN); - if (ap->crypt->encrypt_mpdu(skb, 0, ap->crypt_priv)) { - dev_kfree_skb(skb); - kfree(tmpbuf); - return NULL; - } - - skb_copy_from_linear_data_offset(skb, ap->crypt->extra_mpdu_prefix_len, - tmpbuf, WLAN_AUTH_CHALLENGE_LEN); - dev_kfree_skb(skb); - - return tmpbuf; -} - - -/* Called only as a scheduled task for pending AP frames. */ -static void handle_authen(local_info_t *local, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats) -{ - struct net_device *dev = local->dev; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - size_t hdrlen; - struct ap_data *ap = local->ap; - char body[8 + WLAN_AUTH_CHALLENGE_LEN], *challenge = NULL; - int len, olen; - u16 auth_alg, auth_transaction, status_code; - __le16 *pos; - u16 resp = WLAN_STATUS_SUCCESS; - struct sta_info *sta = NULL; - struct lib80211_crypt_data *crypt; - char *txt = ""; - - len = skb->len - IEEE80211_MGMT_HDR_LEN; - - hdrlen = hostap_80211_get_hdrlen(hdr->frame_control); - - if (len < 6) { - PDEBUG(DEBUG_AP, "%s: handle_authen - too short payload " - "(len=%d) from %pM\n", dev->name, len, hdr->addr2); - return; - } - - spin_lock_bh(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr2); - if (sta) - atomic_inc(&sta->users); - spin_unlock_bh(&local->ap->sta_table_lock); - - if (sta && sta->crypt) - crypt = sta->crypt; - else { - int idx = 0; - if (skb->len >= hdrlen + 3) - idx = skb->data[hdrlen + 3] >> 6; - crypt = local->crypt_info.crypt[idx]; - } - - pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); - auth_alg = __le16_to_cpu(*pos); - pos++; - auth_transaction = __le16_to_cpu(*pos); - pos++; - status_code = __le16_to_cpu(*pos); - pos++; - - if (ether_addr_equal(dev->dev_addr, hdr->addr2) || - ap_control_mac_deny(&ap->mac_restrictions, hdr->addr2)) { - txt = "authentication denied"; - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto fail; - } - - if (((local->auth_algs & PRISM2_AUTH_OPEN) && - auth_alg == WLAN_AUTH_OPEN) || - ((local->auth_algs & PRISM2_AUTH_SHARED_KEY) && - crypt && auth_alg == WLAN_AUTH_SHARED_KEY)) { - } else { - txt = "unsupported algorithm"; - resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; - goto fail; - } - - if (len >= 8) { - u8 *u = (u8 *) pos; - if (*u == WLAN_EID_CHALLENGE) { - if (*(u + 1) != WLAN_AUTH_CHALLENGE_LEN) { - txt = "invalid challenge len"; - resp = WLAN_STATUS_CHALLENGE_FAIL; - goto fail; - } - if (len - 8 < WLAN_AUTH_CHALLENGE_LEN) { - txt = "challenge underflow"; - resp = WLAN_STATUS_CHALLENGE_FAIL; - goto fail; - } - challenge = (char *) (u + 2); - } - } - - if (sta && sta->ap) { - if (time_after(jiffies, sta->u.ap.last_beacon + - (10 * sta->listen_interval * HZ) / 1024)) { - PDEBUG(DEBUG_AP, "%s: no beacons received for a while," - " assuming AP %pM is now STA\n", - dev->name, sta->addr); - sta->ap = 0; - sta->flags = 0; - sta->u.sta.challenge = NULL; - } else { - txt = "AP trying to authenticate?"; - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto fail; - } - } - - if ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1) || - (auth_alg == WLAN_AUTH_SHARED_KEY && - (auth_transaction == 1 || - (auth_transaction == 3 && sta != NULL && - sta->u.sta.challenge != NULL)))) { - } else { - txt = "unknown authentication transaction number"; - resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; - goto fail; - } - - if (sta == NULL) { - txt = "new STA"; - - if (local->ap->num_sta >= MAX_STA_COUNT) { - /* FIX: might try to remove some old STAs first? */ - txt = "no more room for new STAs"; - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto fail; - } - - sta = ap_add_sta(local->ap, hdr->addr2); - if (sta == NULL) { - txt = "ap_add_sta failed"; - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto fail; - } - } - - switch (auth_alg) { - case WLAN_AUTH_OPEN: - txt = "authOK"; - /* IEEE 802.11 standard is not completely clear about - * whether STA is considered authenticated after - * authentication OK frame has been send or after it - * has been ACKed. In order to reduce interoperability - * issues, mark the STA authenticated before ACK. */ - sta->flags |= WLAN_STA_AUTH; - break; - - case WLAN_AUTH_SHARED_KEY: - if (auth_transaction == 1) { - if (sta->u.sta.challenge == NULL) { - sta->u.sta.challenge = - ap_auth_make_challenge(local->ap); - if (sta->u.sta.challenge == NULL) { - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto fail; - } - } - } else { - if (sta->u.sta.challenge == NULL || - challenge == NULL || - memcmp(sta->u.sta.challenge, challenge, - WLAN_AUTH_CHALLENGE_LEN) != 0 || - !ieee80211_has_protected(hdr->frame_control)) { - txt = "challenge response incorrect"; - resp = WLAN_STATUS_CHALLENGE_FAIL; - goto fail; - } - - txt = "challenge OK - authOK"; - /* IEEE 802.11 standard is not completely clear about - * whether STA is considered authenticated after - * authentication OK frame has been send or after it - * has been ACKed. In order to reduce interoperability - * issues, mark the STA authenticated before ACK. */ - sta->flags |= WLAN_STA_AUTH; - kfree(sta->u.sta.challenge); - sta->u.sta.challenge = NULL; - } - break; - } - - fail: - pos = (__le16 *) body; - *pos = cpu_to_le16(auth_alg); - pos++; - *pos = cpu_to_le16(auth_transaction + 1); - pos++; - *pos = cpu_to_le16(resp); /* status_code */ - pos++; - olen = 6; - - if (resp == WLAN_STATUS_SUCCESS && sta != NULL && - sta->u.sta.challenge != NULL && - auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 1) { - u8 *tmp = (u8 *) pos; - *tmp++ = WLAN_EID_CHALLENGE; - *tmp++ = WLAN_AUTH_CHALLENGE_LEN; - pos++; - memcpy(pos, sta->u.sta.challenge, WLAN_AUTH_CHALLENGE_LEN); - olen += 2 + WLAN_AUTH_CHALLENGE_LEN; - } - - prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH, - body, olen, hdr->addr2, ap->tx_callback_auth); - - if (sta) { - sta->last_rx = jiffies; - atomic_dec(&sta->users); - } - - if (resp) { - PDEBUG(DEBUG_AP, "%s: %pM auth (alg=%d " - "trans#=%d stat=%d len=%d fc=%04x) ==> %d (%s)\n", - dev->name, hdr->addr2, - auth_alg, auth_transaction, status_code, len, - le16_to_cpu(hdr->frame_control), resp, txt); - } -} - - -/* Called only as a scheduled task for pending AP frames. */ -static void handle_assoc(local_info_t *local, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats, int reassoc) -{ - struct net_device *dev = local->dev; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - char body[12], *p, *lpos; - int len, left; - __le16 *pos; - u16 resp = WLAN_STATUS_SUCCESS; - struct sta_info *sta = NULL; - int send_deauth = 0; - char __always_unused *txt = ""; - u8 prev_ap[ETH_ALEN]; - - left = len = skb->len - IEEE80211_MGMT_HDR_LEN; - - if (len < (reassoc ? 10 : 4)) { - PDEBUG(DEBUG_AP, "%s: handle_assoc - too short payload " - "(len=%d, reassoc=%d) from %pM\n", - dev->name, len, reassoc, hdr->addr2); - return; - } - - spin_lock_bh(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr2); - if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) { - spin_unlock_bh(&local->ap->sta_table_lock); - txt = "trying to associate before authentication"; - send_deauth = 1; - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - sta = NULL; /* do not decrement sta->users */ - goto fail; - } - atomic_inc(&sta->users); - spin_unlock_bh(&local->ap->sta_table_lock); - - pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); - sta->capability = __le16_to_cpu(*pos); - pos++; left -= 2; - sta->listen_interval = __le16_to_cpu(*pos); - pos++; left -= 2; - - if (reassoc) { - memcpy(prev_ap, pos, ETH_ALEN); - pos++; pos++; pos++; left -= 6; - } else - eth_zero_addr(prev_ap); - - if (left >= 2) { - unsigned int ileft; - unsigned char *u = (unsigned char *) pos; - - if (*u == WLAN_EID_SSID) { - u++; left--; - ileft = *u; - u++; left--; - - if (ileft > left || ileft > MAX_SSID_LEN) { - txt = "SSID overflow"; - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto fail; - } - - if (ileft != strlen(local->essid) || - memcmp(local->essid, u, ileft) != 0) { - txt = "not our SSID"; - resp = WLAN_STATUS_ASSOC_DENIED_UNSPEC; - goto fail; - } - - u += ileft; - left -= ileft; - } - - if (left >= 2 && *u == WLAN_EID_SUPP_RATES) { - u++; left--; - ileft = *u; - u++; left--; - - if (ileft > left || ileft == 0 || - ileft > WLAN_SUPP_RATES_MAX) { - txt = "SUPP_RATES len error"; - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto fail; - } - - memset(sta->supported_rates, 0, - sizeof(sta->supported_rates)); - memcpy(sta->supported_rates, u, ileft); - prism2_check_tx_rates(sta); - - u += ileft; - left -= ileft; - } - - if (left > 0) { - PDEBUG(DEBUG_AP, "%s: assoc from %pM" - " with extra data (%d bytes) [", - dev->name, hdr->addr2, left); - while (left > 0) { - PDEBUG2(DEBUG_AP, "<%02x>", *u); - u++; left--; - } - PDEBUG2(DEBUG_AP, "]\n"); - } - } else { - txt = "frame underflow"; - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto fail; - } - - /* get a unique AID */ - if (sta->aid > 0) - txt = "OK, old AID"; - else { - spin_lock_bh(&local->ap->sta_table_lock); - for (sta->aid = 1; sta->aid <= MAX_AID_TABLE_SIZE; sta->aid++) - if (local->ap->sta_aid[sta->aid - 1] == NULL) - break; - if (sta->aid > MAX_AID_TABLE_SIZE) { - sta->aid = 0; - spin_unlock_bh(&local->ap->sta_table_lock); - resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; - txt = "no room for more AIDs"; - } else { - local->ap->sta_aid[sta->aid - 1] = sta; - spin_unlock_bh(&local->ap->sta_table_lock); - txt = "OK, new AID"; - } - } - - fail: - pos = (__le16 *) body; - - if (send_deauth) { - *pos = cpu_to_le16(WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH); - pos++; - } else { - /* FIX: CF-Pollable and CF-PollReq should be set to match the - * values in beacons/probe responses */ - /* FIX: how about privacy and WEP? */ - /* capability */ - *pos = cpu_to_le16(WLAN_CAPABILITY_ESS); - pos++; - - /* status_code */ - *pos = cpu_to_le16(resp); - pos++; - - *pos = cpu_to_le16((sta && sta->aid > 0 ? sta->aid : 0) | - BIT(14) | BIT(15)); /* AID */ - pos++; - - /* Supported rates (Information element) */ - p = (char *) pos; - *p++ = WLAN_EID_SUPP_RATES; - lpos = p; - *p++ = 0; /* len */ - if (local->tx_rate_control & WLAN_RATE_1M) { - *p++ = local->basic_rates & WLAN_RATE_1M ? 0x82 : 0x02; - (*lpos)++; - } - if (local->tx_rate_control & WLAN_RATE_2M) { - *p++ = local->basic_rates & WLAN_RATE_2M ? 0x84 : 0x04; - (*lpos)++; - } - if (local->tx_rate_control & WLAN_RATE_5M5) { - *p++ = local->basic_rates & WLAN_RATE_5M5 ? - 0x8b : 0x0b; - (*lpos)++; - } - if (local->tx_rate_control & WLAN_RATE_11M) { - *p++ = local->basic_rates & WLAN_RATE_11M ? - 0x96 : 0x16; - (*lpos)++; - } - pos = (__le16 *) p; - } - - prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | - (send_deauth ? IEEE80211_STYPE_DEAUTH : - (reassoc ? IEEE80211_STYPE_REASSOC_RESP : - IEEE80211_STYPE_ASSOC_RESP)), - body, (u8 *) pos - (u8 *) body, - hdr->addr2, - send_deauth ? 0 : local->ap->tx_callback_assoc); - - if (sta) { - if (resp == WLAN_STATUS_SUCCESS) { - sta->last_rx = jiffies; - /* STA will be marked associated from TX callback, if - * AssocResp is ACKed */ - } - atomic_dec(&sta->users); - } - -#if 0 - PDEBUG(DEBUG_AP, "%s: %pM %sassoc (len=%d " - "prev_ap=%pM) => %d(%d) (%s)\n", - dev->name, - hdr->addr2, - reassoc ? "re" : "", len, - prev_ap, - resp, send_deauth, txt); -#endif -} - - -/* Called only as a scheduled task for pending AP frames. */ -static void handle_deauth(local_info_t *local, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats) -{ - struct net_device *dev = local->dev; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - char *body = (char *) (skb->data + IEEE80211_MGMT_HDR_LEN); - int len; - u16 reason_code; - __le16 *pos; - struct sta_info *sta = NULL; - - len = skb->len - IEEE80211_MGMT_HDR_LEN; - - if (len < 2) { - printk("handle_deauth - too short payload (len=%d)\n", len); - return; - } - - pos = (__le16 *) body; - reason_code = le16_to_cpu(*pos); - - PDEBUG(DEBUG_AP, "%s: deauthentication: %pM len=%d, " - "reason_code=%d\n", dev->name, hdr->addr2, - len, reason_code); - - spin_lock_bh(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr2); - if (sta != NULL) { - if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap) - hostap_event_expired_sta(local->dev, sta); - sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); - } - spin_unlock_bh(&local->ap->sta_table_lock); - if (sta == NULL) { - printk("%s: deauthentication from %pM, " - "reason_code=%d, but STA not authenticated\n", dev->name, - hdr->addr2, reason_code); - } -} - - -/* Called only as a scheduled task for pending AP frames. */ -static void handle_disassoc(local_info_t *local, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats) -{ - struct net_device *dev = local->dev; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - char *body = skb->data + IEEE80211_MGMT_HDR_LEN; - int len; - u16 reason_code; - __le16 *pos; - struct sta_info *sta = NULL; - - len = skb->len - IEEE80211_MGMT_HDR_LEN; - - if (len < 2) { - printk("handle_disassoc - too short payload (len=%d)\n", len); - return; - } - - pos = (__le16 *) body; - reason_code = le16_to_cpu(*pos); - - PDEBUG(DEBUG_AP, "%s: disassociation: %pM len=%d, " - "reason_code=%d\n", dev->name, hdr->addr2, - len, reason_code); - - spin_lock_bh(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr2); - if (sta != NULL) { - if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap) - hostap_event_expired_sta(local->dev, sta); - sta->flags &= ~WLAN_STA_ASSOC; - } - spin_unlock_bh(&local->ap->sta_table_lock); - if (sta == NULL) { - printk("%s: disassociation from %pM, " - "reason_code=%d, but STA not authenticated\n", - dev->name, hdr->addr2, reason_code); - } -} - - -/* Called only as a scheduled task for pending AP frames. */ -static void ap_handle_data_nullfunc(local_info_t *local, - struct ieee80211_hdr *hdr) -{ - struct net_device *dev = local->dev; - - /* some STA f/w's seem to require control::ACK frame for - * data::nullfunc, but at least Prism2 station f/w version 0.8.0 does - * not send this.. - * send control::ACK for the data::nullfunc */ - - printk(KERN_DEBUG "Sending control::ACK for data::nullfunc\n"); - prism2_send_mgmt(dev, IEEE80211_FTYPE_CTL | IEEE80211_STYPE_ACK, - NULL, 0, hdr->addr2, 0); -} - - -/* Called only as a scheduled task for pending AP frames. */ -static void ap_handle_dropped_data(local_info_t *local, - struct ieee80211_hdr *hdr) -{ - struct net_device *dev = local->dev; - struct sta_info *sta; - __le16 reason; - - spin_lock_bh(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr2); - if (sta) - atomic_inc(&sta->users); - spin_unlock_bh(&local->ap->sta_table_lock); - - if (sta != NULL && (sta->flags & WLAN_STA_ASSOC)) { - PDEBUG(DEBUG_AP, "ap_handle_dropped_data: STA is now okay?\n"); - atomic_dec(&sta->users); - return; - } - - reason = cpu_to_le16(WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); - prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | - ((sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) ? - IEEE80211_STYPE_DEAUTH : IEEE80211_STYPE_DISASSOC), - (char *) &reason, sizeof(reason), hdr->addr2, 0); - - if (sta) - atomic_dec(&sta->users); -} - -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - -/* Called only as a scheduled task for pending AP frames. */ -static void pspoll_send_buffered(local_info_t *local, struct sta_info *sta, - struct sk_buff *skb) -{ - struct hostap_skb_tx_data *meta; - - if (!(sta->flags & WLAN_STA_PS)) { - /* Station has moved to non-PS mode, so send all buffered - * frames using normal device queue. */ - dev_queue_xmit(skb); - return; - } - - /* add a flag for hostap_handle_sta_tx() to know that this skb should - * be passed through even though STA is using PS */ - meta = (struct hostap_skb_tx_data *) skb->cb; - meta->flags |= HOSTAP_TX_FLAGS_BUFFERED_FRAME; - if (!skb_queue_empty(&sta->tx_buf)) { - /* indicate to STA that more frames follow */ - meta->flags |= HOSTAP_TX_FLAGS_ADD_MOREDATA; - } - dev_queue_xmit(skb); -} - - -/* Called only as a scheduled task for pending AP frames. */ -static void handle_pspoll(local_info_t *local, - struct ieee80211_hdr *hdr, - struct hostap_80211_rx_status *rx_stats) -{ - struct net_device *dev = local->dev; - struct sta_info *sta; - u16 aid; - struct sk_buff *skb; - - PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=%pM, TA=%pM PWRMGT=%d\n", - hdr->addr1, hdr->addr2, !!ieee80211_has_pm(hdr->frame_control)); - - if (!ether_addr_equal(hdr->addr1, dev->dev_addr)) { - PDEBUG(DEBUG_AP, - "handle_pspoll - addr1(BSSID)=%pM not own MAC\n", - hdr->addr1); - return; - } - - aid = le16_to_cpu(hdr->duration_id); - if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) { - PDEBUG(DEBUG_PS, " PSPOLL and AID[15:14] not set\n"); - return; - } - aid &= ~(BIT(15) | BIT(14)); - if (aid == 0 || aid > MAX_AID_TABLE_SIZE) { - PDEBUG(DEBUG_PS, " invalid aid=%d\n", aid); - return; - } - PDEBUG(DEBUG_PS2, " aid=%d\n", aid); - - spin_lock_bh(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr2); - if (sta) - atomic_inc(&sta->users); - spin_unlock_bh(&local->ap->sta_table_lock); - - if (sta == NULL) { - PDEBUG(DEBUG_PS, " STA not found\n"); - return; - } - if (sta->aid != aid) { - PDEBUG(DEBUG_PS, " received aid=%i does not match with " - "assoc.aid=%d\n", aid, sta->aid); - return; - } - - /* FIX: todo: - * - add timeout for buffering (clear aid in TIM vector if buffer timed - * out (expiry time must be longer than ListenInterval for - * the corresponding STA; "8802-11: 11.2.1.9 AP aging function" - * - what to do, if buffered, pspolled, and sent frame is not ACKed by - * sta; store buffer for later use and leave TIM aid bit set? use - * TX event to check whether frame was ACKed? - */ - - while ((skb = skb_dequeue(&sta->tx_buf)) != NULL) { - /* send buffered frame .. */ - PDEBUG(DEBUG_PS2, "Sending buffered frame to STA after PS POLL" - " (buffer_count=%d)\n", skb_queue_len(&sta->tx_buf)); - - pspoll_send_buffered(local, sta, skb); - - if (sta->flags & WLAN_STA_PS) { - /* send only one buffered packet per PS Poll */ - /* FIX: should ignore further PS Polls until the - * buffered packet that was just sent is acknowledged - * (Tx or TxExc event) */ - break; - } - } - - if (skb_queue_empty(&sta->tx_buf)) { - /* try to clear aid from TIM */ - if (!(sta->flags & WLAN_STA_TIM)) - PDEBUG(DEBUG_PS2, "Re-unsetting TIM for aid %d\n", - aid); - hostap_set_tim(local, aid, 0); - sta->flags &= ~WLAN_STA_TIM; - } - - atomic_dec(&sta->users); -} - - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - -static void handle_wds_oper_queue(struct work_struct *work) -{ - struct ap_data *ap = container_of(work, struct ap_data, - wds_oper_queue); - local_info_t *local = ap->local; - struct wds_oper_data *entry, *prev; - - spin_lock_bh(&local->lock); - entry = local->ap->wds_oper_entries; - local->ap->wds_oper_entries = NULL; - spin_unlock_bh(&local->lock); - - while (entry) { - PDEBUG(DEBUG_AP, "%s: %s automatic WDS connection " - "to AP %pM\n", - local->dev->name, - entry->type == WDS_ADD ? "adding" : "removing", - entry->addr); - if (entry->type == WDS_ADD) - prism2_wds_add(local, entry->addr, 0); - else if (entry->type == WDS_DEL) - prism2_wds_del(local, entry->addr, 0, 1); - - prev = entry; - entry = entry->next; - kfree(prev); - } -} - - -/* Called only as a scheduled task for pending AP frames. */ -static void handle_beacon(local_info_t *local, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - char *body = skb->data + IEEE80211_MGMT_HDR_LEN; - int len, left; - u16 beacon_int, capability; - __le16 *pos; - char *ssid = NULL; - unsigned char *supp_rates = NULL; - int ssid_len = 0, supp_rates_len = 0; - struct sta_info *sta = NULL; - int new_sta = 0, channel = -1; - - len = skb->len - IEEE80211_MGMT_HDR_LEN; - - if (len < 8 + 2 + 2) { - printk(KERN_DEBUG "handle_beacon - too short payload " - "(len=%d)\n", len); - return; - } - - pos = (__le16 *) body; - left = len; - - /* Timestamp (8 octets) */ - pos += 4; left -= 8; - /* Beacon interval (2 octets) */ - beacon_int = le16_to_cpu(*pos); - pos++; left -= 2; - /* Capability information (2 octets) */ - capability = le16_to_cpu(*pos); - pos++; left -= 2; - - if (local->ap->ap_policy != AP_OTHER_AP_EVEN_IBSS && - capability & WLAN_CAPABILITY_IBSS) - return; - - if (left >= 2) { - unsigned int ileft; - unsigned char *u = (unsigned char *) pos; - - if (*u == WLAN_EID_SSID) { - u++; left--; - ileft = *u; - u++; left--; - - if (ileft > left || ileft > MAX_SSID_LEN) { - PDEBUG(DEBUG_AP, "SSID: overflow\n"); - return; - } - - if (local->ap->ap_policy == AP_OTHER_AP_SAME_SSID && - (ileft != strlen(local->essid) || - memcmp(local->essid, u, ileft) != 0)) { - /* not our SSID */ - return; - } - - ssid = u; - ssid_len = ileft; - - u += ileft; - left -= ileft; - } - - if (*u == WLAN_EID_SUPP_RATES) { - u++; left--; - ileft = *u; - u++; left--; - - if (ileft > left || ileft == 0 || ileft > 8) { - PDEBUG(DEBUG_AP, " - SUPP_RATES len error\n"); - return; - } - - supp_rates = u; - supp_rates_len = ileft; - - u += ileft; - left -= ileft; - } - - if (*u == WLAN_EID_DS_PARAMS) { - u++; left--; - ileft = *u; - u++; left--; - - if (ileft > left || ileft != 1) { - PDEBUG(DEBUG_AP, " - DS_PARAMS len error\n"); - return; - } - - channel = *u; - - u += ileft; - left -= ileft; - } - } - - spin_lock_bh(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr2); - if (sta != NULL) - atomic_inc(&sta->users); - spin_unlock_bh(&local->ap->sta_table_lock); - - if (sta == NULL) { - /* add new AP */ - new_sta = 1; - sta = ap_add_sta(local->ap, hdr->addr2); - if (sta == NULL) { - printk(KERN_INFO "prism2: kmalloc failed for AP " - "data structure\n"); - return; - } - hostap_event_new_sta(local->dev, sta); - - /* mark APs authentication and associated for pseudo ad-hoc - * style communication */ - sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; - - if (local->ap->autom_ap_wds) { - hostap_wds_link_oper(local, sta->addr, WDS_ADD); - } - } - - sta->ap = 1; - if (ssid) { - sta->u.ap.ssid_len = ssid_len; - memcpy(sta->u.ap.ssid, ssid, ssid_len); - sta->u.ap.ssid[ssid_len] = '\0'; - } else { - sta->u.ap.ssid_len = 0; - sta->u.ap.ssid[0] = '\0'; - } - sta->u.ap.channel = channel; - sta->rx_packets++; - sta->rx_bytes += len; - sta->u.ap.last_beacon = sta->last_rx = jiffies; - sta->capability = capability; - sta->listen_interval = beacon_int; - - atomic_dec(&sta->users); - - if (new_sta) { - memset(sta->supported_rates, 0, sizeof(sta->supported_rates)); - memcpy(sta->supported_rates, supp_rates, supp_rates_len); - prism2_check_tx_rates(sta); - } -} - -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - -/* Called only as a tasklet. */ -static void handle_ap_item(local_info_t *local, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats) -{ -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - struct net_device *dev = local->dev; -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - u16 fc, type, stype; - struct ieee80211_hdr *hdr; - - /* FIX: should give skb->len to handler functions and check that the - * buffer is long enough */ - hdr = (struct ieee80211_hdr *) skb->data; - fc = le16_to_cpu(hdr->frame_control); - type = fc & IEEE80211_FCTL_FTYPE; - stype = fc & IEEE80211_FCTL_STYPE; - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - if (!local->hostapd && type == IEEE80211_FTYPE_DATA) { - PDEBUG(DEBUG_AP, "handle_ap_item - data frame\n"); - - if (!(fc & IEEE80211_FCTL_TODS) || - (fc & IEEE80211_FCTL_FROMDS)) { - if (stype == IEEE80211_STYPE_NULLFUNC) { - /* no ToDS nullfunc seems to be used to check - * AP association; so send reject message to - * speed up re-association */ - ap_handle_dropped_data(local, hdr); - goto done; - } - PDEBUG(DEBUG_AP, " not ToDS frame (fc=0x%04x)\n", - fc); - goto done; - } - - if (!ether_addr_equal(hdr->addr1, dev->dev_addr)) { - PDEBUG(DEBUG_AP, "handle_ap_item - addr1(BSSID)=%pM" - " not own MAC\n", hdr->addr1); - goto done; - } - - if (local->ap->nullfunc_ack && - stype == IEEE80211_STYPE_NULLFUNC) - ap_handle_data_nullfunc(local, hdr); - else - ap_handle_dropped_data(local, hdr); - goto done; - } - - if (type == IEEE80211_FTYPE_MGMT && stype == IEEE80211_STYPE_BEACON) { - handle_beacon(local, skb, rx_stats); - goto done; - } -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - if (type == IEEE80211_FTYPE_CTL && stype == IEEE80211_STYPE_PSPOLL) { - handle_pspoll(local, hdr, rx_stats); - goto done; - } - - if (local->hostapd) { - PDEBUG(DEBUG_AP, "Unknown frame in AP queue: type=0x%02x " - "subtype=0x%02x\n", type, stype); - goto done; - } - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - if (type != IEEE80211_FTYPE_MGMT) { - PDEBUG(DEBUG_AP, "handle_ap_item - not a management frame?\n"); - goto done; - } - - if (!ether_addr_equal(hdr->addr1, dev->dev_addr)) { - PDEBUG(DEBUG_AP, "handle_ap_item - addr1(DA)=%pM" - " not own MAC\n", hdr->addr1); - goto done; - } - - if (!ether_addr_equal(hdr->addr3, dev->dev_addr)) { - PDEBUG(DEBUG_AP, "handle_ap_item - addr3(BSSID)=%pM" - " not own MAC\n", hdr->addr3); - goto done; - } - - switch (stype) { - case IEEE80211_STYPE_ASSOC_REQ: - handle_assoc(local, skb, rx_stats, 0); - break; - case IEEE80211_STYPE_ASSOC_RESP: - PDEBUG(DEBUG_AP, "==> ASSOC RESP (ignored)\n"); - break; - case IEEE80211_STYPE_REASSOC_REQ: - handle_assoc(local, skb, rx_stats, 1); - break; - case IEEE80211_STYPE_REASSOC_RESP: - PDEBUG(DEBUG_AP, "==> REASSOC RESP (ignored)\n"); - break; - case IEEE80211_STYPE_ATIM: - PDEBUG(DEBUG_AP, "==> ATIM (ignored)\n"); - break; - case IEEE80211_STYPE_DISASSOC: - handle_disassoc(local, skb, rx_stats); - break; - case IEEE80211_STYPE_AUTH: - handle_authen(local, skb, rx_stats); - break; - case IEEE80211_STYPE_DEAUTH: - handle_deauth(local, skb, rx_stats); - break; - default: - PDEBUG(DEBUG_AP, "Unknown mgmt frame subtype 0x%02x\n", - stype >> 4); - break; - } -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - done: - dev_kfree_skb(skb); -} - - -/* Called only as a tasklet (software IRQ) */ -void hostap_rx(struct net_device *dev, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats) -{ - struct hostap_interface *iface; - local_info_t *local; - struct ieee80211_hdr *hdr; - - iface = netdev_priv(dev); - local = iface->local; - - if (skb->len < 16) - goto drop; - - dev->stats.rx_packets++; - - hdr = (struct ieee80211_hdr *) skb->data; - - if (local->ap->ap_policy == AP_OTHER_AP_SKIP_ALL && - ieee80211_is_beacon(hdr->frame_control)) - goto drop; - - skb->protocol = cpu_to_be16(ETH_P_HOSTAP); - handle_ap_item(local, skb, rx_stats); - return; - - drop: - dev_kfree_skb(skb); -} - - -/* Called only as a tasklet (software IRQ) */ -static void schedule_packet_send(local_info_t *local, struct sta_info *sta) -{ - struct sk_buff *skb; - struct ieee80211_hdr *hdr; - struct hostap_80211_rx_status rx_stats; - - if (skb_queue_empty(&sta->tx_buf)) - return; - - skb = dev_alloc_skb(16); - if (skb == NULL) { - printk(KERN_DEBUG "%s: schedule_packet_send: skb alloc " - "failed\n", local->dev->name); - return; - } - - hdr = skb_put(skb, 16); - - /* Generate a fake pspoll frame to start packet delivery */ - hdr->frame_control = cpu_to_le16( - IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); - memcpy(hdr->addr1, local->dev->dev_addr, ETH_ALEN); - memcpy(hdr->addr2, sta->addr, ETH_ALEN); - hdr->duration_id = cpu_to_le16(sta->aid | BIT(15) | BIT(14)); - - PDEBUG(DEBUG_PS2, - "%s: Scheduling buffered packet delivery for STA %pM\n", - local->dev->name, sta->addr); - - skb->dev = local->dev; - - memset(&rx_stats, 0, sizeof(rx_stats)); - hostap_rx(local->dev, skb, &rx_stats); -} - - -int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[], - struct iw_quality qual[], int buf_size, - int aplist) -{ - struct ap_data *ap = local->ap; - struct list_head *ptr; - int count = 0; - - spin_lock_bh(&ap->sta_table_lock); - - for (ptr = ap->sta_list.next; ptr != NULL && ptr != &ap->sta_list; - ptr = ptr->next) { - struct sta_info *sta = (struct sta_info *) ptr; - - if (aplist && !sta->ap) - continue; - addr[count].sa_family = ARPHRD_ETHER; - memcpy(addr[count].sa_data, sta->addr, ETH_ALEN); - if (sta->last_rx_silence == 0) - qual[count].qual = sta->last_rx_signal < 27 ? - 0 : (sta->last_rx_signal - 27) * 92 / 127; - else - qual[count].qual = sta->last_rx_signal - - sta->last_rx_silence - 35; - qual[count].level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal); - qual[count].noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence); - qual[count].updated = sta->last_rx_updated; - - sta->last_rx_updated = IW_QUAL_DBM; - - count++; - if (count >= buf_size) - break; - } - spin_unlock_bh(&ap->sta_table_lock); - - return count; -} - - -/* Translate our list of Access Points & Stations to a card independent - * format that the Wireless Tools will understand - Jean II */ -int prism2_ap_translate_scan(struct net_device *dev, - struct iw_request_info *info, char *buffer) -{ - struct hostap_interface *iface; - local_info_t *local; - struct ap_data *ap; - struct list_head *ptr; - struct iw_event iwe; - char *current_ev = buffer; - char *end_buf = buffer + IW_SCAN_MAX_DATA; -#if !defined(PRISM2_NO_KERNEL_IEEE80211_MGMT) - char buf[64]; -#endif - - iface = netdev_priv(dev); - local = iface->local; - ap = local->ap; - - spin_lock_bh(&ap->sta_table_lock); - - for (ptr = ap->sta_list.next; ptr != NULL && ptr != &ap->sta_list; - ptr = ptr->next) { - struct sta_info *sta = (struct sta_info *) ptr; - - /* First entry *MUST* be the AP MAC address */ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, sta->addr, ETH_ALEN); - iwe.len = IW_EV_ADDR_LEN; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_ADDR_LEN); - - /* Use the mode to indicate if it's a station or - * an Access Point */ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWMODE; - if (sta->ap) - iwe.u.mode = IW_MODE_MASTER; - else - iwe.u.mode = IW_MODE_INFRA; - iwe.len = IW_EV_UINT_LEN; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_UINT_LEN); - - /* Some quality */ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVQUAL; - if (sta->last_rx_silence == 0) - iwe.u.qual.qual = sta->last_rx_signal < 27 ? - 0 : (sta->last_rx_signal - 27) * 92 / 127; - else - iwe.u.qual.qual = sta->last_rx_signal - - sta->last_rx_silence - 35; - iwe.u.qual.level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal); - iwe.u.qual.noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence); - iwe.u.qual.updated = sta->last_rx_updated; - iwe.len = IW_EV_QUAL_LEN; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_QUAL_LEN); - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - if (sta->ap) { - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWESSID; - iwe.u.data.length = sta->u.ap.ssid_len; - iwe.u.data.flags = 1; - current_ev = iwe_stream_add_point(info, current_ev, - end_buf, &iwe, - sta->u.ap.ssid); - - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWENCODE; - if (sta->capability & WLAN_CAPABILITY_PRIVACY) - iwe.u.data.flags = - IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - current_ev = iwe_stream_add_point(info, current_ev, - end_buf, &iwe, - sta->u.ap.ssid); - - if (sta->u.ap.channel > 0 && - sta->u.ap.channel <= FREQ_COUNT) { - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = freq_list[sta->u.ap.channel - 1] - * 100000; - iwe.u.freq.e = 1; - current_ev = iwe_stream_add_event( - info, current_ev, end_buf, &iwe, - IW_EV_FREQ_LEN); - } - - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVCUSTOM; - sprintf(buf, "beacon_interval=%d", - sta->listen_interval); - iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(info, current_ev, - end_buf, &iwe, buf); - } -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - sta->last_rx_updated = IW_QUAL_DBM; - - /* To be continued, we should make good use of IWEVCUSTOM */ - } - - spin_unlock_bh(&ap->sta_table_lock); - - return current_ev - buffer; -} - - -static int prism2_hostapd_add_sta(struct ap_data *ap, - struct prism2_hostapd_param *param) -{ - struct sta_info *sta; - - spin_lock_bh(&ap->sta_table_lock); - sta = ap_get_sta(ap, param->sta_addr); - if (sta) - atomic_inc(&sta->users); - spin_unlock_bh(&ap->sta_table_lock); - - if (sta == NULL) { - sta = ap_add_sta(ap, param->sta_addr); - if (sta == NULL) - return -1; - } - - if (!(sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) - hostap_event_new_sta(sta->local->dev, sta); - - sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; - sta->last_rx = jiffies; - sta->aid = param->u.add_sta.aid; - sta->capability = param->u.add_sta.capability; - sta->tx_supp_rates = param->u.add_sta.tx_supp_rates; - if (sta->tx_supp_rates & WLAN_RATE_1M) - sta->supported_rates[0] = 2; - if (sta->tx_supp_rates & WLAN_RATE_2M) - sta->supported_rates[1] = 4; - if (sta->tx_supp_rates & WLAN_RATE_5M5) - sta->supported_rates[2] = 11; - if (sta->tx_supp_rates & WLAN_RATE_11M) - sta->supported_rates[3] = 22; - prism2_check_tx_rates(sta); - atomic_dec(&sta->users); - return 0; -} - - -static int prism2_hostapd_remove_sta(struct ap_data *ap, - struct prism2_hostapd_param *param) -{ - struct sta_info *sta; - - spin_lock_bh(&ap->sta_table_lock); - sta = ap_get_sta(ap, param->sta_addr); - if (sta) { - ap_sta_hash_del(ap, sta); - list_del(&sta->list); - } - spin_unlock_bh(&ap->sta_table_lock); - - if (!sta) - return -ENOENT; - - if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) - hostap_event_expired_sta(sta->local->dev, sta); - ap_free_sta(ap, sta); - - return 0; -} - - -static int prism2_hostapd_get_info_sta(struct ap_data *ap, - struct prism2_hostapd_param *param) -{ - struct sta_info *sta; - - spin_lock_bh(&ap->sta_table_lock); - sta = ap_get_sta(ap, param->sta_addr); - if (sta) - atomic_inc(&sta->users); - spin_unlock_bh(&ap->sta_table_lock); - - if (!sta) - return -ENOENT; - - param->u.get_info_sta.inactive_sec = (jiffies - sta->last_rx) / HZ; - - atomic_dec(&sta->users); - - return 1; -} - - -static int prism2_hostapd_set_flags_sta(struct ap_data *ap, - struct prism2_hostapd_param *param) -{ - struct sta_info *sta; - - spin_lock_bh(&ap->sta_table_lock); - sta = ap_get_sta(ap, param->sta_addr); - if (sta) { - sta->flags |= param->u.set_flags_sta.flags_or; - sta->flags &= param->u.set_flags_sta.flags_and; - } - spin_unlock_bh(&ap->sta_table_lock); - - if (!sta) - return -ENOENT; - - return 0; -} - - -static int prism2_hostapd_sta_clear_stats(struct ap_data *ap, - struct prism2_hostapd_param *param) -{ - struct sta_info *sta; - int rate; - - spin_lock_bh(&ap->sta_table_lock); - sta = ap_get_sta(ap, param->sta_addr); - if (sta) { - sta->rx_packets = sta->tx_packets = 0; - sta->rx_bytes = sta->tx_bytes = 0; - for (rate = 0; rate < WLAN_RATE_COUNT; rate++) { - sta->tx_count[rate] = 0; - sta->rx_count[rate] = 0; - } - } - spin_unlock_bh(&ap->sta_table_lock); - - if (!sta) - return -ENOENT; - - return 0; -} - - -int prism2_hostapd(struct ap_data *ap, struct prism2_hostapd_param *param) -{ - switch (param->cmd) { - case PRISM2_HOSTAPD_FLUSH: - ap_control_kickall(ap); - return 0; - case PRISM2_HOSTAPD_ADD_STA: - return prism2_hostapd_add_sta(ap, param); - case PRISM2_HOSTAPD_REMOVE_STA: - return prism2_hostapd_remove_sta(ap, param); - case PRISM2_HOSTAPD_GET_INFO_STA: - return prism2_hostapd_get_info_sta(ap, param); - case PRISM2_HOSTAPD_SET_FLAGS_STA: - return prism2_hostapd_set_flags_sta(ap, param); - case PRISM2_HOSTAPD_STA_CLEAR_STATS: - return prism2_hostapd_sta_clear_stats(ap, param); - default: - printk(KERN_WARNING "prism2_hostapd: unknown cmd=%d\n", - param->cmd); - return -EOPNOTSUPP; - } -} - - -/* Update station info for host-based TX rate control and return current - * TX rate */ -static int ap_update_sta_tx_rate(struct sta_info *sta, struct net_device *dev) -{ - int ret = sta->tx_rate; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - sta->tx_count[sta->tx_rate_idx]++; - sta->tx_since_last_failure++; - sta->tx_consecutive_exc = 0; - if (sta->tx_since_last_failure >= WLAN_RATE_UPDATE_COUNT && - sta->tx_rate_idx < sta->tx_max_rate) { - /* use next higher rate */ - int old_rate, new_rate; - old_rate = new_rate = sta->tx_rate_idx; - while (new_rate < sta->tx_max_rate) { - new_rate++; - if (ap_tx_rate_ok(new_rate, sta, local)) { - sta->tx_rate_idx = new_rate; - break; - } - } - if (old_rate != sta->tx_rate_idx) { - switch (sta->tx_rate_idx) { - case 0: sta->tx_rate = 10; break; - case 1: sta->tx_rate = 20; break; - case 2: sta->tx_rate = 55; break; - case 3: sta->tx_rate = 110; break; - default: sta->tx_rate = 0; break; - } - PDEBUG(DEBUG_AP, "%s: STA %pM TX rate raised to %d\n", - dev->name, sta->addr, sta->tx_rate); - } - sta->tx_since_last_failure = 0; - } - - return ret; -} - - -/* Called only from software IRQ. Called for each TX frame prior possible - * encryption and transmit. */ -ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx) -{ - struct sta_info *sta = NULL; - struct sk_buff *skb = tx->skb; - int set_tim, ret; - struct ieee80211_hdr *hdr; - struct hostap_skb_tx_data *meta; - - meta = (struct hostap_skb_tx_data *) skb->cb; - ret = AP_TX_CONTINUE; - if (local->ap == NULL || skb->len < 10 || - meta->iface->type == HOSTAP_INTERFACE_STA) - goto out; - - hdr = (struct ieee80211_hdr *) skb->data; - - if (hdr->addr1[0] & 0x01) { - /* broadcast/multicast frame - no AP related processing */ - if (local->ap->num_sta <= 0) - ret = AP_TX_DROP; - goto out; - } - - /* unicast packet - check whether destination STA is associated */ - spin_lock(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr1); - if (sta) - atomic_inc(&sta->users); - spin_unlock(&local->ap->sta_table_lock); - - if (local->iw_mode == IW_MODE_MASTER && sta == NULL && - !(meta->flags & HOSTAP_TX_FLAGS_WDS) && - meta->iface->type != HOSTAP_INTERFACE_MASTER && - meta->iface->type != HOSTAP_INTERFACE_AP) { -#if 0 - /* This can happen, e.g., when wlan0 is added to a bridge and - * bridging code does not know which port is the correct target - * for a unicast frame. In this case, the packet is send to all - * ports of the bridge. Since this is a valid scenario, do not - * print out any errors here. */ - if (net_ratelimit()) { - printk(KERN_DEBUG "AP: drop packet to non-associated " - "STA %pM\n", hdr->addr1); - } -#endif - local->ap->tx_drop_nonassoc++; - ret = AP_TX_DROP; - goto out; - } - - if (sta == NULL) - goto out; - - if (!(sta->flags & WLAN_STA_AUTHORIZED)) - ret = AP_TX_CONTINUE_NOT_AUTHORIZED; - - /* Set tx_rate if using host-based TX rate control */ - if (!local->fw_tx_rate_control) - local->ap->last_tx_rate = meta->rate = - ap_update_sta_tx_rate(sta, local->dev); - - if (local->iw_mode != IW_MODE_MASTER) - goto out; - - if (!(sta->flags & WLAN_STA_PS)) - goto out; - - if (meta->flags & HOSTAP_TX_FLAGS_ADD_MOREDATA) { - /* indicate to STA that more frames follow */ - hdr->frame_control |= - cpu_to_le16(IEEE80211_FCTL_MOREDATA); - } - - if (meta->flags & HOSTAP_TX_FLAGS_BUFFERED_FRAME) { - /* packet was already buffered and now send due to - * PS poll, so do not rebuffer it */ - goto out; - } - - if (skb_queue_len(&sta->tx_buf) >= STA_MAX_TX_BUFFER) { - PDEBUG(DEBUG_PS, "%s: No more space in STA (%pM)'s" - "PS mode buffer\n", - local->dev->name, sta->addr); - /* Make sure that TIM is set for the station (it might not be - * after AP wlan hw reset). */ - /* FIX: should fix hw reset to restore bits based on STA - * buffer state.. */ - hostap_set_tim(local, sta->aid, 1); - sta->flags |= WLAN_STA_TIM; - ret = AP_TX_DROP; - goto out; - } - - /* STA in PS mode, buffer frame for later delivery */ - set_tim = skb_queue_empty(&sta->tx_buf); - skb_queue_tail(&sta->tx_buf, skb); - /* FIX: could save RX time to skb and expire buffered frames after - * some time if STA does not poll for them */ - - if (set_tim) { - if (sta->flags & WLAN_STA_TIM) - PDEBUG(DEBUG_PS2, "Re-setting TIM for aid %d\n", - sta->aid); - hostap_set_tim(local, sta->aid, 1); - sta->flags |= WLAN_STA_TIM; - } - - ret = AP_TX_BUFFERED; - - out: - if (sta != NULL) { - if (ret == AP_TX_CONTINUE || - ret == AP_TX_CONTINUE_NOT_AUTHORIZED) { - sta->tx_packets++; - sta->tx_bytes += skb->len; - sta->last_tx = jiffies; - } - - if ((ret == AP_TX_CONTINUE || - ret == AP_TX_CONTINUE_NOT_AUTHORIZED) && - sta->crypt && tx->host_encrypt) { - tx->crypt = sta->crypt; - tx->sta_ptr = sta; /* hostap_handle_sta_release() will - * be called to release sta info - * later */ - } else - atomic_dec(&sta->users); - } - - return ret; -} - - -void hostap_handle_sta_release(void *ptr) -{ - struct sta_info *sta = ptr; - atomic_dec(&sta->users); -} - - -/* Called only as a tasklet (software IRQ) */ -void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb) -{ - struct sta_info *sta; - struct ieee80211_hdr *hdr; - struct hostap_skb_tx_data *meta; - - hdr = (struct ieee80211_hdr *) skb->data; - meta = (struct hostap_skb_tx_data *) skb->cb; - - spin_lock(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr1); - if (!sta) { - spin_unlock(&local->ap->sta_table_lock); - PDEBUG(DEBUG_AP, "%s: Could not find STA %pM" - " for this TX error (@%lu)\n", - local->dev->name, hdr->addr1, jiffies); - return; - } - - sta->tx_since_last_failure = 0; - sta->tx_consecutive_exc++; - - if (sta->tx_consecutive_exc >= WLAN_RATE_DECREASE_THRESHOLD && - sta->tx_rate_idx > 0 && meta->rate <= sta->tx_rate) { - /* use next lower rate */ - int old, rate; - old = rate = sta->tx_rate_idx; - while (rate > 0) { - rate--; - if (ap_tx_rate_ok(rate, sta, local)) { - sta->tx_rate_idx = rate; - break; - } - } - if (old != sta->tx_rate_idx) { - switch (sta->tx_rate_idx) { - case 0: sta->tx_rate = 10; break; - case 1: sta->tx_rate = 20; break; - case 2: sta->tx_rate = 55; break; - case 3: sta->tx_rate = 110; break; - default: sta->tx_rate = 0; break; - } - PDEBUG(DEBUG_AP, - "%s: STA %pM TX rate lowered to %d\n", - local->dev->name, sta->addr, sta->tx_rate); - } - sta->tx_consecutive_exc = 0; - } - spin_unlock(&local->ap->sta_table_lock); -} - - -static void hostap_update_sta_ps2(local_info_t *local, struct sta_info *sta, - int pwrmgt, int type, int stype) -{ - if (pwrmgt && !(sta->flags & WLAN_STA_PS)) { - sta->flags |= WLAN_STA_PS; - PDEBUG(DEBUG_PS2, "STA %pM changed to use PS " - "mode (type=0x%02X, stype=0x%02X)\n", - sta->addr, type >> 2, stype >> 4); - } else if (!pwrmgt && (sta->flags & WLAN_STA_PS)) { - sta->flags &= ~WLAN_STA_PS; - PDEBUG(DEBUG_PS2, "STA %pM changed to not use " - "PS mode (type=0x%02X, stype=0x%02X)\n", - sta->addr, type >> 2, stype >> 4); - if (type != IEEE80211_FTYPE_CTL || - stype != IEEE80211_STYPE_PSPOLL) - schedule_packet_send(local, sta); - } -} - - -/* Called only as a tasklet (software IRQ). Called for each RX frame to update - * STA power saving state. pwrmgt is a flag from 802.11 frame_control field. */ -int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr *hdr) -{ - struct sta_info *sta; - u16 fc; - - spin_lock(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr2); - if (sta) - atomic_inc(&sta->users); - spin_unlock(&local->ap->sta_table_lock); - - if (!sta) - return -1; - - fc = le16_to_cpu(hdr->frame_control); - hostap_update_sta_ps2(local, sta, fc & IEEE80211_FCTL_PM, - fc & IEEE80211_FCTL_FTYPE, - fc & IEEE80211_FCTL_STYPE); - - atomic_dec(&sta->users); - return 0; -} - - -/* Called only as a tasklet (software IRQ). Called for each RX frame after - * getting RX header and payload from hardware. */ -ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, - struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats, - int wds) -{ - int ret; - struct sta_info *sta; - u16 fc, type, stype; - struct ieee80211_hdr *hdr; - - if (local->ap == NULL) - return AP_RX_CONTINUE; - - hdr = (struct ieee80211_hdr *) skb->data; - - fc = le16_to_cpu(hdr->frame_control); - type = fc & IEEE80211_FCTL_FTYPE; - stype = fc & IEEE80211_FCTL_STYPE; - - spin_lock(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr2); - if (sta) - atomic_inc(&sta->users); - spin_unlock(&local->ap->sta_table_lock); - - if (sta && !(sta->flags & WLAN_STA_AUTHORIZED)) - ret = AP_RX_CONTINUE_NOT_AUTHORIZED; - else - ret = AP_RX_CONTINUE; - - - if (fc & IEEE80211_FCTL_TODS) { - if (!wds && (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) { - if (local->hostapd) { - prism2_rx_80211(local->apdev, skb, rx_stats, - PRISM2_RX_NON_ASSOC); -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - } else { - printk(KERN_DEBUG "%s: dropped received packet" - " from non-associated STA %pM" - " (type=0x%02x, subtype=0x%02x)\n", - dev->name, hdr->addr2, - type >> 2, stype >> 4); - hostap_rx(dev, skb, rx_stats); -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - } - ret = AP_RX_EXIT; - goto out; - } - } else if (fc & IEEE80211_FCTL_FROMDS) { - if (!wds) { - /* FromDS frame - not for us; probably - * broadcast/multicast in another BSS - drop */ - if (ether_addr_equal(hdr->addr1, dev->dev_addr)) { - printk(KERN_DEBUG "Odd.. FromDS packet " - "received with own BSSID\n"); - hostap_dump_rx_80211(dev->name, skb, rx_stats); - } - ret = AP_RX_DROP; - goto out; - } - } else if (stype == IEEE80211_STYPE_NULLFUNC && sta == NULL && - ether_addr_equal(hdr->addr1, dev->dev_addr)) { - - if (local->hostapd) { - prism2_rx_80211(local->apdev, skb, rx_stats, - PRISM2_RX_NON_ASSOC); -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - } else { - /* At least Lucent f/w seems to send data::nullfunc - * frames with no ToDS flag when the current AP returns - * after being unavailable for some time. Speed up - * re-association by informing the station about it not - * being associated. */ - printk(KERN_DEBUG "%s: rejected received nullfunc frame" - " without ToDS from not associated STA %pM\n", - dev->name, hdr->addr2); - hostap_rx(dev, skb, rx_stats); -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - } - ret = AP_RX_EXIT; - goto out; - } else if (stype == IEEE80211_STYPE_NULLFUNC) { - /* At least Lucent cards seem to send periodic nullfunc - * frames with ToDS. Let these through to update SQ - * stats and PS state. Nullfunc frames do not contain - * any data and they will be dropped below. */ - } else { - /* If BSSID (Addr3) is foreign, this frame is a normal - * broadcast frame from an IBSS network. Drop it silently. - * If BSSID is own, report the dropping of this frame. */ - if (ether_addr_equal(hdr->addr3, dev->dev_addr)) { - printk(KERN_DEBUG "%s: dropped received packet from %pM" - " with no ToDS flag " - "(type=0x%02x, subtype=0x%02x)\n", dev->name, - hdr->addr2, type >> 2, stype >> 4); - hostap_dump_rx_80211(dev->name, skb, rx_stats); - } - ret = AP_RX_DROP; - goto out; - } - - if (sta) { - hostap_update_sta_ps2(local, sta, fc & IEEE80211_FCTL_PM, - type, stype); - - sta->rx_packets++; - sta->rx_bytes += skb->len; - sta->last_rx = jiffies; - } - - if (local->ap->nullfunc_ack && stype == IEEE80211_STYPE_NULLFUNC && - fc & IEEE80211_FCTL_TODS) { - if (local->hostapd) { - prism2_rx_80211(local->apdev, skb, rx_stats, - PRISM2_RX_NULLFUNC_ACK); -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - } else { - /* some STA f/w's seem to require control::ACK frame - * for data::nullfunc, but Prism2 f/w 0.8.0 (at least - * from Compaq) does not send this.. Try to generate - * ACK for these frames from the host driver to make - * power saving work with, e.g., Lucent WaveLAN f/w */ - hostap_rx(dev, skb, rx_stats); -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - } - ret = AP_RX_EXIT; - goto out; - } - - out: - if (sta) - atomic_dec(&sta->users); - - return ret; -} - - -/* Called only as a tasklet (software IRQ) */ -int hostap_handle_sta_crypto(local_info_t *local, - struct ieee80211_hdr *hdr, - struct lib80211_crypt_data **crypt, - void **sta_ptr) -{ - struct sta_info *sta; - - spin_lock(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr2); - if (sta) - atomic_inc(&sta->users); - spin_unlock(&local->ap->sta_table_lock); - - if (!sta) - return -1; - - if (sta->crypt) { - *crypt = sta->crypt; - *sta_ptr = sta; - /* hostap_handle_sta_release() will be called to release STA - * info */ - } else - atomic_dec(&sta->users); - - return 0; -} - - -/* Called only as a tasklet (software IRQ) */ -int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr) -{ - struct sta_info *sta; - int ret = 0; - - spin_lock(&ap->sta_table_lock); - sta = ap_get_sta(ap, sta_addr); - if (sta != NULL && (sta->flags & WLAN_STA_ASSOC) && !sta->ap) - ret = 1; - spin_unlock(&ap->sta_table_lock); - - return ret; -} - - -/* Called only as a tasklet (software IRQ) */ -int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr) -{ - struct sta_info *sta; - int ret = 0; - - spin_lock(&ap->sta_table_lock); - sta = ap_get_sta(ap, sta_addr); - if (sta != NULL && (sta->flags & WLAN_STA_ASSOC) && !sta->ap && - ((sta->flags & WLAN_STA_AUTHORIZED) || - ap->local->ieee_802_1x == 0)) - ret = 1; - spin_unlock(&ap->sta_table_lock); - - return ret; -} - - -/* Called only as a tasklet (software IRQ) */ -int hostap_add_sta(struct ap_data *ap, u8 *sta_addr) -{ - struct sta_info *sta; - int ret = 1; - - if (!ap) - return -1; - - spin_lock(&ap->sta_table_lock); - sta = ap_get_sta(ap, sta_addr); - if (sta) - ret = 0; - spin_unlock(&ap->sta_table_lock); - - if (ret == 1) { - sta = ap_add_sta(ap, sta_addr); - if (!sta) - return -1; - sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; - sta->ap = 1; - memset(sta->supported_rates, 0, sizeof(sta->supported_rates)); - /* No way of knowing which rates are supported since we did not - * get supported rates element from beacon/assoc req. Assume - * that remote end supports all 802.11b rates. */ - sta->supported_rates[0] = 0x82; - sta->supported_rates[1] = 0x84; - sta->supported_rates[2] = 0x0b; - sta->supported_rates[3] = 0x16; - sta->tx_supp_rates = WLAN_RATE_1M | WLAN_RATE_2M | - WLAN_RATE_5M5 | WLAN_RATE_11M; - sta->tx_rate = 110; - sta->tx_max_rate = sta->tx_rate_idx = 3; - } - - return ret; -} - - -/* Called only as a tasklet (software IRQ) */ -int hostap_update_rx_stats(struct ap_data *ap, - struct ieee80211_hdr *hdr, - struct hostap_80211_rx_status *rx_stats) -{ - struct sta_info *sta; - - if (!ap) - return -1; - - spin_lock(&ap->sta_table_lock); - sta = ap_get_sta(ap, hdr->addr2); - if (sta) { - sta->last_rx_silence = rx_stats->noise; - sta->last_rx_signal = rx_stats->signal; - sta->last_rx_rate = rx_stats->rate; - sta->last_rx_updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; - if (rx_stats->rate == 10) - sta->rx_count[0]++; - else if (rx_stats->rate == 20) - sta->rx_count[1]++; - else if (rx_stats->rate == 55) - sta->rx_count[2]++; - else if (rx_stats->rate == 110) - sta->rx_count[3]++; - } - spin_unlock(&ap->sta_table_lock); - - return sta ? 0 : -1; -} - - -void hostap_update_rates(local_info_t *local) -{ - struct sta_info *sta; - struct ap_data *ap = local->ap; - - if (!ap) - return; - - spin_lock_bh(&ap->sta_table_lock); - list_for_each_entry(sta, &ap->sta_list, list) { - prism2_check_tx_rates(sta); - } - spin_unlock_bh(&ap->sta_table_lock); -} - - -void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent, - struct lib80211_crypt_data ***crypt) -{ - struct sta_info *sta; - - spin_lock_bh(&ap->sta_table_lock); - sta = ap_get_sta(ap, addr); - if (sta) - atomic_inc(&sta->users); - spin_unlock_bh(&ap->sta_table_lock); - - if (!sta && permanent) - sta = ap_add_sta(ap, addr); - - if (!sta) - return NULL; - - if (permanent) - sta->flags |= WLAN_STA_PERM; - - *crypt = &sta->crypt; - - return sta; -} - - -void hostap_add_wds_links(local_info_t *local) -{ - struct ap_data *ap = local->ap; - struct sta_info *sta; - - spin_lock_bh(&ap->sta_table_lock); - list_for_each_entry(sta, &ap->sta_list, list) { - if (sta->ap) - hostap_wds_link_oper(local, sta->addr, WDS_ADD); - } - spin_unlock_bh(&ap->sta_table_lock); - - schedule_work(&local->ap->wds_oper_queue); -} - - -void hostap_wds_link_oper(local_info_t *local, u8 *addr, wds_oper_type type) -{ - struct wds_oper_data *entry; - - entry = kmalloc(sizeof(*entry), GFP_ATOMIC); - if (!entry) - return; - memcpy(entry->addr, addr, ETH_ALEN); - entry->type = type; - spin_lock_bh(&local->lock); - entry->next = local->ap->wds_oper_entries; - local->ap->wds_oper_entries = entry; - spin_unlock_bh(&local->lock); - - schedule_work(&local->ap->wds_oper_queue); -} - - -EXPORT_SYMBOL(hostap_init_data); -EXPORT_SYMBOL(hostap_init_ap_proc); -EXPORT_SYMBOL(hostap_free_data); -EXPORT_SYMBOL(hostap_check_sta_fw_version); -EXPORT_SYMBOL(hostap_handle_sta_tx_exc); -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ diff --git a/drivers/net/wireless/intersil/hostap/hostap_ap.h b/drivers/net/wireless/intersil/hostap/hostap_ap.h deleted file mode 100644 index b7ac9e2f1a394..0000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_ap.h +++ /dev/null @@ -1,264 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef HOSTAP_AP_H -#define HOSTAP_AP_H - -#include "hostap_80211.h" - -/* AP data structures for STAs */ - -/* maximum number of frames to buffer per STA */ -#define STA_MAX_TX_BUFFER 32 - -/* STA flags */ -#define WLAN_STA_AUTH BIT(0) -#define WLAN_STA_ASSOC BIT(1) -#define WLAN_STA_PS BIT(2) -#define WLAN_STA_TIM BIT(3) /* TIM bit is on for PS stations */ -#define WLAN_STA_PERM BIT(4) /* permanent; do not remove entry on expiration */ -#define WLAN_STA_AUTHORIZED BIT(5) /* If 802.1X is used, this flag is - * controlling whether STA is authorized to - * send and receive non-IEEE 802.1X frames - */ -#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */ - -#define WLAN_RATE_1M BIT(0) -#define WLAN_RATE_2M BIT(1) -#define WLAN_RATE_5M5 BIT(2) -#define WLAN_RATE_11M BIT(3) -#define WLAN_RATE_COUNT 4 - -/* Maximum size of Supported Rates info element. IEEE 802.11 has a limit of 8, - * but some pre-standard IEEE 802.11g products use longer elements. */ -#define WLAN_SUPP_RATES_MAX 32 - -/* Try to increase TX rate after # successfully sent consecutive packets */ -#define WLAN_RATE_UPDATE_COUNT 50 - -/* Decrease TX rate after # consecutive dropped packets */ -#define WLAN_RATE_DECREASE_THRESHOLD 2 - -struct sta_info { - struct list_head list; - struct sta_info *hnext; /* next entry in hash table list */ - atomic_t users; /* number of users (do not remove if > 0) */ - struct proc_dir_entry *proc; - - u8 addr[6]; - u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */ - u32 flags; - u16 capability; - u16 listen_interval; /* or beacon_int for APs */ - u8 supported_rates[WLAN_SUPP_RATES_MAX]; - - unsigned long last_auth; - unsigned long last_assoc; - unsigned long last_rx; - unsigned long last_tx; - unsigned long rx_packets, tx_packets; - unsigned long rx_bytes, tx_bytes; - struct sk_buff_head tx_buf; - /* FIX: timeout buffers with an expiry time somehow derived from - * listen_interval */ - - s8 last_rx_silence; /* Noise in dBm */ - s8 last_rx_signal; /* Signal strength in dBm */ - u8 last_rx_rate; /* TX rate in 0.1 Mbps */ - u8 last_rx_updated; /* IWSPY's struct iw_quality::updated */ - - u8 tx_supp_rates; /* bit field of supported TX rates */ - u8 tx_rate; /* current TX rate (in 0.1 Mbps) */ - u8 tx_rate_idx; /* current TX rate (WLAN_RATE_*) */ - u8 tx_max_rate; /* max TX rate (WLAN_RATE_*) */ - u32 tx_count[WLAN_RATE_COUNT]; /* number of frames sent (per rate) */ - u32 rx_count[WLAN_RATE_COUNT]; /* number of frames received (per rate) - */ - u32 tx_since_last_failure; - u32 tx_consecutive_exc; - - struct lib80211_crypt_data *crypt; - - int ap; /* whether this station is an AP */ - - local_info_t *local; - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - union { - struct { - char *challenge; /* shared key authentication - * challenge */ - } sta; - struct { - int ssid_len; - unsigned char ssid[MAX_SSID_LEN + 1]; /* AP's ssid */ - int channel; - unsigned long last_beacon; /* last RX beacon time */ - } ap; - } u; - - struct timer_list timer; - enum { STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH } timeout_next; -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ -}; - - -#define MAX_STA_COUNT 1024 - -/* Maximum number of AIDs to use for STAs; must be 2007 or lower - * (8802.11 limitation) */ -#define MAX_AID_TABLE_SIZE 128 - -#define STA_HASH_SIZE 256 -#define STA_HASH(sta) (sta[5]) - - -/* Default value for maximum station inactivity. After AP_MAX_INACTIVITY_SEC - * has passed since last received frame from the station, a nullfunc data - * frame is sent to the station. If this frame is not acknowledged and no other - * frames have been received, the station will be disassociated after - * AP_DISASSOC_DELAY. Similarly, a the station will be deauthenticated after - * AP_DEAUTH_DELAY. AP_TIMEOUT_RESOLUTION is the resolution that is used with - * max inactivity timer. */ -#define AP_MAX_INACTIVITY_SEC (5 * 60) -#define AP_DISASSOC_DELAY (HZ) -#define AP_DEAUTH_DELAY (HZ) - -/* ap_policy: whether to accept frames to/from other APs/IBSS */ -typedef enum { - AP_OTHER_AP_SKIP_ALL = 0, - AP_OTHER_AP_SAME_SSID = 1, - AP_OTHER_AP_ALL = 2, - AP_OTHER_AP_EVEN_IBSS = 3 -} ap_policy_enum; - -#define PRISM2_AUTH_OPEN BIT(0) -#define PRISM2_AUTH_SHARED_KEY BIT(1) - - -/* MAC address-based restrictions */ -struct mac_entry { - struct list_head list; - u8 addr[6]; -}; - -struct mac_restrictions { - enum { MAC_POLICY_OPEN = 0, MAC_POLICY_ALLOW, MAC_POLICY_DENY } policy; - unsigned int entries; - struct list_head mac_list; - spinlock_t lock; -}; - - -struct add_sta_proc_data { - u8 addr[ETH_ALEN]; - struct add_sta_proc_data *next; -}; - - -typedef enum { WDS_ADD, WDS_DEL } wds_oper_type; -struct wds_oper_data { - wds_oper_type type; - u8 addr[ETH_ALEN]; - struct wds_oper_data *next; -}; - - -struct ap_data { - int initialized; /* whether ap_data has been initialized */ - local_info_t *local; - int bridge_packets; /* send packet to associated STAs directly to the - * wireless media instead of higher layers in the - * kernel */ - unsigned int bridged_unicast; /* number of unicast frames bridged on - * wireless media */ - unsigned int bridged_multicast; /* number of non-unicast frames - * bridged on wireless media */ - unsigned int tx_drop_nonassoc; /* number of unicast TX packets dropped - * because they were to an address that - * was not associated */ - int nullfunc_ack; /* use workaround for nullfunc frame ACKs */ - - spinlock_t sta_table_lock; - int num_sta; /* number of entries in sta_list */ - struct list_head sta_list; /* STA info list head */ - struct sta_info *sta_hash[STA_HASH_SIZE]; - - struct proc_dir_entry *proc; - - ap_policy_enum ap_policy; - unsigned int max_inactivity; - int autom_ap_wds; - - struct mac_restrictions mac_restrictions; /* MAC-based auth */ - int last_tx_rate; - - struct work_struct add_sta_proc_queue; - struct add_sta_proc_data *add_sta_proc_entries; - - struct work_struct wds_oper_queue; - struct wds_oper_data *wds_oper_entries; - - u16 tx_callback_idx; - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - /* pointers to STA info; based on allocated AID or NULL if AID free - * AID is in the range 1-2007, so sta_aid[0] corresponders to AID 1 - * and so on - */ - struct sta_info *sta_aid[MAX_AID_TABLE_SIZE]; - - u16 tx_callback_auth, tx_callback_assoc, tx_callback_poll; - - /* WEP operations for generating challenges to be used with shared key - * authentication */ - struct lib80211_crypto_ops *crypt; - void *crypt_priv; -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ -}; - - -void hostap_rx(struct net_device *dev, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats); -void hostap_init_data(local_info_t *local); -void hostap_init_ap_proc(local_info_t *local); -void hostap_free_data(struct ap_data *ap); -void hostap_check_sta_fw_version(struct ap_data *ap, int sta_fw_ver); - -typedef enum { - AP_TX_CONTINUE, AP_TX_DROP, AP_TX_RETRY, AP_TX_BUFFERED, - AP_TX_CONTINUE_NOT_AUTHORIZED -} ap_tx_ret; -struct hostap_tx_data { - struct sk_buff *skb; - int host_encrypt; - struct lib80211_crypt_data *crypt; - void *sta_ptr; -}; -ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx); -void hostap_handle_sta_release(void *ptr); -void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb); -int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr *hdr); -typedef enum { - AP_RX_CONTINUE, AP_RX_DROP, AP_RX_EXIT, AP_RX_CONTINUE_NOT_AUTHORIZED -} ap_rx_ret; -ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, - struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats, - int wds); -int hostap_handle_sta_crypto(local_info_t *local, struct ieee80211_hdr *hdr, - struct lib80211_crypt_data **crypt, - void **sta_ptr); -int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr); -int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr); -int hostap_add_sta(struct ap_data *ap, u8 *sta_addr); -int hostap_update_rx_stats(struct ap_data *ap, struct ieee80211_hdr *hdr, - struct hostap_80211_rx_status *rx_stats); -void hostap_update_rates(local_info_t *local); -void hostap_add_wds_links(local_info_t *local); -void hostap_wds_link_oper(local_info_t *local, u8 *addr, wds_oper_type type); - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT -void hostap_deauth_all_stas(struct net_device *dev, struct ap_data *ap, - int resend); -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - -#endif /* HOSTAP_AP_H */ diff --git a/drivers/net/wireless/intersil/hostap/hostap_common.h b/drivers/net/wireless/intersil/hostap/hostap_common.h deleted file mode 100644 index dd29a8e8d3496..0000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_common.h +++ /dev/null @@ -1,420 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef HOSTAP_COMMON_H -#define HOSTAP_COMMON_H - -#include -#include - -/* IEEE 802.11 defines */ - -/* HFA384X Configuration RIDs */ -#define HFA384X_RID_CNFPORTTYPE 0xFC00 -#define HFA384X_RID_CNFOWNMACADDR 0xFC01 -#define HFA384X_RID_CNFDESIREDSSID 0xFC02 -#define HFA384X_RID_CNFOWNCHANNEL 0xFC03 -#define HFA384X_RID_CNFOWNSSID 0xFC04 -#define HFA384X_RID_CNFOWNATIMWINDOW 0xFC05 -#define HFA384X_RID_CNFSYSTEMSCALE 0xFC06 -#define HFA384X_RID_CNFMAXDATALEN 0xFC07 -#define HFA384X_RID_CNFWDSADDRESS 0xFC08 -#define HFA384X_RID_CNFPMENABLED 0xFC09 -#define HFA384X_RID_CNFPMEPS 0xFC0A -#define HFA384X_RID_CNFMULTICASTRECEIVE 0xFC0B -#define HFA384X_RID_CNFMAXSLEEPDURATION 0xFC0C -#define HFA384X_RID_CNFPMHOLDOVERDURATION 0xFC0D -#define HFA384X_RID_CNFOWNNAME 0xFC0E -#define HFA384X_RID_CNFOWNDTIMPERIOD 0xFC10 -#define HFA384X_RID_CNFWDSADDRESS1 0xFC11 /* AP f/w only */ -#define HFA384X_RID_CNFWDSADDRESS2 0xFC12 /* AP f/w only */ -#define HFA384X_RID_CNFWDSADDRESS3 0xFC13 /* AP f/w only */ -#define HFA384X_RID_CNFWDSADDRESS4 0xFC14 /* AP f/w only */ -#define HFA384X_RID_CNFWDSADDRESS5 0xFC15 /* AP f/w only */ -#define HFA384X_RID_CNFWDSADDRESS6 0xFC16 /* AP f/w only */ -#define HFA384X_RID_CNFMULTICASTPMBUFFERING 0xFC17 /* AP f/w only */ -#define HFA384X_RID_UNKNOWN1 0xFC20 -#define HFA384X_RID_UNKNOWN2 0xFC21 -#define HFA384X_RID_CNFWEPDEFAULTKEYID 0xFC23 -#define HFA384X_RID_CNFDEFAULTKEY0 0xFC24 -#define HFA384X_RID_CNFDEFAULTKEY1 0xFC25 -#define HFA384X_RID_CNFDEFAULTKEY2 0xFC26 -#define HFA384X_RID_CNFDEFAULTKEY3 0xFC27 -#define HFA384X_RID_CNFWEPFLAGS 0xFC28 -#define HFA384X_RID_CNFWEPKEYMAPPINGTABLE 0xFC29 -#define HFA384X_RID_CNFAUTHENTICATION 0xFC2A -#define HFA384X_RID_CNFMAXASSOCSTA 0xFC2B /* AP f/w only */ -#define HFA384X_RID_CNFTXCONTROL 0xFC2C -#define HFA384X_RID_CNFROAMINGMODE 0xFC2D -#define HFA384X_RID_CNFHOSTAUTHENTICATION 0xFC2E /* AP f/w only */ -#define HFA384X_RID_CNFRCVCRCERROR 0xFC30 -#define HFA384X_RID_CNFMMLIFE 0xFC31 -#define HFA384X_RID_CNFALTRETRYCOUNT 0xFC32 -#define HFA384X_RID_CNFBEACONINT 0xFC33 -#define HFA384X_RID_CNFAPPCFINFO 0xFC34 /* AP f/w only */ -#define HFA384X_RID_CNFSTAPCFINFO 0xFC35 -#define HFA384X_RID_CNFPRIORITYQUSAGE 0xFC37 -#define HFA384X_RID_CNFTIMCTRL 0xFC40 -#define HFA384X_RID_UNKNOWN3 0xFC41 /* added in STA f/w 0.7.x */ -#define HFA384X_RID_CNFTHIRTY2TALLY 0xFC42 /* added in STA f/w 0.8.0 */ -#define HFA384X_RID_CNFENHSECURITY 0xFC43 /* AP f/w or STA f/w >= 1.6.3 */ -#define HFA384X_RID_CNFDBMADJUST 0xFC46 /* added in STA f/w 1.3.1 */ -#define HFA384X_RID_GENERICELEMENT 0xFC48 /* added in STA f/w 1.7.0; - * write only */ -#define HFA384X_RID_PROPAGATIONDELAY 0xFC49 /* added in STA f/w 1.7.6 */ -#define HFA384X_RID_GROUPADDRESSES 0xFC80 -#define HFA384X_RID_CREATEIBSS 0xFC81 -#define HFA384X_RID_FRAGMENTATIONTHRESHOLD 0xFC82 -#define HFA384X_RID_RTSTHRESHOLD 0xFC83 -#define HFA384X_RID_TXRATECONTROL 0xFC84 -#define HFA384X_RID_PROMISCUOUSMODE 0xFC85 -#define HFA384X_RID_FRAGMENTATIONTHRESHOLD0 0xFC90 /* AP f/w only */ -#define HFA384X_RID_FRAGMENTATIONTHRESHOLD1 0xFC91 /* AP f/w only */ -#define HFA384X_RID_FRAGMENTATIONTHRESHOLD2 0xFC92 /* AP f/w only */ -#define HFA384X_RID_FRAGMENTATIONTHRESHOLD3 0xFC93 /* AP f/w only */ -#define HFA384X_RID_FRAGMENTATIONTHRESHOLD4 0xFC94 /* AP f/w only */ -#define HFA384X_RID_FRAGMENTATIONTHRESHOLD5 0xFC95 /* AP f/w only */ -#define HFA384X_RID_FRAGMENTATIONTHRESHOLD6 0xFC96 /* AP f/w only */ -#define HFA384X_RID_RTSTHRESHOLD0 0xFC97 /* AP f/w only */ -#define HFA384X_RID_RTSTHRESHOLD1 0xFC98 /* AP f/w only */ -#define HFA384X_RID_RTSTHRESHOLD2 0xFC99 /* AP f/w only */ -#define HFA384X_RID_RTSTHRESHOLD3 0xFC9A /* AP f/w only */ -#define HFA384X_RID_RTSTHRESHOLD4 0xFC9B /* AP f/w only */ -#define HFA384X_RID_RTSTHRESHOLD5 0xFC9C /* AP f/w only */ -#define HFA384X_RID_RTSTHRESHOLD6 0xFC9D /* AP f/w only */ -#define HFA384X_RID_TXRATECONTROL0 0xFC9E /* AP f/w only */ -#define HFA384X_RID_TXRATECONTROL1 0xFC9F /* AP f/w only */ -#define HFA384X_RID_TXRATECONTROL2 0xFCA0 /* AP f/w only */ -#define HFA384X_RID_TXRATECONTROL3 0xFCA1 /* AP f/w only */ -#define HFA384X_RID_TXRATECONTROL4 0xFCA2 /* AP f/w only */ -#define HFA384X_RID_TXRATECONTROL5 0xFCA3 /* AP f/w only */ -#define HFA384X_RID_TXRATECONTROL6 0xFCA4 /* AP f/w only */ -#define HFA384X_RID_CNFSHORTPREAMBLE 0xFCB0 -#define HFA384X_RID_CNFEXCLUDELONGPREAMBLE 0xFCB1 -#define HFA384X_RID_CNFAUTHENTICATIONRSPTO 0xFCB2 -#define HFA384X_RID_CNFBASICRATES 0xFCB3 -#define HFA384X_RID_CNFSUPPORTEDRATES 0xFCB4 -#define HFA384X_RID_CNFFALLBACKCTRL 0xFCB5 /* added in STA f/w 1.3.1 */ -#define HFA384X_RID_WEPKEYDISABLE 0xFCB6 /* added in STA f/w 1.3.1 */ -#define HFA384X_RID_WEPKEYMAPINDEX 0xFCB7 /* ? */ -#define HFA384X_RID_BROADCASTKEYID 0xFCB8 /* ? */ -#define HFA384X_RID_ENTSECFLAGEYID 0xFCB9 /* ? */ -#define HFA384X_RID_CNFPASSIVESCANCTRL 0xFCBA /* added in STA f/w 1.5.0 */ -#define HFA384X_RID_SSNHANDLINGMODE 0xFCBB /* added in STA f/w 1.7.0 */ -#define HFA384X_RID_MDCCONTROL 0xFCBC /* added in STA f/w 1.7.0 */ -#define HFA384X_RID_MDCCOUNTRY 0xFCBD /* added in STA f/w 1.7.0 */ -#define HFA384X_RID_TXPOWERMAX 0xFCBE /* added in STA f/w 1.7.0 */ -#define HFA384X_RID_CNFLFOENABLED 0xFCBF /* added in STA f/w 1.6.3 */ -#define HFA384X_RID_CAPINFO 0xFCC0 /* added in STA f/w 1.7.0 */ -#define HFA384X_RID_LISTENINTERVAL 0xFCC1 /* added in STA f/w 1.7.0 */ -#define HFA384X_RID_SW_ANT_DIV 0xFCC2 /* added in STA f/w 1.7.0; Prism3 */ -#define HFA384X_RID_LED_CTRL 0xFCC4 /* added in STA f/w 1.7.6 */ -#define HFA384X_RID_HFODELAY 0xFCC5 /* added in STA f/w 1.7.6 */ -#define HFA384X_RID_DISALLOWEDBSSID 0xFCC6 /* added in STA f/w 1.8.0 */ -#define HFA384X_RID_TICKTIME 0xFCE0 -#define HFA384X_RID_SCANREQUEST 0xFCE1 -#define HFA384X_RID_JOINREQUEST 0xFCE2 -#define HFA384X_RID_AUTHENTICATESTATION 0xFCE3 /* AP f/w only */ -#define HFA384X_RID_CHANNELINFOREQUEST 0xFCE4 /* AP f/w only */ -#define HFA384X_RID_HOSTSCAN 0xFCE5 /* added in STA f/w 1.3.1 */ - -/* HFA384X Information RIDs */ -#define HFA384X_RID_MAXLOADTIME 0xFD00 -#define HFA384X_RID_DOWNLOADBUFFER 0xFD01 -#define HFA384X_RID_PRIID 0xFD02 -#define HFA384X_RID_PRISUPRANGE 0xFD03 -#define HFA384X_RID_CFIACTRANGES 0xFD04 -#define HFA384X_RID_NICSERNUM 0xFD0A -#define HFA384X_RID_NICID 0xFD0B -#define HFA384X_RID_MFISUPRANGE 0xFD0C -#define HFA384X_RID_CFISUPRANGE 0xFD0D -#define HFA384X_RID_CHANNELLIST 0xFD10 -#define HFA384X_RID_REGULATORYDOMAINS 0xFD11 -#define HFA384X_RID_TEMPTYPE 0xFD12 -#define HFA384X_RID_CIS 0xFD13 -#define HFA384X_RID_STAID 0xFD20 -#define HFA384X_RID_STASUPRANGE 0xFD21 -#define HFA384X_RID_MFIACTRANGES 0xFD22 -#define HFA384X_RID_CFIACTRANGES2 0xFD23 -#define HFA384X_RID_PRODUCTNAME 0xFD24 /* added in STA f/w 1.3.1; - * only Prism2.5(?) */ -#define HFA384X_RID_PORTSTATUS 0xFD40 -#define HFA384X_RID_CURRENTSSID 0xFD41 -#define HFA384X_RID_CURRENTBSSID 0xFD42 -#define HFA384X_RID_COMMSQUALITY 0xFD43 -#define HFA384X_RID_CURRENTTXRATE 0xFD44 -#define HFA384X_RID_CURRENTBEACONINTERVAL 0xFD45 -#define HFA384X_RID_CURRENTSCALETHRESHOLDS 0xFD46 -#define HFA384X_RID_PROTOCOLRSPTIME 0xFD47 -#define HFA384X_RID_SHORTRETRYLIMIT 0xFD48 -#define HFA384X_RID_LONGRETRYLIMIT 0xFD49 -#define HFA384X_RID_MAXTRANSMITLIFETIME 0xFD4A -#define HFA384X_RID_MAXRECEIVELIFETIME 0xFD4B -#define HFA384X_RID_CFPOLLABLE 0xFD4C -#define HFA384X_RID_AUTHENTICATIONALGORITHMS 0xFD4D -#define HFA384X_RID_PRIVACYOPTIONIMPLEMENTED 0xFD4F -#define HFA384X_RID_DBMCOMMSQUALITY 0xFD51 /* added in STA f/w 1.3.1 */ -#define HFA384X_RID_CURRENTTXRATE1 0xFD80 /* AP f/w only */ -#define HFA384X_RID_CURRENTTXRATE2 0xFD81 /* AP f/w only */ -#define HFA384X_RID_CURRENTTXRATE3 0xFD82 /* AP f/w only */ -#define HFA384X_RID_CURRENTTXRATE4 0xFD83 /* AP f/w only */ -#define HFA384X_RID_CURRENTTXRATE5 0xFD84 /* AP f/w only */ -#define HFA384X_RID_CURRENTTXRATE6 0xFD85 /* AP f/w only */ -#define HFA384X_RID_OWNMACADDR 0xFD86 /* AP f/w only */ -#define HFA384X_RID_SCANRESULTSTABLE 0xFD88 /* added in STA f/w 0.8.3 */ -#define HFA384X_RID_HOSTSCANRESULTS 0xFD89 /* added in STA f/w 1.3.1 */ -#define HFA384X_RID_AUTHENTICATIONUSED 0xFD8A /* added in STA f/w 1.3.4 */ -#define HFA384X_RID_CNFFAASWITCHCTRL 0xFD8B /* added in STA f/w 1.6.3 */ -#define HFA384X_RID_ASSOCIATIONFAILURE 0xFD8D /* added in STA f/w 1.8.0 */ -#define HFA384X_RID_PHYTYPE 0xFDC0 -#define HFA384X_RID_CURRENTCHANNEL 0xFDC1 -#define HFA384X_RID_CURRENTPOWERSTATE 0xFDC2 -#define HFA384X_RID_CCAMODE 0xFDC3 -#define HFA384X_RID_SUPPORTEDDATARATES 0xFDC6 -#define HFA384X_RID_LFO_VOLT_REG_TEST_RES 0xFDC7 /* added in STA f/w 1.7.1 */ -#define HFA384X_RID_BUILDSEQ 0xFFFE -#define HFA384X_RID_FWID 0xFFFF - - -struct hfa384x_comp_ident -{ - __le16 id; - __le16 variant; - __le16 major; - __le16 minor; -} __packed; - -#define HFA384X_COMP_ID_PRI 0x15 -#define HFA384X_COMP_ID_STA 0x1f -#define HFA384X_COMP_ID_FW_AP 0x14b - -struct hfa384x_sup_range -{ - __le16 role; - __le16 id; - __le16 variant; - __le16 bottom; - __le16 top; -} __packed; - - -struct hfa384x_build_id -{ - __le16 pri_seq; - __le16 sec_seq; -} __packed; - -/* FD01 - Download Buffer */ -struct hfa384x_rid_download_buffer -{ - __le16 page; - __le16 offset; - __le16 length; -} __packed; - -/* BSS connection quality (RID FD43 range, RID FD51 dBm-normalized) */ -struct hfa384x_comms_quality { - __le16 comm_qual; /* 0 .. 92 */ - __le16 signal_level; /* 27 .. 154 */ - __le16 noise_level; /* 27 .. 154 */ -} __packed; - - -/* netdevice private ioctls (used, e.g., with iwpriv from user space) */ - -/* New wireless extensions API - SET/GET convention (even ioctl numbers are - * root only) - */ -#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0) -#define PRISM2_IOCTL_GET_PRISM2_PARAM (SIOCIWFIRSTPRIV + 1) -#define PRISM2_IOCTL_WRITEMIF (SIOCIWFIRSTPRIV + 2) -#define PRISM2_IOCTL_READMIF (SIOCIWFIRSTPRIV + 3) -#define PRISM2_IOCTL_MONITOR (SIOCIWFIRSTPRIV + 4) -#define PRISM2_IOCTL_RESET (SIOCIWFIRSTPRIV + 6) -#define PRISM2_IOCTL_INQUIRE (SIOCIWFIRSTPRIV + 8) -#define PRISM2_IOCTL_WDS_ADD (SIOCIWFIRSTPRIV + 10) -#define PRISM2_IOCTL_WDS_DEL (SIOCIWFIRSTPRIV + 12) -#define PRISM2_IOCTL_SET_RID_WORD (SIOCIWFIRSTPRIV + 14) -#define PRISM2_IOCTL_MACCMD (SIOCIWFIRSTPRIV + 16) -#define PRISM2_IOCTL_ADDMAC (SIOCIWFIRSTPRIV + 18) -#define PRISM2_IOCTL_DELMAC (SIOCIWFIRSTPRIV + 20) -#define PRISM2_IOCTL_KICKMAC (SIOCIWFIRSTPRIV + 22) - -/* following are not in SIOCGIWPRIV list; check permission in the driver code - */ -#define PRISM2_IOCTL_DOWNLOAD (SIOCDEVPRIVATE + 13) -#define PRISM2_IOCTL_HOSTAPD (SIOCDEVPRIVATE + 14) - - -/* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes: */ -enum { - /* PRISM2_PARAM_PTYPE = 1, */ /* REMOVED 2003-10-22 */ - PRISM2_PARAM_TXRATECTRL = 2, - PRISM2_PARAM_BEACON_INT = 3, - PRISM2_PARAM_PSEUDO_IBSS = 4, - PRISM2_PARAM_ALC = 5, - /* PRISM2_PARAM_TXPOWER = 6, */ /* REMOVED 2003-10-22 */ - PRISM2_PARAM_DUMP = 7, - PRISM2_PARAM_OTHER_AP_POLICY = 8, - PRISM2_PARAM_AP_MAX_INACTIVITY = 9, - PRISM2_PARAM_AP_BRIDGE_PACKETS = 10, - PRISM2_PARAM_DTIM_PERIOD = 11, - PRISM2_PARAM_AP_NULLFUNC_ACK = 12, - PRISM2_PARAM_MAX_WDS = 13, - PRISM2_PARAM_AP_AUTOM_AP_WDS = 14, - PRISM2_PARAM_AP_AUTH_ALGS = 15, - PRISM2_PARAM_MONITOR_ALLOW_FCSERR = 16, - PRISM2_PARAM_HOST_ENCRYPT = 17, - PRISM2_PARAM_HOST_DECRYPT = 18, - /* PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX = 19, REMOVED 2005-08-14 */ - /* PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX = 20, REMOVED 2005-08-14 */ - PRISM2_PARAM_HOST_ROAMING = 21, - PRISM2_PARAM_BCRX_STA_KEY = 22, - PRISM2_PARAM_IEEE_802_1X = 23, - PRISM2_PARAM_ANTSEL_TX = 24, - PRISM2_PARAM_ANTSEL_RX = 25, - PRISM2_PARAM_MONITOR_TYPE = 26, - PRISM2_PARAM_WDS_TYPE = 27, - PRISM2_PARAM_HOSTSCAN = 28, - PRISM2_PARAM_AP_SCAN = 29, - PRISM2_PARAM_ENH_SEC = 30, - PRISM2_PARAM_IO_DEBUG = 31, - PRISM2_PARAM_BASIC_RATES = 32, - PRISM2_PARAM_OPER_RATES = 33, - PRISM2_PARAM_HOSTAPD = 34, - PRISM2_PARAM_HOSTAPD_STA = 35, - PRISM2_PARAM_WPA = 36, - PRISM2_PARAM_PRIVACY_INVOKED = 37, - PRISM2_PARAM_TKIP_COUNTERMEASURES = 38, - PRISM2_PARAM_DROP_UNENCRYPTED = 39, - PRISM2_PARAM_SCAN_CHANNEL_MASK = 40, -}; - -enum { HOSTAP_ANTSEL_DO_NOT_TOUCH = 0, HOSTAP_ANTSEL_DIVERSITY = 1, - HOSTAP_ANTSEL_LOW = 2, HOSTAP_ANTSEL_HIGH = 3 }; - - -/* PRISM2_IOCTL_MACCMD ioctl() subcommands: */ -enum { AP_MAC_CMD_POLICY_OPEN = 0, AP_MAC_CMD_POLICY_ALLOW = 1, - AP_MAC_CMD_POLICY_DENY = 2, AP_MAC_CMD_FLUSH = 3, - AP_MAC_CMD_KICKALL = 4 }; - - -/* PRISM2_IOCTL_DOWNLOAD ioctl() dl_cmd: */ -enum { - PRISM2_DOWNLOAD_VOLATILE = 1 /* RAM */, - /* Note! Old versions of prism2_srec have a fatal error in CRC-16 - * calculation, which will corrupt all non-volatile downloads. - * PRISM2_DOWNLOAD_NON_VOLATILE used to be 2, but it is now 3 to - * prevent use of old versions of prism2_srec for non-volatile - * download. */ - PRISM2_DOWNLOAD_NON_VOLATILE = 3 /* FLASH */, - PRISM2_DOWNLOAD_VOLATILE_GENESIS = 4 /* RAM in Genesis mode */, - /* Persistent versions of volatile download commands (keep firmware - * data in memory and automatically re-download after hw_reset */ - PRISM2_DOWNLOAD_VOLATILE_PERSISTENT = 5, - PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT = 6, -}; - -struct prism2_download_param { - u32 dl_cmd; - u32 start_addr; - u32 num_areas; - struct prism2_download_area { - u32 addr; /* wlan card address */ - u32 len; - void __user *ptr; /* pointer to data in user space */ - } data[]; -}; - -#define PRISM2_MAX_DOWNLOAD_AREA_LEN 131072 -#define PRISM2_MAX_DOWNLOAD_LEN 262144 - - -/* PRISM2_IOCTL_HOSTAPD ioctl() cmd: */ -enum { - PRISM2_HOSTAPD_FLUSH = 1, - PRISM2_HOSTAPD_ADD_STA = 2, - PRISM2_HOSTAPD_REMOVE_STA = 3, - PRISM2_HOSTAPD_GET_INFO_STA = 4, - /* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */ - PRISM2_SET_ENCRYPTION = 6, - PRISM2_GET_ENCRYPTION = 7, - PRISM2_HOSTAPD_SET_FLAGS_STA = 8, - PRISM2_HOSTAPD_GET_RID = 9, - PRISM2_HOSTAPD_SET_RID = 10, - PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR = 11, - PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12, - PRISM2_HOSTAPD_MLME = 13, - PRISM2_HOSTAPD_SCAN_REQ = 14, - PRISM2_HOSTAPD_STA_CLEAR_STATS = 15, -}; - -#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024 -#define PRISM2_HOSTAPD_RID_HDR_LEN \ -offsetof(struct prism2_hostapd_param, u.rid.data) -#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \ -offsetof(struct prism2_hostapd_param, u.generic_elem.data) - -/* Maximum length for algorithm names (-1 for nul termination) used in ioctl() - */ -#define HOSTAP_CRYPT_ALG_NAME_LEN 16 - - -struct prism2_hostapd_param { - u32 cmd; - u8 sta_addr[ETH_ALEN]; - union { - struct { - u16 aid; - u16 capability; - u8 tx_supp_rates; - } add_sta; - struct { - u32 inactive_sec; - } get_info_sta; - struct { - u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN]; - u32 flags; - u32 err; - u8 idx; - u8 seq[8]; /* sequence counter (set: RX, get: TX) */ - u16 key_len; - u8 key[0]; - } crypt; - struct { - u32 flags_and; - u32 flags_or; - } set_flags_sta; - struct { - u16 rid; - u16 len; - u8 data[0]; - } rid; - struct { - u8 len; - u8 data[0]; - } generic_elem; - struct { -#define MLME_STA_DEAUTH 0 -#define MLME_STA_DISASSOC 1 - u16 cmd; - u16 reason_code; - } mlme; - struct { - u8 ssid_len; - u8 ssid[32]; - } scan_req; - } u; -}; - -#define HOSTAP_CRYPT_FLAG_SET_TX_KEY BIT(0) -#define HOSTAP_CRYPT_FLAG_PERMANENT BIT(1) - -#define HOSTAP_CRYPT_ERR_UNKNOWN_ALG 2 -#define HOSTAP_CRYPT_ERR_UNKNOWN_ADDR 3 -#define HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED 4 -#define HOSTAP_CRYPT_ERR_KEY_SET_FAILED 5 -#define HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED 6 -#define HOSTAP_CRYPT_ERR_CARD_CONF_FAILED 7 - - -#endif /* HOSTAP_COMMON_H */ diff --git a/drivers/net/wireless/intersil/hostap/hostap_config.h b/drivers/net/wireless/intersil/hostap/hostap_config.h deleted file mode 100644 index 3ebd55847fad3..0000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_config.h +++ /dev/null @@ -1,49 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef HOSTAP_CONFIG_H -#define HOSTAP_CONFIG_H - -/* In the previous versions of Host AP driver, support for user space version - * of IEEE 802.11 management (hostapd) used to be disabled in the default - * configuration. From now on, support for hostapd is always included and it is - * possible to disable kernel driver version of IEEE 802.11 management with a - * separate define, PRISM2_NO_KERNEL_IEEE80211_MGMT. */ -/* #define PRISM2_NO_KERNEL_IEEE80211_MGMT */ - -/* Maximum number of events handler per one interrupt */ -#define PRISM2_MAX_INTERRUPT_EVENTS 20 - -/* Include code for downloading firmware images into volatile RAM. */ -#define PRISM2_DOWNLOAD_SUPPORT - -/* Allow kernel configuration to enable download support. */ -#if !defined(PRISM2_DOWNLOAD_SUPPORT) && defined(CONFIG_HOSTAP_FIRMWARE) -#define PRISM2_DOWNLOAD_SUPPORT -#endif - -/* Allow kernel configuration to enable non-volatile download support. */ -#ifdef CONFIG_HOSTAP_FIRMWARE_NVRAM -#define PRISM2_NON_VOLATILE_DOWNLOAD -#endif - -/* Save low-level I/O for debugging. This should not be enabled in normal use. - */ -/* #define PRISM2_IO_DEBUG */ - -/* Following defines can be used to remove unneeded parts of the driver, e.g., - * to limit the size of the kernel module. Definitions can be added here in - * hostap_config.h or they can be added to make command with ccflags-y, - * e.g., - * 'make pccard ccflags-y="-DPRISM2_NO_DEBUG -DPRISM2_NO_PROCFS_DEBUG"' - */ - -/* Do not include debug messages into the driver */ -/* #define PRISM2_NO_DEBUG */ - -/* Do not include /proc/net/prism2/wlan#/{registers,debug} */ -/* #define PRISM2_NO_PROCFS_DEBUG */ - -/* Do not include station functionality (i.e., allow only Master (Host AP) mode - */ -/* #define PRISM2_NO_STATION_MODES */ - -#endif /* HOSTAP_CONFIG_H */ diff --git a/drivers/net/wireless/intersil/hostap/hostap_cs.c b/drivers/net/wireless/intersil/hostap/hostap_cs.c deleted file mode 100644 index ec7db2badc40e..0000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_cs.c +++ /dev/null @@ -1,710 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -#define PRISM2_PCCARD - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include "hostap_wlan.h" - - -static char *dev_info = "hostap_cs"; - -MODULE_AUTHOR("Jouni Malinen"); -MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN " - "cards (PC Card)."); -MODULE_LICENSE("GPL"); - - -static int ignore_cis_vcc; -module_param(ignore_cis_vcc, int, 0444); -MODULE_PARM_DESC(ignore_cis_vcc, "Ignore broken CIS VCC entry"); - - -/* struct local_info::hw_priv */ -struct hostap_cs_priv { - struct pcmcia_device *link; - int sandisk_connectplus; -}; - - -#ifdef PRISM2_IO_DEBUG - -static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - - iface = netdev_priv(dev); - local = iface->local; - spin_lock_irqsave(&local->lock, flags); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v); - outb(v, dev->base_addr + a); - spin_unlock_irqrestore(&local->lock, flags); -} - -static inline u8 hfa384x_inb_debug(struct net_device *dev, int a) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - u8 v; - - iface = netdev_priv(dev); - local = iface->local; - spin_lock_irqsave(&local->lock, flags); - v = inb(dev->base_addr + a); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v); - spin_unlock_irqrestore(&local->lock, flags); - return v; -} - -static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - - iface = netdev_priv(dev); - local = iface->local; - spin_lock_irqsave(&local->lock, flags); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v); - outw(v, dev->base_addr + a); - spin_unlock_irqrestore(&local->lock, flags); -} - -static inline u16 hfa384x_inw_debug(struct net_device *dev, int a) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - u16 v; - - iface = netdev_priv(dev); - local = iface->local; - spin_lock_irqsave(&local->lock, flags); - v = inw(dev->base_addr + a); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v); - spin_unlock_irqrestore(&local->lock, flags); - return v; -} - -static inline void hfa384x_outsw_debug(struct net_device *dev, int a, - u8 *buf, int wc) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - - iface = netdev_priv(dev); - local = iface->local; - spin_lock_irqsave(&local->lock, flags); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc); - outsw(dev->base_addr + a, buf, wc); - spin_unlock_irqrestore(&local->lock, flags); -} - -static inline void hfa384x_insw_debug(struct net_device *dev, int a, - u8 *buf, int wc) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - - iface = netdev_priv(dev); - local = iface->local; - spin_lock_irqsave(&local->lock, flags); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc); - insw(dev->base_addr + a, buf, wc); - spin_unlock_irqrestore(&local->lock, flags); -} - -#define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v)) -#define HFA384X_INB(a) hfa384x_inb_debug(dev, (a)) -#define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v)) -#define HFA384X_INW(a) hfa384x_inw_debug(dev, (a)) -#define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc)) -#define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc)) - -#else /* PRISM2_IO_DEBUG */ - -#define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a)) -#define HFA384X_INB(a) inb(dev->base_addr + (a)) -#define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a)) -#define HFA384X_INW(a) inw(dev->base_addr + (a)) -#define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc) -#define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc) - -#endif /* PRISM2_IO_DEBUG */ - - -static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf, - int len) -{ - u16 d_off; - u16 *pos; - - d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; - pos = (u16 *) buf; - - if (len / 2) - HFA384X_INSW(d_off, buf, len / 2); - pos += len / 2; - - if (len & 1) - *((char *) pos) = HFA384X_INB(d_off); - - return 0; -} - - -static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len) -{ - u16 d_off; - u16 *pos; - - d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; - pos = (u16 *) buf; - - if (len / 2) - HFA384X_OUTSW(d_off, buf, len / 2); - pos += len / 2; - - if (len & 1) - HFA384X_OUTB(*((char *) pos), d_off); - - return 0; -} - - -/* FIX: This might change at some point.. */ -#include "hostap_hw.c" - - - -static void prism2_detach(struct pcmcia_device *p_dev); -static void prism2_release(u_long arg); -static int prism2_config(struct pcmcia_device *link); - - -static int prism2_pccard_card_present(local_info_t *local) -{ - struct hostap_cs_priv *hw_priv = local->hw_priv; - if (hw_priv != NULL && hw_priv->link != NULL && pcmcia_dev_present(hw_priv->link)) - return 1; - return 0; -} - - -/* - * SanDisk CompactFlash WLAN Flashcard - Product Manual v1.0 - * Document No. 20-10-00058, January 2004 - * http://www.sandisk.com/pdf/industrial/ProdManualCFWLANv1.0.pdf - */ -#define SANDISK_WLAN_ACTIVATION_OFF 0x40 -#define SANDISK_HCR_OFF 0x42 - - -static void sandisk_set_iobase(local_info_t *local) -{ - int res; - struct hostap_cs_priv *hw_priv = local->hw_priv; - - res = pcmcia_write_config_byte(hw_priv->link, 0x10, - hw_priv->link->resource[0]->start & 0x00ff); - if (res != 0) { - printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 0 -" - " res=%d\n", res); - } - udelay(10); - - res = pcmcia_write_config_byte(hw_priv->link, 0x12, - (hw_priv->link->resource[0]->start >> 8) & 0x00ff); - if (res != 0) { - printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 1 -" - " res=%d\n", res); - } -} - - -static void sandisk_write_hcr(local_info_t *local, int hcr) -{ - struct net_device *dev = local->dev; - int i; - - HFA384X_OUTB(0x80, SANDISK_WLAN_ACTIVATION_OFF); - udelay(50); - for (i = 0; i < 10; i++) { - HFA384X_OUTB(hcr, SANDISK_HCR_OFF); - } - udelay(55); - HFA384X_OUTB(0x45, SANDISK_WLAN_ACTIVATION_OFF); -} - - -static int sandisk_enable_wireless(struct net_device *dev) -{ - int res, ret = 0; - struct hostap_interface *iface = netdev_priv(dev); - local_info_t *local = iface->local; - struct hostap_cs_priv *hw_priv = local->hw_priv; - - if (resource_size(hw_priv->link->resource[0]) < 0x42) { - /* Not enough ports to be SanDisk multi-function card */ - ret = -ENODEV; - goto done; - } - - if (hw_priv->link->manf_id != 0xd601 || hw_priv->link->card_id != 0x0101) { - /* No SanDisk manfid found */ - ret = -ENODEV; - goto done; - } - - if (hw_priv->link->socket->functions < 2) { - /* No multi-function links found */ - ret = -ENODEV; - goto done; - } - - printk(KERN_DEBUG "%s: Multi-function SanDisk ConnectPlus detected" - " - using vendor-specific initialization\n", dev->name); - hw_priv->sandisk_connectplus = 1; - - res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, - COR_SOFT_RESET); - if (res != 0) { - printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n", - dev->name, res); - goto done; - } - mdelay(5); - - /* - * Do not enable interrupts here to avoid some bogus events. Interrupts - * will be enabled during the first cor_sreset call. - */ - res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, - (COR_LEVEL_REQ | 0x8 | COR_ADDR_DECODE | - COR_FUNC_ENA)); - if (res != 0) { - printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n", - dev->name, res); - goto done; - } - mdelay(5); - - sandisk_set_iobase(local); - - HFA384X_OUTB(0xc5, SANDISK_WLAN_ACTIVATION_OFF); - udelay(10); - HFA384X_OUTB(0x4b, SANDISK_WLAN_ACTIVATION_OFF); - udelay(10); - -done: - return ret; -} - - -static void prism2_pccard_cor_sreset(local_info_t *local) -{ - int res; - u8 val; - struct hostap_cs_priv *hw_priv = local->hw_priv; - - if (!prism2_pccard_card_present(local)) - return; - - res = pcmcia_read_config_byte(hw_priv->link, CISREG_COR, &val); - if (res != 0) { - printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 1 (%d)\n", - res); - return; - } - printk(KERN_DEBUG "prism2_pccard_cor_sreset: original COR %02x\n", - val); - - val |= COR_SOFT_RESET; - res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, val); - if (res != 0) { - printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 2 (%d)\n", - res); - return; - } - - mdelay(hw_priv->sandisk_connectplus ? 5 : 2); - - val &= ~COR_SOFT_RESET; - if (hw_priv->sandisk_connectplus) - val |= COR_IREQ_ENA; - res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, val); - if (res != 0) { - printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 3 (%d)\n", - res); - return; - } - - mdelay(hw_priv->sandisk_connectplus ? 5 : 2); - - if (hw_priv->sandisk_connectplus) - sandisk_set_iobase(local); -} - - -static void prism2_pccard_genesis_reset(local_info_t *local, int hcr) -{ - int res; - u8 old_cor; - struct hostap_cs_priv *hw_priv = local->hw_priv; - - if (!prism2_pccard_card_present(local)) - return; - - if (hw_priv->sandisk_connectplus) { - sandisk_write_hcr(local, hcr); - return; - } - - res = pcmcia_read_config_byte(hw_priv->link, CISREG_COR, &old_cor); - if (res != 0) { - printk(KERN_DEBUG "%s failed 1 (%d)\n", __func__, res); - return; - } - printk(KERN_DEBUG "%s: original COR %02x\n", __func__, old_cor); - - res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, - old_cor | COR_SOFT_RESET); - if (res != 0) { - printk(KERN_DEBUG "%s failed 2 (%d)\n", __func__, res); - return; - } - - mdelay(10); - - /* Setup Genesis mode */ - res = pcmcia_write_config_byte(hw_priv->link, CISREG_CCSR, hcr); - if (res != 0) { - printk(KERN_DEBUG "%s failed 3 (%d)\n", __func__, res); - return; - } - mdelay(10); - - res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, - old_cor & ~COR_SOFT_RESET); - if (res != 0) { - printk(KERN_DEBUG "%s failed 4 (%d)\n", __func__, res); - return; - } - - mdelay(10); -} - - -static struct prism2_helper_functions prism2_pccard_funcs = -{ - .card_present = prism2_pccard_card_present, - .cor_sreset = prism2_pccard_cor_sreset, - .genesis_reset = prism2_pccard_genesis_reset, - .hw_type = HOSTAP_HW_PCCARD, -}; - - -/* allocate local data and register with CardServices - * initialize dev_link structure, but do not configure the card yet */ -static int hostap_cs_probe(struct pcmcia_device *p_dev) -{ - int ret; - - PDEBUG(DEBUG_HW, "%s: setting Vcc=33 (constant)\n", dev_info); - - ret = prism2_config(p_dev); - if (ret) { - PDEBUG(DEBUG_EXTRA, "prism2_config() failed\n"); - } - - return ret; -} - - -static void prism2_detach(struct pcmcia_device *link) -{ - PDEBUG(DEBUG_FLOW, "prism2_detach\n"); - - prism2_release((u_long)link); - - /* release net devices */ - if (link->priv) { - struct hostap_cs_priv *hw_priv; - struct net_device *dev; - struct hostap_interface *iface; - dev = link->priv; - iface = netdev_priv(dev); - hw_priv = iface->local->hw_priv; - prism2_free_local_data(dev); - kfree(hw_priv); - } -} - - -static int prism2_config_check(struct pcmcia_device *p_dev, void *priv_data) -{ - if (p_dev->config_index == 0) - return -EINVAL; - - return pcmcia_request_io(p_dev); -} - -static int prism2_config(struct pcmcia_device *link) -{ - struct net_device *dev; - struct hostap_interface *iface; - local_info_t *local; - int ret; - struct hostap_cs_priv *hw_priv; - unsigned long flags; - - PDEBUG(DEBUG_FLOW, "prism2_config()\n"); - - hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL); - if (hw_priv == NULL) { - ret = -ENOMEM; - goto failed; - } - - /* Look for an appropriate configuration table entry in the CIS */ - link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_AUDIO | - CONF_AUTO_CHECK_VCC | CONF_AUTO_SET_IO | CONF_ENABLE_IRQ; - if (ignore_cis_vcc) - link->config_flags &= ~CONF_AUTO_CHECK_VCC; - ret = pcmcia_loop_config(link, prism2_config_check, NULL); - if (ret) { - if (!ignore_cis_vcc) - printk(KERN_ERR "GetNextTuple(): No matching " - "CIS configuration. Maybe you need the " - "ignore_cis_vcc=1 parameter.\n"); - goto failed; - } - - /* Need to allocate net_device before requesting IRQ handler */ - dev = prism2_init_local_data(&prism2_pccard_funcs, 0, - &link->dev); - if (!dev) { - ret = -ENOMEM; - goto failed; - } - link->priv = dev; - - iface = netdev_priv(dev); - local = iface->local; - local->hw_priv = hw_priv; - hw_priv->link = link; - - /* - * We enable IRQ here, but IRQ handler will not proceed - * until dev->base_addr is set below. This protect us from - * receive interrupts when driver is not initialized. - */ - ret = pcmcia_request_irq(link, prism2_interrupt); - if (ret) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - spin_lock_irqsave(&local->irq_init_lock, flags); - dev->irq = link->irq; - dev->base_addr = link->resource[0]->start; - spin_unlock_irqrestore(&local->irq_init_lock, flags); - - local->shutdown = 0; - - sandisk_enable_wireless(dev); - - ret = prism2_hw_config(dev, 1); - if (!ret) - ret = hostap_hw_ready(dev); - - return ret; - - failed: - kfree(hw_priv); - prism2_release((u_long)link); - return ret; -} - - -static void prism2_release(u_long arg) -{ - struct pcmcia_device *link = (struct pcmcia_device *)arg; - - PDEBUG(DEBUG_FLOW, "prism2_release\n"); - - if (link->priv) { - struct net_device *dev = link->priv; - struct hostap_interface *iface; - - iface = netdev_priv(dev); - prism2_hw_shutdown(dev, 0); - iface->local->shutdown = 1; - } - - pcmcia_disable_device(link); - PDEBUG(DEBUG_FLOW, "release - done\n"); -} - -static int hostap_cs_suspend(struct pcmcia_device *link) -{ - struct net_device *dev = (struct net_device *) link->priv; - int dev_open = 0; - struct hostap_interface *iface = NULL; - - if (!dev) - return -ENODEV; - - iface = netdev_priv(dev); - - PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_SUSPEND\n", dev_info); - if (iface && iface->local) - dev_open = iface->local->num_dev_open > 0; - if (dev_open) { - netif_stop_queue(dev); - netif_device_detach(dev); - } - prism2_suspend(dev); - - return 0; -} - -static int hostap_cs_resume(struct pcmcia_device *link) -{ - struct net_device *dev = (struct net_device *) link->priv; - int dev_open = 0; - struct hostap_interface *iface = NULL; - - if (!dev) - return -ENODEV; - - iface = netdev_priv(dev); - - PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_RESUME\n", dev_info); - - if (iface && iface->local) - dev_open = iface->local->num_dev_open > 0; - - prism2_hw_shutdown(dev, 1); - prism2_hw_config(dev, dev_open ? 0 : 1); - if (dev_open) { - netif_device_attach(dev); - netif_start_queue(dev); - } - - return 0; -} - -static const struct pcmcia_device_id hostap_cs_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100), - PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300), - PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), - PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000), - PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x3301), - PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0x026f, 0x030b), - PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612), - PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613), - PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0x02d2, 0x0001), - PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x0001), - PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300), -/* PCMCIA_DEVICE_MANF_CARD(0xc00f, 0x0000), conflict with pcnet_cs */ - PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005), - PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0010), - PCMCIA_DEVICE_MANF_CARD(0x0126, 0x0002), - PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0xd601, 0x0005, "ADLINK 345 CF", - 0x2d858104), - PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "INTERSIL", - 0x74c5e40d), - PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "Intersil", - 0x4b801a17), - PCMCIA_DEVICE_MANF_CARD_PROD_ID3(0x0156, 0x0002, "Version 01.02", - 0x4b74baa0), - PCMCIA_MFC_DEVICE_PROD_ID12(0, "SanDisk", "ConnectPlus", - 0x7a954bd9, 0x74be00c6), - PCMCIA_DEVICE_PROD_ID123( - "Addtron", "AWP-100 Wireless PCMCIA", "Version 01.02", - 0xe6ec52ce, 0x08649af2, 0x4b74baa0), - PCMCIA_DEVICE_PROD_ID123( - "Canon", "Wireless LAN CF Card K30225", "Version 01.00", - 0x96ef6fe2, 0x263fcbab, 0xa57adb8c), - PCMCIA_DEVICE_PROD_ID123( - "D", "Link DWL-650 11Mbps WLAN Card", "Version 01.02", - 0x71b18589, 0xb6f1b0ab, 0x4b74baa0), - PCMCIA_DEVICE_PROD_ID123( - "Instant Wireless ", " Network PC CARD", "Version 01.02", - 0x11d901af, 0x6e9bd926, 0x4b74baa0), - PCMCIA_DEVICE_PROD_ID123( - "SMC", "SMC2632W", "Version 01.02", - 0xc4f8b18b, 0x474a1f2a, 0x4b74baa0), - PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G", - 0x2decece3, 0x82067c18), - PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card", - 0x54f7c49c, 0x15a75e5b), - PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE", - 0x74c5e40d, 0xdb472a18), - PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card", - 0x0733cc81, 0x0c52f395), - PCMCIA_DEVICE_PROD_ID12( - "ZoomAir 11Mbps High", "Rate wireless Networking", - 0x273fe3db, 0x32a1eaee), - PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401 Wireless PC", "Card", - 0xa37434e9, 0x9762e8f1), - PCMCIA_DEVICE_PROD_ID123( - "Pretec", "CompactWLAN Card 802.11b", "2.5", - 0x1cadd3e5, 0xe697636c, 0x7a5bfcf1), - PCMCIA_DEVICE_PROD_ID123( - "U.S. Robotics", "IEEE 802.11b PC-CARD", "Version 01.02", - 0xc7b8df9d, 0x1700d087, 0x4b74baa0), - PCMCIA_DEVICE_PROD_ID123( - "Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio", - "Ver. 1.00", - 0x5cd01705, 0x4271660f, 0x9d08ee12), - PCMCIA_DEVICE_PROD_ID123( - "Wireless LAN" , "11Mbps PC Card", "Version 01.02", - 0x4b8870ff, 0x70e946d1, 0x4b74baa0), - PCMCIA_DEVICE_PROD_ID3("HFA3863", 0x355cb092), - PCMCIA_DEVICE_PROD_ID3("ISL37100P", 0x630d52b2), - PCMCIA_DEVICE_PROD_ID3("ISL37101P-10", 0xdd97a26b), - PCMCIA_DEVICE_PROD_ID3("ISL37300P", 0xc9049a39), - PCMCIA_DEVICE_NULL -}; -MODULE_DEVICE_TABLE(pcmcia, hostap_cs_ids); - - -static struct pcmcia_driver hostap_driver = { - .name = "hostap_cs", - .probe = hostap_cs_probe, - .remove = prism2_detach, - .owner = THIS_MODULE, - .id_table = hostap_cs_ids, - .suspend = hostap_cs_suspend, - .resume = hostap_cs_resume, -}; -module_pcmcia_driver(hostap_driver); diff --git a/drivers/net/wireless/intersil/hostap/hostap_download.c b/drivers/net/wireless/intersil/hostap/hostap_download.c deleted file mode 100644 index 5e5bada28b5b9..0000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_download.c +++ /dev/null @@ -1,810 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -static int prism2_enable_aux_port(struct net_device *dev, int enable) -{ - u16 val, reg; - int i, tries; - unsigned long flags; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->no_pri) { - if (enable) { - PDEBUG(DEBUG_EXTRA2, "%s: no PRI f/w - assuming Aux " - "port is already enabled\n", dev->name); - } - return 0; - } - - spin_lock_irqsave(&local->cmdlock, flags); - - /* wait until busy bit is clear */ - tries = HFA384X_CMD_BUSY_TIMEOUT; - while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) { - tries--; - udelay(1); - } - if (tries == 0) { - reg = HFA384X_INW(HFA384X_CMD_OFF); - spin_unlock_irqrestore(&local->cmdlock, flags); - printk("%s: prism2_enable_aux_port - timeout - reg=0x%04x\n", - dev->name, reg); - return -ETIMEDOUT; - } - - val = HFA384X_INW(HFA384X_CONTROL_OFF); - - if (enable) { - HFA384X_OUTW(HFA384X_AUX_MAGIC0, HFA384X_PARAM0_OFF); - HFA384X_OUTW(HFA384X_AUX_MAGIC1, HFA384X_PARAM1_OFF); - HFA384X_OUTW(HFA384X_AUX_MAGIC2, HFA384X_PARAM2_OFF); - - if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_DISABLED) - printk("prism2_enable_aux_port: was not disabled!?\n"); - val &= ~HFA384X_AUX_PORT_MASK; - val |= HFA384X_AUX_PORT_ENABLE; - } else { - HFA384X_OUTW(0, HFA384X_PARAM0_OFF); - HFA384X_OUTW(0, HFA384X_PARAM1_OFF); - HFA384X_OUTW(0, HFA384X_PARAM2_OFF); - - if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_ENABLED) - printk("prism2_enable_aux_port: was not enabled!?\n"); - val &= ~HFA384X_AUX_PORT_MASK; - val |= HFA384X_AUX_PORT_DISABLE; - } - HFA384X_OUTW(val, HFA384X_CONTROL_OFF); - - udelay(5); - - i = 10000; - while (i > 0) { - val = HFA384X_INW(HFA384X_CONTROL_OFF); - val &= HFA384X_AUX_PORT_MASK; - - if ((enable && val == HFA384X_AUX_PORT_ENABLED) || - (!enable && val == HFA384X_AUX_PORT_DISABLED)) - break; - - udelay(10); - i--; - } - - spin_unlock_irqrestore(&local->cmdlock, flags); - - if (i == 0) { - printk("prism2_enable_aux_port(%d) timed out\n", - enable); - return -ETIMEDOUT; - } - - return 0; -} - - -static int hfa384x_from_aux(struct net_device *dev, unsigned int addr, int len, - void *buf) -{ - u16 page, offset; - if (addr & 1 || len & 1) - return -1; - - page = addr >> 7; - offset = addr & 0x7f; - - HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF); - HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF); - - udelay(5); - -#ifdef PRISM2_PCI - { - __le16 *pos = (__le16 *) buf; - while (len > 0) { - *pos++ = HFA384X_INW_DATA(HFA384X_AUXDATA_OFF); - len -= 2; - } - } -#else /* PRISM2_PCI */ - HFA384X_INSW(HFA384X_AUXDATA_OFF, buf, len / 2); -#endif /* PRISM2_PCI */ - - return 0; -} - - -static int hfa384x_to_aux(struct net_device *dev, unsigned int addr, int len, - void *buf) -{ - u16 page, offset; - if (addr & 1 || len & 1) - return -1; - - page = addr >> 7; - offset = addr & 0x7f; - - HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF); - HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF); - - udelay(5); - -#ifdef PRISM2_PCI - { - __le16 *pos = (__le16 *) buf; - while (len > 0) { - HFA384X_OUTW_DATA(*pos++, HFA384X_AUXDATA_OFF); - len -= 2; - } - } -#else /* PRISM2_PCI */ - HFA384X_OUTSW(HFA384X_AUXDATA_OFF, buf, len / 2); -#endif /* PRISM2_PCI */ - - return 0; -} - - -static int prism2_pda_ok(u8 *buf) -{ - __le16 *pda = (__le16 *) buf; - int pos; - u16 len, pdr; - - if (buf[0] == 0xff && buf[1] == 0x00 && buf[2] == 0xff && - buf[3] == 0x00) - return 0; - - pos = 0; - while (pos + 1 < PRISM2_PDA_SIZE / 2) { - len = le16_to_cpu(pda[pos]); - pdr = le16_to_cpu(pda[pos + 1]); - if (len == 0 || pos + len > PRISM2_PDA_SIZE / 2) - return 0; - - if (pdr == 0x0000 && len == 2) { - /* PDA end found */ - return 1; - } - - pos += len + 1; - } - - return 0; -} - - -#define prism2_download_aux_dump_npages 65536 - -struct prism2_download_aux_dump { - local_info_t *local; - u16 page[0x80]; -}; - -static int prism2_download_aux_dump_proc_show(struct seq_file *m, void *v) -{ - struct prism2_download_aux_dump *ctx = m->private; - - hfa384x_from_aux(ctx->local->dev, (unsigned long)v - 1, 0x80, ctx->page); - seq_write(m, ctx->page, 0x80); - return 0; -} - -static void *prism2_download_aux_dump_proc_start(struct seq_file *m, loff_t *_pos) -{ - struct prism2_download_aux_dump *ctx = m->private; - prism2_enable_aux_port(ctx->local->dev, 1); - if (*_pos >= prism2_download_aux_dump_npages) - return NULL; - return (void *)((unsigned long)*_pos + 1); -} - -static void *prism2_download_aux_dump_proc_next(struct seq_file *m, void *v, loff_t *_pos) -{ - ++*_pos; - if (*_pos >= prism2_download_aux_dump_npages) - return NULL; - return (void *)((unsigned long)*_pos + 1); -} - -static void prism2_download_aux_dump_proc_stop(struct seq_file *m, void *v) -{ - struct prism2_download_aux_dump *ctx = m->private; - prism2_enable_aux_port(ctx->local->dev, 0); -} - -static const struct seq_operations prism2_download_aux_dump_proc_seqops = { - .start = prism2_download_aux_dump_proc_start, - .next = prism2_download_aux_dump_proc_next, - .stop = prism2_download_aux_dump_proc_stop, - .show = prism2_download_aux_dump_proc_show, -}; - -static int prism2_download_aux_dump_proc_open(struct inode *inode, struct file *file) -{ - int ret = seq_open_private(file, &prism2_download_aux_dump_proc_seqops, - sizeof(struct prism2_download_aux_dump)); - if (ret == 0) { - struct seq_file *m = file->private_data; - m->private = pde_data(inode); - } - return ret; -} - -static const struct proc_ops prism2_download_aux_dump_proc_ops = { - .proc_open = prism2_download_aux_dump_proc_open, - .proc_read = seq_read, - .proc_lseek = seq_lseek, - .proc_release = seq_release_private, -}; - - -static u8 * prism2_read_pda(struct net_device *dev) -{ - u8 *buf; - int res, i, found = 0; -#define NUM_PDA_ADDRS 4 - unsigned int pda_addr[NUM_PDA_ADDRS] = { - 0x7f0000 /* others than HFA3841 */, - 0x3f0000 /* HFA3841 */, - 0x390000 /* apparently used in older cards */, - 0x7f0002 /* Intel PRO/Wireless 2011B (PCI) */, - }; - - buf = kmalloc(PRISM2_PDA_SIZE, GFP_KERNEL); - if (buf == NULL) - return NULL; - - /* Note: wlan card should be in initial state (just after init cmd) - * and no other operations should be performed concurrently. */ - - prism2_enable_aux_port(dev, 1); - - for (i = 0; i < NUM_PDA_ADDRS; i++) { - PDEBUG(DEBUG_EXTRA2, "%s: trying to read PDA from 0x%08x", - dev->name, pda_addr[i]); - res = hfa384x_from_aux(dev, pda_addr[i], PRISM2_PDA_SIZE, buf); - if (res) - continue; - if (res == 0 && prism2_pda_ok(buf)) { - PDEBUG2(DEBUG_EXTRA2, ": OK\n"); - found = 1; - break; - } else { - PDEBUG2(DEBUG_EXTRA2, ": failed\n"); - } - } - - prism2_enable_aux_port(dev, 0); - - if (!found) { - printk(KERN_DEBUG "%s: valid PDA not found\n", dev->name); - kfree(buf); - buf = NULL; - } - - return buf; -} - - -static int prism2_download_volatile(local_info_t *local, - struct prism2_download_data *param) -{ - struct net_device *dev = local->dev; - int ret = 0, i; - u16 param0, param1; - - if (local->hw_downloading) { - printk(KERN_WARNING "%s: Already downloading - aborting new " - "request\n", dev->name); - return -1; - } - - local->hw_downloading = 1; - if (local->pri_only) { - hfa384x_disable_interrupts(dev); - } else { - prism2_hw_shutdown(dev, 0); - - if (prism2_hw_init(dev, 0)) { - printk(KERN_WARNING "%s: Could not initialize card for" - " download\n", dev->name); - ret = -1; - goto out; - } - } - - if (prism2_enable_aux_port(dev, 1)) { - printk(KERN_WARNING "%s: Could not enable AUX port\n", - dev->name); - ret = -1; - goto out; - } - - param0 = param->start_addr & 0xffff; - param1 = param->start_addr >> 16; - - HFA384X_OUTW(0, HFA384X_PARAM2_OFF); - HFA384X_OUTW(param1, HFA384X_PARAM1_OFF); - if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD | - (HFA384X_PROGMODE_ENABLE_VOLATILE << 8), - param0)) { - printk(KERN_WARNING "%s: Download command execution failed\n", - dev->name); - ret = -1; - goto out; - } - - for (i = 0; i < param->num_areas; i++) { - PDEBUG(DEBUG_EXTRA2, "%s: Writing %d bytes at 0x%08x\n", - dev->name, param->data[i].len, param->data[i].addr); - if (hfa384x_to_aux(dev, param->data[i].addr, - param->data[i].len, param->data[i].data)) { - printk(KERN_WARNING "%s: RAM download at 0x%08x " - "(len=%d) failed\n", dev->name, - param->data[i].addr, param->data[i].len); - ret = -1; - goto out; - } - } - - HFA384X_OUTW(param1, HFA384X_PARAM1_OFF); - HFA384X_OUTW(0, HFA384X_PARAM2_OFF); - if (hfa384x_cmd_no_wait(dev, HFA384X_CMDCODE_DOWNLOAD | - (HFA384X_PROGMODE_DISABLE << 8), param0)) { - printk(KERN_WARNING "%s: Download command execution failed\n", - dev->name); - ret = -1; - goto out; - } - /* ProgMode disable causes the hardware to restart itself from the - * given starting address. Give hw some time and ACK command just in - * case restart did not happen. */ - mdelay(5); - HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); - - if (prism2_enable_aux_port(dev, 0)) { - printk(KERN_DEBUG "%s: Disabling AUX port failed\n", - dev->name); - /* continue anyway.. restart should have taken care of this */ - } - - mdelay(5); - local->hw_downloading = 0; - if (prism2_hw_config(dev, 2)) { - printk(KERN_WARNING "%s: Card configuration after RAM " - "download failed\n", dev->name); - ret = -1; - goto out; - } - - out: - local->hw_downloading = 0; - return ret; -} - - -static int prism2_enable_genesis(local_info_t *local, int hcr) -{ - struct net_device *dev = local->dev; - u8 initseq[4] = { 0x00, 0xe1, 0xa1, 0xff }; - u8 readbuf[4]; - - printk(KERN_DEBUG "%s: test Genesis mode with HCR 0x%02x\n", - dev->name, hcr); - local->func->cor_sreset(local); - hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq); - local->func->genesis_reset(local, hcr); - - /* Readback test */ - hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf); - hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq); - hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf); - - if (memcmp(initseq, readbuf, sizeof(initseq)) == 0) { - printk(KERN_DEBUG "Readback test succeeded, HCR 0x%02x\n", - hcr); - return 0; - } else { - printk(KERN_DEBUG "Readback test failed, HCR 0x%02x write %4ph read %4ph\n", - hcr, initseq, readbuf); - return 1; - } -} - - -static int prism2_get_ram_size(local_info_t *local) -{ - int ret; - - /* Try to enable genesis mode; 0x1F for x8 SRAM or 0x0F for x16 SRAM */ - if (prism2_enable_genesis(local, 0x1f) == 0) - ret = 8; - else if (prism2_enable_genesis(local, 0x0f) == 0) - ret = 16; - else - ret = -1; - - /* Disable genesis mode */ - local->func->genesis_reset(local, ret == 16 ? 0x07 : 0x17); - - return ret; -} - - -static int prism2_download_genesis(local_info_t *local, - struct prism2_download_data *param) -{ - struct net_device *dev = local->dev; - int ram16 = 0, i; - int ret = 0; - - if (local->hw_downloading) { - printk(KERN_WARNING "%s: Already downloading - aborting new " - "request\n", dev->name); - return -EBUSY; - } - - if (!local->func->genesis_reset || !local->func->cor_sreset) { - printk(KERN_INFO "%s: Genesis mode downloading not supported " - "with this hwmodel\n", dev->name); - return -EOPNOTSUPP; - } - - local->hw_downloading = 1; - - if (prism2_enable_aux_port(dev, 1)) { - printk(KERN_DEBUG "%s: failed to enable AUX port\n", - dev->name); - ret = -EIO; - goto out; - } - - if (local->sram_type == -1) { - /* 0x1F for x8 SRAM or 0x0F for x16 SRAM */ - if (prism2_enable_genesis(local, 0x1f) == 0) { - ram16 = 0; - PDEBUG(DEBUG_EXTRA2, "%s: Genesis mode OK using x8 " - "SRAM\n", dev->name); - } else if (prism2_enable_genesis(local, 0x0f) == 0) { - ram16 = 1; - PDEBUG(DEBUG_EXTRA2, "%s: Genesis mode OK using x16 " - "SRAM\n", dev->name); - } else { - printk(KERN_DEBUG "%s: Could not initiate genesis " - "mode\n", dev->name); - ret = -EIO; - goto out; - } - } else { - if (prism2_enable_genesis(local, local->sram_type == 8 ? - 0x1f : 0x0f)) { - printk(KERN_DEBUG "%s: Failed to set Genesis " - "mode (sram_type=%d)\n", dev->name, - local->sram_type); - ret = -EIO; - goto out; - } - ram16 = local->sram_type != 8; - } - - for (i = 0; i < param->num_areas; i++) { - PDEBUG(DEBUG_EXTRA2, "%s: Writing %d bytes at 0x%08x\n", - dev->name, param->data[i].len, param->data[i].addr); - if (hfa384x_to_aux(dev, param->data[i].addr, - param->data[i].len, param->data[i].data)) { - printk(KERN_WARNING "%s: RAM download at 0x%08x " - "(len=%d) failed\n", dev->name, - param->data[i].addr, param->data[i].len); - ret = -EIO; - goto out; - } - } - - PDEBUG(DEBUG_EXTRA2, "Disable genesis mode\n"); - local->func->genesis_reset(local, ram16 ? 0x07 : 0x17); - if (prism2_enable_aux_port(dev, 0)) { - printk(KERN_DEBUG "%s: Failed to disable AUX port\n", - dev->name); - } - - mdelay(5); - local->hw_downloading = 0; - - PDEBUG(DEBUG_EXTRA2, "Trying to initialize card\n"); - /* - * Make sure the INIT command does not generate a command completion - * event by disabling interrupts. - */ - hfa384x_disable_interrupts(dev); - if (prism2_hw_init(dev, 1)) { - printk(KERN_DEBUG "%s: Initialization after genesis mode " - "download failed\n", dev->name); - ret = -EIO; - goto out; - } - - PDEBUG(DEBUG_EXTRA2, "Card initialized - running PRI only\n"); - if (prism2_hw_init2(dev, 1)) { - printk(KERN_DEBUG "%s: Initialization(2) after genesis mode " - "download failed\n", dev->name); - ret = -EIO; - goto out; - } - - out: - local->hw_downloading = 0; - return ret; -} - - -#ifdef PRISM2_NON_VOLATILE_DOWNLOAD -/* Note! Non-volatile downloading functionality has not yet been tested - * thoroughly and it may corrupt flash image and effectively kill the card that - * is being updated. You have been warned. */ - -static inline int prism2_download_block(struct net_device *dev, - u32 addr, u8 *data, - u32 bufaddr, int rest_len) -{ - u16 param0, param1; - int block_len; - - block_len = rest_len < 4096 ? rest_len : 4096; - - param0 = addr & 0xffff; - param1 = addr >> 16; - - HFA384X_OUTW(block_len, HFA384X_PARAM2_OFF); - HFA384X_OUTW(param1, HFA384X_PARAM1_OFF); - - if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD | - (HFA384X_PROGMODE_ENABLE_NON_VOLATILE << 8), - param0)) { - printk(KERN_WARNING "%s: Flash download command execution " - "failed\n", dev->name); - return -1; - } - - if (hfa384x_to_aux(dev, bufaddr, block_len, data)) { - printk(KERN_WARNING "%s: flash download at 0x%08x " - "(len=%d) failed\n", dev->name, addr, block_len); - return -1; - } - - HFA384X_OUTW(0, HFA384X_PARAM2_OFF); - HFA384X_OUTW(0, HFA384X_PARAM1_OFF); - if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD | - (HFA384X_PROGMODE_PROGRAM_NON_VOLATILE << 8), - 0)) { - printk(KERN_WARNING "%s: Flash write command execution " - "failed\n", dev->name); - return -1; - } - - return block_len; -} - - -static int prism2_download_nonvolatile(local_info_t *local, - struct prism2_download_data *dl) -{ - struct net_device *dev = local->dev; - int ret = 0, i; - struct { - __le16 page; - __le16 offset; - __le16 len; - } dlbuffer; - u32 bufaddr; - - if (local->hw_downloading) { - printk(KERN_WARNING "%s: Already downloading - aborting new " - "request\n", dev->name); - return -1; - } - - ret = local->func->get_rid(dev, HFA384X_RID_DOWNLOADBUFFER, - &dlbuffer, 6, 0); - - if (ret < 0) { - printk(KERN_WARNING "%s: Could not read download buffer " - "parameters\n", dev->name); - goto out; - } - - printk(KERN_DEBUG "Download buffer: %d bytes at 0x%04x:0x%04x\n", - le16_to_cpu(dlbuffer.len), - le16_to_cpu(dlbuffer.page), - le16_to_cpu(dlbuffer.offset)); - - bufaddr = (le16_to_cpu(dlbuffer.page) << 7) + le16_to_cpu(dlbuffer.offset); - - local->hw_downloading = 1; - - if (!local->pri_only) { - prism2_hw_shutdown(dev, 0); - - if (prism2_hw_init(dev, 0)) { - printk(KERN_WARNING "%s: Could not initialize card for" - " download\n", dev->name); - ret = -1; - goto out; - } - } - - hfa384x_disable_interrupts(dev); - - if (prism2_enable_aux_port(dev, 1)) { - printk(KERN_WARNING "%s: Could not enable AUX port\n", - dev->name); - ret = -1; - goto out; - } - - printk(KERN_DEBUG "%s: starting flash download\n", dev->name); - for (i = 0; i < dl->num_areas; i++) { - int rest_len = dl->data[i].len; - int data_off = 0; - - while (rest_len > 0) { - int block_len; - - block_len = prism2_download_block( - dev, dl->data[i].addr + data_off, - dl->data[i].data + data_off, bufaddr, - rest_len); - - if (block_len < 0) { - ret = -1; - goto out; - } - - rest_len -= block_len; - data_off += block_len; - } - } - - HFA384X_OUTW(0, HFA384X_PARAM1_OFF); - HFA384X_OUTW(0, HFA384X_PARAM2_OFF); - if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD | - (HFA384X_PROGMODE_DISABLE << 8), 0)) { - printk(KERN_WARNING "%s: Download command execution failed\n", - dev->name); - ret = -1; - goto out; - } - - if (prism2_enable_aux_port(dev, 0)) { - printk(KERN_DEBUG "%s: Disabling AUX port failed\n", - dev->name); - /* continue anyway.. restart should have taken care of this */ - } - - mdelay(5); - - local->func->hw_reset(dev); - local->hw_downloading = 0; - if (prism2_hw_config(dev, 2)) { - printk(KERN_WARNING "%s: Card configuration after flash " - "download failed\n", dev->name); - ret = -1; - } else { - printk(KERN_INFO "%s: Card initialized successfully after " - "flash download\n", dev->name); - } - - out: - local->hw_downloading = 0; - return ret; -} -#endif /* PRISM2_NON_VOLATILE_DOWNLOAD */ - - -static void prism2_download_free_data(struct prism2_download_data *dl) -{ - int i; - - if (dl == NULL) - return; - - for (i = 0; i < dl->num_areas; i++) - kfree(dl->data[i].data); - kfree(dl); -} - - -static int prism2_download(local_info_t *local, - struct prism2_download_param *param) -{ - int ret = 0; - int i; - u32 total_len = 0; - struct prism2_download_data *dl = NULL; - - printk(KERN_DEBUG "prism2_download: dl_cmd=%d start_addr=0x%08x " - "num_areas=%d\n", - param->dl_cmd, param->start_addr, param->num_areas); - - if (param->num_areas > 100) { - ret = -EINVAL; - goto out; - } - - dl = kzalloc(struct_size(dl, data, param->num_areas), GFP_KERNEL); - if (dl == NULL) { - ret = -ENOMEM; - goto out; - } - dl->dl_cmd = param->dl_cmd; - dl->start_addr = param->start_addr; - dl->num_areas = param->num_areas; - for (i = 0; i < param->num_areas; i++) { - PDEBUG(DEBUG_EXTRA2, - " area %d: addr=0x%08x len=%d ptr=0x%p\n", - i, param->data[i].addr, param->data[i].len, - param->data[i].ptr); - - dl->data[i].addr = param->data[i].addr; - dl->data[i].len = param->data[i].len; - - total_len += param->data[i].len; - if (param->data[i].len > PRISM2_MAX_DOWNLOAD_AREA_LEN || - total_len > PRISM2_MAX_DOWNLOAD_LEN) { - ret = -E2BIG; - goto out; - } - - dl->data[i].data = kmalloc(dl->data[i].len, GFP_KERNEL); - if (dl->data[i].data == NULL) { - ret = -ENOMEM; - goto out; - } - - if (copy_from_user(dl->data[i].data, param->data[i].ptr, - param->data[i].len)) { - ret = -EFAULT; - goto out; - } - } - - switch (param->dl_cmd) { - case PRISM2_DOWNLOAD_VOLATILE: - case PRISM2_DOWNLOAD_VOLATILE_PERSISTENT: - ret = prism2_download_volatile(local, dl); - break; - case PRISM2_DOWNLOAD_VOLATILE_GENESIS: - case PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT: - ret = prism2_download_genesis(local, dl); - break; - case PRISM2_DOWNLOAD_NON_VOLATILE: -#ifdef PRISM2_NON_VOLATILE_DOWNLOAD - ret = prism2_download_nonvolatile(local, dl); -#else /* PRISM2_NON_VOLATILE_DOWNLOAD */ - printk(KERN_INFO "%s: non-volatile downloading not enabled\n", - local->dev->name); - ret = -EOPNOTSUPP; -#endif /* PRISM2_NON_VOLATILE_DOWNLOAD */ - break; - default: - printk(KERN_DEBUG "%s: unsupported download command %d\n", - local->dev->name, param->dl_cmd); - ret = -EINVAL; - break; - } - - out: - if (ret == 0 && dl && - param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT) { - prism2_download_free_data(local->dl_pri); - local->dl_pri = dl; - } else if (ret == 0 && dl && - param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_PERSISTENT) { - prism2_download_free_data(local->dl_sec); - local->dl_sec = dl; - } else - prism2_download_free_data(dl); - - return ret; -} diff --git a/drivers/net/wireless/intersil/hostap/hostap_hw.c b/drivers/net/wireless/intersil/hostap/hostap_hw.c deleted file mode 100644 index b74f4cb5d6d39..0000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_hw.c +++ /dev/null @@ -1,3387 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Host AP (software wireless LAN access point) driver for - * Intersil Prism2/2.5/3. - * - * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen - * - * Copyright (c) 2002-2005, Jouni Malinen - * - * FIX: - * - there is currently no way of associating TX packets to correct wds device - * when TX Exc/OK event occurs, so all tx_packets and some - * tx_errors/tx_dropped are added to the main netdevice; using sw_support - * field in txdesc might be used to fix this (using Alloc event to increment - * tx_packets would need some further info in txfid table) - * - * Buffer Access Path (BAP) usage: - * Prism2 cards have two separate BAPs for accessing the card memory. These - * should allow concurrent access to two different frames and the driver - * previously used BAP0 for sending data and BAP1 for receiving data. - * However, there seems to be number of issues with concurrent access and at - * least one know hardware bug in using BAP0 and BAP1 concurrently with PCI - * Prism2.5. Therefore, the driver now only uses BAP0 for moving data between - * host and card memories. BAP0 accesses are protected with local->baplock - * (spin_lock_bh) to prevent concurrent use. - */ - - - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "hostap_80211.h" -#include "hostap.h" -#include "hostap_ap.h" - - -/* #define final_version */ - -static int mtu = 1500; -module_param(mtu, int, 0444); -MODULE_PARM_DESC(mtu, "Maximum transfer unit"); - -static int channel[MAX_PARM_DEVICES] = { 3, DEF_INTS }; -module_param_array(channel, int, NULL, 0444); -MODULE_PARM_DESC(channel, "Initial channel"); - -static char essid[33] = "test"; -module_param_string(essid, essid, sizeof(essid), 0444); -MODULE_PARM_DESC(essid, "Host AP's ESSID"); - -static int iw_mode[MAX_PARM_DEVICES] = { IW_MODE_MASTER, DEF_INTS }; -module_param_array(iw_mode, int, NULL, 0444); -MODULE_PARM_DESC(iw_mode, "Initial operation mode"); - -static int beacon_int[MAX_PARM_DEVICES] = { 100, DEF_INTS }; -module_param_array(beacon_int, int, NULL, 0444); -MODULE_PARM_DESC(beacon_int, "Beacon interval (1 = 1024 usec)"); - -static int dtim_period[MAX_PARM_DEVICES] = { 1, DEF_INTS }; -module_param_array(dtim_period, int, NULL, 0444); -MODULE_PARM_DESC(dtim_period, "DTIM period"); - -static char dev_template[16] = "wlan%d"; -module_param_string(dev_template, dev_template, sizeof(dev_template), 0444); -MODULE_PARM_DESC(dev_template, "Prefix for network device name (default: " - "wlan%d)"); - -#ifdef final_version -#define EXTRA_EVENTS_WTERR 0 -#else -/* check WTERR events (Wait Time-out) in development versions */ -#define EXTRA_EVENTS_WTERR HFA384X_EV_WTERR -#endif - -/* Events that will be using BAP0 */ -#define HFA384X_BAP0_EVENTS \ - (HFA384X_EV_TXEXC | HFA384X_EV_RX | HFA384X_EV_INFO | HFA384X_EV_TX) - -/* event mask, i.e., events that will result in an interrupt */ -#define HFA384X_EVENT_MASK \ - (HFA384X_BAP0_EVENTS | HFA384X_EV_ALLOC | HFA384X_EV_INFDROP | \ - HFA384X_EV_CMD | HFA384X_EV_TICK | \ - EXTRA_EVENTS_WTERR) - -/* Default TX control flags: use 802.11 headers and request interrupt for - * failed transmits. Frames that request ACK callback, will add - * _TX_OK flag and _ALT_RTRY flag may be used to select different retry policy. - */ -#define HFA384X_TX_CTRL_FLAGS \ - (HFA384X_TX_CTRL_802_11 | HFA384X_TX_CTRL_TX_EX) - - -/* ca. 1 usec */ -#define HFA384X_CMD_BUSY_TIMEOUT 5000 -#define HFA384X_BAP_BUSY_TIMEOUT 50000 - -/* ca. 10 usec */ -#define HFA384X_CMD_COMPL_TIMEOUT 20000 -#define HFA384X_DL_COMPL_TIMEOUT 1000000 - -/* Wait times for initialization; yield to other processes to avoid busy - * waiting for long time. */ -#define HFA384X_INIT_TIMEOUT (HZ / 2) /* 500 ms */ -#define HFA384X_ALLOC_COMPL_TIMEOUT (HZ / 20) /* 50 ms */ - - -static void prism2_hw_reset(struct net_device *dev); -static void prism2_check_sta_fw_version(local_info_t *local); - -#ifdef PRISM2_DOWNLOAD_SUPPORT -/* hostap_download.c */ -static const struct proc_ops prism2_download_aux_dump_proc_ops; -static u8 * prism2_read_pda(struct net_device *dev); -static int prism2_download(local_info_t *local, - struct prism2_download_param *param); -static void prism2_download_free_data(struct prism2_download_data *dl); -static int prism2_download_volatile(local_info_t *local, - struct prism2_download_data *param); -static int prism2_download_genesis(local_info_t *local, - struct prism2_download_data *param); -static int prism2_get_ram_size(local_info_t *local); -#endif /* PRISM2_DOWNLOAD_SUPPORT */ - - - - -#ifndef final_version -/* magic value written to SWSUPPORT0 reg. for detecting whether card is still - * present */ -#define HFA384X_MAGIC 0x8A32 -#endif - -static void hfa384x_read_regs(struct net_device *dev, - struct hfa384x_regs *regs) -{ - regs->cmd = HFA384X_INW(HFA384X_CMD_OFF); - regs->evstat = HFA384X_INW(HFA384X_EVSTAT_OFF); - regs->offset0 = HFA384X_INW(HFA384X_OFFSET0_OFF); - regs->offset1 = HFA384X_INW(HFA384X_OFFSET1_OFF); - regs->swsupport0 = HFA384X_INW(HFA384X_SWSUPPORT0_OFF); -} - - -/** - * __hostap_cmd_queue_free - Free Prism2 command queue entry (private) - * @local: pointer to private Host AP driver data - * @entry: Prism2 command queue entry to be freed - * @del_req: request the entry to be removed - * - * Internal helper function for freeing Prism2 command queue entries. - * Caller must have acquired local->cmdlock before calling this function. - */ -static inline void __hostap_cmd_queue_free(local_info_t *local, - struct hostap_cmd_queue *entry, - int del_req) -{ - if (del_req) { - entry->del_req = 1; - if (!list_empty(&entry->list)) { - list_del_init(&entry->list); - local->cmd_queue_len--; - } - } - - if (refcount_dec_and_test(&entry->usecnt) && entry->del_req) - kfree(entry); -} - - -/** - * hostap_cmd_queue_free - Free Prism2 command queue entry - * @local: pointer to private Host AP driver data - * @entry: Prism2 command queue entry to be freed - * @del_req: request the entry to be removed - * - * Free a Prism2 command queue entry. - */ -static inline void hostap_cmd_queue_free(local_info_t *local, - struct hostap_cmd_queue *entry, - int del_req) -{ - unsigned long flags; - - spin_lock_irqsave(&local->cmdlock, flags); - __hostap_cmd_queue_free(local, entry, del_req); - spin_unlock_irqrestore(&local->cmdlock, flags); -} - - -/** - * prism2_clear_cmd_queue - Free all pending Prism2 command queue entries - * @local: pointer to private Host AP driver data - */ -static void prism2_clear_cmd_queue(local_info_t *local) -{ - struct list_head *ptr, *n; - unsigned long flags; - struct hostap_cmd_queue *entry; - - spin_lock_irqsave(&local->cmdlock, flags); - list_for_each_safe(ptr, n, &local->cmd_queue) { - entry = list_entry(ptr, struct hostap_cmd_queue, list); - refcount_inc(&entry->usecnt); - printk(KERN_DEBUG "%s: removed pending cmd_queue entry " - "(type=%d, cmd=0x%04x, param0=0x%04x)\n", - local->dev->name, entry->type, entry->cmd, - entry->param0); - __hostap_cmd_queue_free(local, entry, 1); - } - if (local->cmd_queue_len) { - /* This should not happen; print debug message and clear - * queue length. */ - printk(KERN_DEBUG "%s: cmd_queue_len (%d) not zero after " - "flush\n", local->dev->name, local->cmd_queue_len); - local->cmd_queue_len = 0; - } - spin_unlock_irqrestore(&local->cmdlock, flags); -} - - -/** - * hfa384x_cmd_issue - Issue a Prism2 command to the hardware - * @dev: pointer to net_device - * @entry: Prism2 command queue entry to be issued - */ -static int hfa384x_cmd_issue(struct net_device *dev, - struct hostap_cmd_queue *entry) -{ - struct hostap_interface *iface; - local_info_t *local; - int tries; - u16 reg; - unsigned long flags; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->func->card_present && !local->func->card_present(local)) - return -ENODEV; - - if (entry->issued) { - printk(KERN_DEBUG "%s: driver bug - re-issuing command @%p\n", - dev->name, entry); - } - - /* wait until busy bit is clear; this should always be clear since the - * commands are serialized */ - tries = HFA384X_CMD_BUSY_TIMEOUT; - while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) { - tries--; - udelay(1); - } -#ifndef final_version - if (tries != HFA384X_CMD_BUSY_TIMEOUT) { - prism2_io_debug_error(dev, 1); - printk(KERN_DEBUG "%s: hfa384x_cmd_issue: cmd reg was busy " - "for %d usec\n", dev->name, - HFA384X_CMD_BUSY_TIMEOUT - tries); - } -#endif - if (tries == 0) { - reg = HFA384X_INW(HFA384X_CMD_OFF); - prism2_io_debug_error(dev, 2); - printk(KERN_DEBUG "%s: hfa384x_cmd_issue - timeout - " - "reg=0x%04x\n", dev->name, reg); - return -ETIMEDOUT; - } - - /* write command */ - spin_lock_irqsave(&local->cmdlock, flags); - HFA384X_OUTW(entry->param0, HFA384X_PARAM0_OFF); - HFA384X_OUTW(entry->param1, HFA384X_PARAM1_OFF); - HFA384X_OUTW(entry->cmd, HFA384X_CMD_OFF); - entry->issued = 1; - spin_unlock_irqrestore(&local->cmdlock, flags); - - return 0; -} - - -/** - * hfa384x_cmd - Issue a Prism2 command and wait (sleep) for completion - * @dev: pointer to net_device - * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) - * @param0: value for Param0 register - * @param1: value for Param1 register (pointer; %NULL if not used) - * @resp0: pointer for Resp0 data or %NULL if Resp0 is not needed - * - * Issue given command (possibly after waiting in command queue) and sleep - * until the command is completed (or timed out or interrupted). This can be - * called only from user process context. - */ -static int hfa384x_cmd(struct net_device *dev, u16 cmd, u16 param0, - u16 *param1, u16 *resp0) -{ - struct hostap_interface *iface; - local_info_t *local; - int err, res, issue, issued = 0; - unsigned long flags; - struct hostap_cmd_queue *entry; - DECLARE_WAITQUEUE(wait, current); - - iface = netdev_priv(dev); - local = iface->local; - - if (local->cmd_queue_len >= HOSTAP_CMD_QUEUE_MAX_LEN) { - printk(KERN_DEBUG "%s: hfa384x_cmd: cmd_queue full\n", - dev->name); - return -1; - } - - if (signal_pending(current)) - return -EINTR; - - entry = kzalloc(sizeof(*entry), GFP_ATOMIC); - if (entry == NULL) - return -ENOMEM; - - refcount_set(&entry->usecnt, 1); - entry->type = CMD_SLEEP; - entry->cmd = cmd; - entry->param0 = param0; - if (param1) - entry->param1 = *param1; - init_waitqueue_head(&entry->compl); - - /* prepare to wait for command completion event, but do not sleep yet - */ - add_wait_queue(&entry->compl, &wait); - set_current_state(TASK_INTERRUPTIBLE); - - spin_lock_irqsave(&local->cmdlock, flags); - issue = list_empty(&local->cmd_queue); - if (issue) - entry->issuing = 1; - list_add_tail(&entry->list, &local->cmd_queue); - local->cmd_queue_len++; - spin_unlock_irqrestore(&local->cmdlock, flags); - - err = 0; - if (!issue) - goto wait_completion; - - if (signal_pending(current)) - err = -EINTR; - - if (!err) { - if (hfa384x_cmd_issue(dev, entry)) - err = -ETIMEDOUT; - else - issued = 1; - } - - wait_completion: - if (!err && entry->type != CMD_COMPLETED) { - /* sleep until command is completed or timed out */ - res = schedule_timeout(2 * HZ); - } else - res = -1; - - if (!err && signal_pending(current)) - err = -EINTR; - - if (err && issued) { - /* the command was issued, so a CmdCompl event should occur - * soon; however, there's a pending signal and - * schedule_timeout() would be interrupted; wait a short period - * of time to avoid removing entry from the list before - * CmdCompl event */ - udelay(300); - } - - set_current_state(TASK_RUNNING); - remove_wait_queue(&entry->compl, &wait); - - /* If entry->list is still in the list, it must be removed - * first and in this case prism2_cmd_ev() does not yet have - * local reference to it, and the data can be kfree()'d - * here. If the command completion event is still generated, - * it will be assigned to next (possibly) pending command, but - * the driver will reset the card anyway due to timeout - * - * If the entry is not in the list prism2_cmd_ev() has a local - * reference to it, but keeps cmdlock as long as the data is - * needed, so the data can be kfree()'d here. */ - - /* FIX: if the entry->list is in the list, it has not been completed - * yet, so removing it here is somewhat wrong.. this could cause - * references to freed memory and next list_del() causing NULL pointer - * dereference.. it would probably be better to leave the entry in the - * list and the list should be emptied during hw reset */ - - spin_lock_irqsave(&local->cmdlock, flags); - if (!list_empty(&entry->list)) { - printk(KERN_DEBUG "%s: hfa384x_cmd: entry still in list? " - "(entry=%p, type=%d, res=%d)\n", dev->name, entry, - entry->type, res); - list_del_init(&entry->list); - local->cmd_queue_len--; - } - spin_unlock_irqrestore(&local->cmdlock, flags); - - if (err) { - printk(KERN_DEBUG "%s: hfa384x_cmd: interrupted; err=%d\n", - dev->name, err); - res = err; - goto done; - } - - if (entry->type != CMD_COMPLETED) { - u16 reg = HFA384X_INW(HFA384X_EVSTAT_OFF); - printk(KERN_DEBUG "%s: hfa384x_cmd: command was not " - "completed (res=%d, entry=%p, type=%d, cmd=0x%04x, " - "param0=0x%04x, EVSTAT=%04x INTEN=%04x)\n", dev->name, - res, entry, entry->type, entry->cmd, entry->param0, reg, - HFA384X_INW(HFA384X_INTEN_OFF)); - if (reg & HFA384X_EV_CMD) { - /* Command completion event is pending, but the - * interrupt was not delivered - probably an issue - * with pcmcia-cs configuration. */ - printk(KERN_WARNING "%s: interrupt delivery does not " - "seem to work\n", dev->name); - } - prism2_io_debug_error(dev, 3); - res = -ETIMEDOUT; - goto done; - } - - if (resp0 != NULL) - *resp0 = entry->resp0; -#ifndef final_version - if (entry->res) { - printk(KERN_DEBUG "%s: CMD=0x%04x => res=0x%02x, " - "resp0=0x%04x\n", - dev->name, cmd, entry->res, entry->resp0); - } -#endif /* final_version */ - - res = entry->res; - done: - hostap_cmd_queue_free(local, entry, 1); - return res; -} - - -/** - * hfa384x_cmd_callback - Issue a Prism2 command; callback when completed - * @dev: pointer to net_device - * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) - * @param0: value for Param0 register - * @callback: command completion callback function (%NULL = no callback) - * @context: context data to be given to the callback function - * - * Issue given command (possibly after waiting in command queue) and use - * callback function to indicate command completion. This can be called both - * from user and interrupt context. The callback function will be called in - * hardware IRQ context. It can be %NULL, when no function is called when - * command is completed. - */ -static int hfa384x_cmd_callback(struct net_device *dev, u16 cmd, u16 param0, - void (*callback)(struct net_device *dev, - long context, u16 resp0, - u16 status), - long context) -{ - struct hostap_interface *iface; - local_info_t *local; - int issue, ret; - unsigned long flags; - struct hostap_cmd_queue *entry; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->cmd_queue_len >= HOSTAP_CMD_QUEUE_MAX_LEN + 2) { - printk(KERN_DEBUG "%s: hfa384x_cmd: cmd_queue full\n", - dev->name); - return -1; - } - - entry = kzalloc(sizeof(*entry), GFP_ATOMIC); - if (entry == NULL) - return -ENOMEM; - - refcount_set(&entry->usecnt, 1); - entry->type = CMD_CALLBACK; - entry->cmd = cmd; - entry->param0 = param0; - entry->callback = callback; - entry->context = context; - - spin_lock_irqsave(&local->cmdlock, flags); - issue = list_empty(&local->cmd_queue); - if (issue) - entry->issuing = 1; - list_add_tail(&entry->list, &local->cmd_queue); - local->cmd_queue_len++; - spin_unlock_irqrestore(&local->cmdlock, flags); - - if (issue && hfa384x_cmd_issue(dev, entry)) - ret = -ETIMEDOUT; - else - ret = 0; - - hostap_cmd_queue_free(local, entry, ret); - - return ret; -} - - -/** - * __hfa384x_cmd_no_wait - Issue a Prism2 command (private) - * @dev: pointer to net_device - * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) - * @param0: value for Param0 register - * @io_debug_num: I/O debug error number - * - * Shared helper function for hfa384x_cmd_wait() and hfa384x_cmd_no_wait(). - */ -static int __hfa384x_cmd_no_wait(struct net_device *dev, u16 cmd, u16 param0, - int io_debug_num) -{ - int tries; - u16 reg; - - /* wait until busy bit is clear; this should always be clear since the - * commands are serialized */ - tries = HFA384X_CMD_BUSY_TIMEOUT; - while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) { - tries--; - udelay(1); - } - if (tries == 0) { - reg = HFA384X_INW(HFA384X_CMD_OFF); - prism2_io_debug_error(dev, io_debug_num); - printk(KERN_DEBUG "%s: __hfa384x_cmd_no_wait(%d) - timeout - " - "reg=0x%04x\n", dev->name, io_debug_num, reg); - return -ETIMEDOUT; - } - - /* write command */ - HFA384X_OUTW(param0, HFA384X_PARAM0_OFF); - HFA384X_OUTW(cmd, HFA384X_CMD_OFF); - - return 0; -} - - -/** - * hfa384x_cmd_wait - Issue a Prism2 command and busy wait for completion - * @dev: pointer to net_device - * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) - * @param0: value for Param0 register - */ -static int hfa384x_cmd_wait(struct net_device *dev, u16 cmd, u16 param0) -{ - int res, tries; - u16 reg; - - res = __hfa384x_cmd_no_wait(dev, cmd, param0, 4); - if (res) - return res; - - /* wait for command completion */ - if ((cmd & HFA384X_CMDCODE_MASK) == HFA384X_CMDCODE_DOWNLOAD) - tries = HFA384X_DL_COMPL_TIMEOUT; - else - tries = HFA384X_CMD_COMPL_TIMEOUT; - - while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD) && - tries > 0) { - tries--; - udelay(10); - } - if (tries == 0) { - reg = HFA384X_INW(HFA384X_EVSTAT_OFF); - prism2_io_debug_error(dev, 5); - printk(KERN_DEBUG "%s: hfa384x_cmd_wait - timeout2 - " - "reg=0x%04x\n", dev->name, reg); - return -ETIMEDOUT; - } - - res = (HFA384X_INW(HFA384X_STATUS_OFF) & - (BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | BIT(9) | - BIT(8))) >> 8; -#ifndef final_version - if (res) { - printk(KERN_DEBUG "%s: CMD=0x%04x => res=0x%02x\n", - dev->name, cmd, res); - } -#endif - - HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); - - return res; -} - - -/** - * hfa384x_cmd_no_wait - Issue a Prism2 command; do not wait for completion - * @dev: pointer to net_device - * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) - * @param0: value for Param0 register - */ -static inline int hfa384x_cmd_no_wait(struct net_device *dev, u16 cmd, - u16 param0) -{ - return __hfa384x_cmd_no_wait(dev, cmd, param0, 6); -} - - -/** - * prism2_cmd_ev - Prism2 command completion event handler - * @dev: pointer to net_device - * - * Interrupt handler for command completion events. Called by the main - * interrupt handler in hardware IRQ context. Read Resp0 and status registers - * from the hardware and ACK the event. Depending on the issued command type - * either wake up the sleeping process that is waiting for command completion - * or call the callback function. Issue the next command, if one is pending. - */ -static void prism2_cmd_ev(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - struct hostap_cmd_queue *entry = NULL; - - iface = netdev_priv(dev); - local = iface->local; - - spin_lock(&local->cmdlock); - if (!list_empty(&local->cmd_queue)) { - entry = list_entry(local->cmd_queue.next, - struct hostap_cmd_queue, list); - refcount_inc(&entry->usecnt); - list_del_init(&entry->list); - local->cmd_queue_len--; - - if (!entry->issued) { - printk(KERN_DEBUG "%s: Command completion event, but " - "cmd not issued\n", dev->name); - __hostap_cmd_queue_free(local, entry, 1); - entry = NULL; - } - } - spin_unlock(&local->cmdlock); - - if (!entry) { - HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); - printk(KERN_DEBUG "%s: Command completion event, but no " - "pending commands\n", dev->name); - return; - } - - entry->resp0 = HFA384X_INW(HFA384X_RESP0_OFF); - entry->res = (HFA384X_INW(HFA384X_STATUS_OFF) & - (BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | - BIT(9) | BIT(8))) >> 8; - HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); - - /* TODO: rest of the CmdEv handling could be moved to tasklet */ - if (entry->type == CMD_SLEEP) { - entry->type = CMD_COMPLETED; - wake_up_interruptible(&entry->compl); - } else if (entry->type == CMD_CALLBACK) { - if (entry->callback) - entry->callback(dev, entry->context, entry->resp0, - entry->res); - } else { - printk(KERN_DEBUG "%s: Invalid command completion type %d\n", - dev->name, entry->type); - } - hostap_cmd_queue_free(local, entry, 1); - - /* issue next command, if pending */ - entry = NULL; - spin_lock(&local->cmdlock); - if (!list_empty(&local->cmd_queue)) { - entry = list_entry(local->cmd_queue.next, - struct hostap_cmd_queue, list); - if (entry->issuing) { - /* hfa384x_cmd() has already started issuing this - * command, so do not start here */ - entry = NULL; - } - if (entry) - refcount_inc(&entry->usecnt); - } - spin_unlock(&local->cmdlock); - - if (entry) { - /* issue next command; if command issuing fails, remove the - * entry from cmd_queue */ - int res = hfa384x_cmd_issue(dev, entry); - spin_lock(&local->cmdlock); - __hostap_cmd_queue_free(local, entry, res); - spin_unlock(&local->cmdlock); - } -} - - -static int hfa384x_wait_offset(struct net_device *dev, u16 o_off) -{ - int tries = HFA384X_BAP_BUSY_TIMEOUT; - int res = HFA384X_INW(o_off) & HFA384X_OFFSET_BUSY; - - while (res && tries > 0) { - tries--; - udelay(1); - res = HFA384X_INW(o_off) & HFA384X_OFFSET_BUSY; - } - return res; -} - - -/* Offset must be even */ -static int hfa384x_setup_bap(struct net_device *dev, u16 bap, u16 id, - int offset) -{ - u16 o_off, s_off; - int ret = 0; - - if (offset % 2 || bap > 1) - return -EINVAL; - - if (bap == BAP1) { - o_off = HFA384X_OFFSET1_OFF; - s_off = HFA384X_SELECT1_OFF; - } else { - o_off = HFA384X_OFFSET0_OFF; - s_off = HFA384X_SELECT0_OFF; - } - - if (hfa384x_wait_offset(dev, o_off)) { - prism2_io_debug_error(dev, 7); - printk(KERN_DEBUG "%s: hfa384x_setup_bap - timeout before\n", - dev->name); - ret = -ETIMEDOUT; - goto out; - } - - HFA384X_OUTW(id, s_off); - HFA384X_OUTW(offset, o_off); - - if (hfa384x_wait_offset(dev, o_off)) { - prism2_io_debug_error(dev, 8); - printk(KERN_DEBUG "%s: hfa384x_setup_bap - timeout after\n", - dev->name); - ret = -ETIMEDOUT; - goto out; - } -#ifndef final_version - if (HFA384X_INW(o_off) & HFA384X_OFFSET_ERR) { - prism2_io_debug_error(dev, 9); - printk(KERN_DEBUG "%s: hfa384x_setup_bap - offset error " - "(%d,0x04%x,%d); reg=0x%04x\n", - dev->name, bap, id, offset, HFA384X_INW(o_off)); - ret = -EINVAL; - } -#endif - - out: - return ret; -} - - -static int hfa384x_get_rid(struct net_device *dev, u16 rid, void *buf, int len, - int exact_len) -{ - struct hostap_interface *iface; - local_info_t *local; - int res, rlen = 0; - struct hfa384x_rid_hdr rec; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->no_pri) { - printk(KERN_DEBUG "%s: cannot get RID %04x (len=%d) - no PRI " - "f/w\n", dev->name, rid, len); - return -ENOTTY; /* Well.. not really correct, but return - * something unique enough.. */ - } - - if ((local->func->card_present && !local->func->card_present(local)) || - local->hw_downloading) - return -ENODEV; - - res = mutex_lock_interruptible(&local->rid_bap_mtx); - if (res) - return res; - - res = hfa384x_cmd(dev, HFA384X_CMDCODE_ACCESS, rid, NULL, NULL); - if (res) { - printk(KERN_DEBUG "%s: hfa384x_get_rid: CMDCODE_ACCESS failed " - "(res=%d, rid=%04x, len=%d)\n", - dev->name, res, rid, len); - mutex_unlock(&local->rid_bap_mtx); - return res; - } - - spin_lock_bh(&local->baplock); - - res = hfa384x_setup_bap(dev, BAP0, rid, 0); - if (res) - goto unlock; - - res = hfa384x_from_bap(dev, BAP0, &rec, sizeof(rec)); - if (res) - goto unlock; - - if (le16_to_cpu(rec.len) == 0) { - /* RID not available */ - res = -ENODATA; - goto unlock; - } - - rlen = (le16_to_cpu(rec.len) - 1) * 2; - if (exact_len && rlen != len) { - printk(KERN_DEBUG "%s: hfa384x_get_rid - RID len mismatch: " - "rid=0x%04x, len=%d (expected %d)\n", - dev->name, rid, rlen, len); - res = -ENODATA; - } - - res = hfa384x_from_bap(dev, BAP0, buf, len); - -unlock: - spin_unlock_bh(&local->baplock); - mutex_unlock(&local->rid_bap_mtx); - - if (res) { - if (res != -ENODATA) - printk(KERN_DEBUG "%s: hfa384x_get_rid (rid=%04x, " - "len=%d) - failed - res=%d\n", dev->name, rid, - len, res); - if (res == -ETIMEDOUT) - prism2_hw_reset(dev); - return res; - } - - return rlen; -} - - -static int hfa384x_set_rid(struct net_device *dev, u16 rid, void *buf, int len) -{ - struct hostap_interface *iface; - local_info_t *local; - struct hfa384x_rid_hdr rec; - int res; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->no_pri) { - printk(KERN_DEBUG "%s: cannot set RID %04x (len=%d) - no PRI " - "f/w\n", dev->name, rid, len); - return -ENOTTY; /* Well.. not really correct, but return - * something unique enough.. */ - } - - if ((local->func->card_present && !local->func->card_present(local)) || - local->hw_downloading) - return -ENODEV; - - rec.rid = cpu_to_le16(rid); - /* RID len in words and +1 for rec.rid */ - rec.len = cpu_to_le16(len / 2 + len % 2 + 1); - - res = mutex_lock_interruptible(&local->rid_bap_mtx); - if (res) - return res; - - spin_lock_bh(&local->baplock); - res = hfa384x_setup_bap(dev, BAP0, rid, 0); - if (!res) - res = hfa384x_to_bap(dev, BAP0, &rec, sizeof(rec)); - if (!res) - res = hfa384x_to_bap(dev, BAP0, buf, len); - spin_unlock_bh(&local->baplock); - - if (res) { - printk(KERN_DEBUG "%s: hfa384x_set_rid (rid=%04x, len=%d) - " - "failed - res=%d\n", dev->name, rid, len, res); - mutex_unlock(&local->rid_bap_mtx); - return res; - } - - res = hfa384x_cmd(dev, HFA384X_CMDCODE_ACCESS_WRITE, rid, NULL, NULL); - mutex_unlock(&local->rid_bap_mtx); - - if (res) { - printk(KERN_DEBUG "%s: hfa384x_set_rid: CMDCODE_ACCESS_WRITE " - "failed (res=%d, rid=%04x, len=%d)\n", - dev->name, res, rid, len); - - if (res == -ETIMEDOUT) - prism2_hw_reset(dev); - } - - return res; -} - - -static void hfa384x_disable_interrupts(struct net_device *dev) -{ - /* disable interrupts and clear event status */ - HFA384X_OUTW(0, HFA384X_INTEN_OFF); - HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF); -} - - -static void hfa384x_enable_interrupts(struct net_device *dev) -{ - /* ack pending events and enable interrupts from selected events */ - HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF); - HFA384X_OUTW(HFA384X_EVENT_MASK, HFA384X_INTEN_OFF); -} - - -static void hfa384x_events_no_bap0(struct net_device *dev) -{ - HFA384X_OUTW(HFA384X_EVENT_MASK & ~HFA384X_BAP0_EVENTS, - HFA384X_INTEN_OFF); -} - - -static void hfa384x_events_all(struct net_device *dev) -{ - HFA384X_OUTW(HFA384X_EVENT_MASK, HFA384X_INTEN_OFF); -} - - -static void hfa384x_events_only_cmd(struct net_device *dev) -{ - HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_INTEN_OFF); -} - - -static u16 hfa384x_allocate_fid(struct net_device *dev, int len) -{ - u16 fid; - unsigned long delay; - - /* FIX: this could be replace with hfa384x_cmd() if the Alloc event - * below would be handled like CmdCompl event (sleep here, wake up from - * interrupt handler */ - if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_ALLOC, len)) { - printk(KERN_DEBUG "%s: cannot allocate fid, len=%d\n", - dev->name, len); - return 0xffff; - } - - delay = jiffies + HFA384X_ALLOC_COMPL_TIMEOUT; - while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_ALLOC) && - time_before(jiffies, delay)) - yield(); - if (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_ALLOC)) { - printk("%s: fid allocate, len=%d - timeout\n", dev->name, len); - return 0xffff; - } - - fid = HFA384X_INW(HFA384X_ALLOCFID_OFF); - HFA384X_OUTW(HFA384X_EV_ALLOC, HFA384X_EVACK_OFF); - - return fid; -} - - -static int prism2_reset_port(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - int res; - - iface = netdev_priv(dev); - local = iface->local; - - if (!local->dev_enabled) - return 0; - - res = hfa384x_cmd(dev, HFA384X_CMDCODE_DISABLE, 0, - NULL, NULL); - if (res) - printk(KERN_DEBUG "%s: reset port failed to disable port\n", - dev->name); - else { - res = hfa384x_cmd(dev, HFA384X_CMDCODE_ENABLE, 0, - NULL, NULL); - if (res) - printk(KERN_DEBUG "%s: reset port failed to enable " - "port\n", dev->name); - } - - /* It looks like at least some STA firmware versions reset - * fragmentation threshold back to 2346 after enable command. Restore - * the configured value, if it differs from this default. */ - if (local->fragm_threshold != 2346 && - hostap_set_word(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, - local->fragm_threshold)) { - printk(KERN_DEBUG "%s: failed to restore fragmentation " - "threshold (%d) after Port0 enable\n", - dev->name, local->fragm_threshold); - } - - /* Some firmwares lose antenna selection settings on reset */ - (void) hostap_set_antsel(local); - - return res; -} - - -static int prism2_get_version_info(struct net_device *dev, u16 rid, - const char *txt) -{ - struct hfa384x_comp_ident comp; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->no_pri) { - /* PRI f/w not yet available - cannot read RIDs */ - return -1; - } - if (hfa384x_get_rid(dev, rid, &comp, sizeof(comp), 1) < 0) { - printk(KERN_DEBUG "Could not get RID for component %s\n", txt); - return -1; - } - - printk(KERN_INFO "%s: %s: id=0x%02x v%d.%d.%d\n", dev->name, txt, - __le16_to_cpu(comp.id), __le16_to_cpu(comp.major), - __le16_to_cpu(comp.minor), __le16_to_cpu(comp.variant)); - return 0; -} - - -static int prism2_setup_rids(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - __le16 tmp; - int ret = 0; - - iface = netdev_priv(dev); - local = iface->local; - - hostap_set_word(dev, HFA384X_RID_TICKTIME, 2000); - - if (!local->fw_ap) { - u16 tmp1 = hostap_get_porttype(local); - ret = hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, tmp1); - if (ret) { - printk("%s: Port type setting to %d failed\n", - dev->name, tmp1); - goto fail; - } - } - - /* Setting SSID to empty string seems to kill the card in Host AP mode - */ - if (local->iw_mode != IW_MODE_MASTER || local->essid[0] != '\0') { - ret = hostap_set_string(dev, HFA384X_RID_CNFOWNSSID, - local->essid); - if (ret) { - printk("%s: AP own SSID setting failed\n", dev->name); - goto fail; - } - } - - ret = hostap_set_word(dev, HFA384X_RID_CNFMAXDATALEN, - PRISM2_DATA_MAXLEN); - if (ret) { - printk("%s: MAC data length setting to %d failed\n", - dev->name, PRISM2_DATA_MAXLEN); - goto fail; - } - - if (hfa384x_get_rid(dev, HFA384X_RID_CHANNELLIST, &tmp, 2, 1) < 0) { - printk("%s: Channel list read failed\n", dev->name); - ret = -EINVAL; - goto fail; - } - local->channel_mask = le16_to_cpu(tmp); - - if (local->channel < 1 || local->channel > 14 || - !(local->channel_mask & (1 << (local->channel - 1)))) { - printk(KERN_WARNING "%s: Channel setting out of range " - "(%d)!\n", dev->name, local->channel); - ret = -EBUSY; - goto fail; - } - - ret = hostap_set_word(dev, HFA384X_RID_CNFOWNCHANNEL, local->channel); - if (ret) { - printk("%s: Channel setting to %d failed\n", - dev->name, local->channel); - goto fail; - } - - ret = hostap_set_word(dev, HFA384X_RID_CNFBEACONINT, - local->beacon_int); - if (ret) { - printk("%s: Beacon interval setting to %d failed\n", - dev->name, local->beacon_int); - /* this may fail with Symbol/Lucent firmware */ - if (ret == -ETIMEDOUT) - goto fail; - } - - ret = hostap_set_word(dev, HFA384X_RID_CNFOWNDTIMPERIOD, - local->dtim_period); - if (ret) { - printk("%s: DTIM period setting to %d failed\n", - dev->name, local->dtim_period); - /* this may fail with Symbol/Lucent firmware */ - if (ret == -ETIMEDOUT) - goto fail; - } - - ret = hostap_set_word(dev, HFA384X_RID_PROMISCUOUSMODE, - local->is_promisc); - if (ret) - printk(KERN_INFO "%s: Setting promiscuous mode (%d) failed\n", - dev->name, local->is_promisc); - - if (!local->fw_ap) { - ret = hostap_set_string(dev, HFA384X_RID_CNFDESIREDSSID, - local->essid); - if (ret) { - printk("%s: Desired SSID setting failed\n", dev->name); - goto fail; - } - } - - /* Setup TXRateControl, defaults to allow use of 1, 2, 5.5, and - * 11 Mbps in automatic TX rate fallback and 1 and 2 Mbps as basic - * rates */ - if (local->tx_rate_control == 0) { - local->tx_rate_control = - HFA384X_RATES_1MBPS | - HFA384X_RATES_2MBPS | - HFA384X_RATES_5MBPS | - HFA384X_RATES_11MBPS; - } - if (local->basic_rates == 0) - local->basic_rates = HFA384X_RATES_1MBPS | HFA384X_RATES_2MBPS; - - if (!local->fw_ap) { - ret = hostap_set_word(dev, HFA384X_RID_TXRATECONTROL, - local->tx_rate_control); - if (ret) { - printk("%s: TXRateControl setting to %d failed\n", - dev->name, local->tx_rate_control); - goto fail; - } - - ret = hostap_set_word(dev, HFA384X_RID_CNFSUPPORTEDRATES, - local->tx_rate_control); - if (ret) { - printk("%s: cnfSupportedRates setting to %d failed\n", - dev->name, local->tx_rate_control); - } - - ret = hostap_set_word(dev, HFA384X_RID_CNFBASICRATES, - local->basic_rates); - if (ret) { - printk("%s: cnfBasicRates setting to %d failed\n", - dev->name, local->basic_rates); - } - - ret = hostap_set_word(dev, HFA384X_RID_CREATEIBSS, 1); - if (ret) { - printk("%s: Create IBSS setting to 1 failed\n", - dev->name); - } - } - - if (local->name_set) - (void) hostap_set_string(dev, HFA384X_RID_CNFOWNNAME, - local->name); - - if (hostap_set_encryption(local)) { - printk(KERN_INFO "%s: could not configure encryption\n", - dev->name); - } - - (void) hostap_set_antsel(local); - - if (hostap_set_roaming(local)) { - printk(KERN_INFO "%s: could not set host roaming\n", - dev->name); - } - - if (local->sta_fw_ver >= PRISM2_FW_VER(1,6,3) && - hostap_set_word(dev, HFA384X_RID_CNFENHSECURITY, local->enh_sec)) - printk(KERN_INFO "%s: cnfEnhSecurity setting to 0x%x failed\n", - dev->name, local->enh_sec); - - /* 32-bit tallies were added in STA f/w 0.8.0, but they were apparently - * not working correctly (last seven counters report bogus values). - * This has been fixed in 0.8.2, so enable 32-bit tallies only - * beginning with that firmware version. Another bug fix for 32-bit - * tallies in 1.4.0; should 16-bit tallies be used for some other - * versions, too? */ - if (local->sta_fw_ver >= PRISM2_FW_VER(0,8,2)) { - if (hostap_set_word(dev, HFA384X_RID_CNFTHIRTY2TALLY, 1)) { - printk(KERN_INFO "%s: cnfThirty2Tally setting " - "failed\n", dev->name); - local->tallies32 = 0; - } else - local->tallies32 = 1; - } else - local->tallies32 = 0; - - hostap_set_auth_algs(local); - - if (hostap_set_word(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, - local->fragm_threshold)) { - printk(KERN_INFO "%s: setting FragmentationThreshold to %d " - "failed\n", dev->name, local->fragm_threshold); - } - - if (hostap_set_word(dev, HFA384X_RID_RTSTHRESHOLD, - local->rts_threshold)) { - printk(KERN_INFO "%s: setting RTSThreshold to %d failed\n", - dev->name, local->rts_threshold); - } - - if (local->manual_retry_count >= 0 && - hostap_set_word(dev, HFA384X_RID_CNFALTRETRYCOUNT, - local->manual_retry_count)) { - printk(KERN_INFO "%s: setting cnfAltRetryCount to %d failed\n", - dev->name, local->manual_retry_count); - } - - if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1) && - hfa384x_get_rid(dev, HFA384X_RID_CNFDBMADJUST, &tmp, 2, 1) == 2) { - local->rssi_to_dBm = le16_to_cpu(tmp); - } - - if (local->sta_fw_ver >= PRISM2_FW_VER(1,7,0) && local->wpa && - hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE, 1)) { - printk(KERN_INFO "%s: setting ssnHandlingMode to 1 failed\n", - dev->name); - } - - if (local->sta_fw_ver >= PRISM2_FW_VER(1,7,0) && local->generic_elem && - hfa384x_set_rid(dev, HFA384X_RID_GENERICELEMENT, - local->generic_elem, local->generic_elem_len)) { - printk(KERN_INFO "%s: setting genericElement failed\n", - dev->name); - } - - fail: - return ret; -} - - -static int prism2_hw_init(struct net_device *dev, int initial) -{ - struct hostap_interface *iface; - local_info_t *local; - int ret, first = 1; - unsigned long start, delay; - - PDEBUG(DEBUG_FLOW, "prism2_hw_init()\n"); - - iface = netdev_priv(dev); - local = iface->local; - - clear_bit(HOSTAP_BITS_TRANSMIT, &local->bits); - - init: - /* initialize HFA 384x */ - ret = hfa384x_cmd_no_wait(dev, HFA384X_CMDCODE_INIT, 0); - if (ret) { - printk(KERN_INFO "%s: first command failed - assuming card " - "does not have primary firmware\n", dev_info); - } - - if (first && (HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD)) { - /* EvStat has Cmd bit set in some cases, so retry once if no - * wait was needed */ - HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); - printk(KERN_DEBUG "%s: init command completed too quickly - " - "retrying\n", dev->name); - first = 0; - goto init; - } - - start = jiffies; - delay = jiffies + HFA384X_INIT_TIMEOUT; - while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD) && - time_before(jiffies, delay)) - yield(); - if (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD)) { - printk(KERN_DEBUG "%s: assuming no Primary image in " - "flash - card initialization not completed\n", - dev_info); - local->no_pri = 1; -#ifdef PRISM2_DOWNLOAD_SUPPORT - if (local->sram_type == -1) - local->sram_type = prism2_get_ram_size(local); -#endif /* PRISM2_DOWNLOAD_SUPPORT */ - return 1; - } - local->no_pri = 0; - printk(KERN_DEBUG "prism2_hw_init: initialized in %lu ms\n", - (jiffies - start) * 1000 / HZ); - HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); - return 0; -} - - -static int prism2_hw_init2(struct net_device *dev, int initial) -{ - struct hostap_interface *iface; - local_info_t *local; - int i; - - iface = netdev_priv(dev); - local = iface->local; - -#ifdef PRISM2_DOWNLOAD_SUPPORT - kfree(local->pda); - if (local->no_pri) - local->pda = NULL; - else - local->pda = prism2_read_pda(dev); -#endif /* PRISM2_DOWNLOAD_SUPPORT */ - - hfa384x_disable_interrupts(dev); - -#ifndef final_version - HFA384X_OUTW(HFA384X_MAGIC, HFA384X_SWSUPPORT0_OFF); - if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != HFA384X_MAGIC) { - printk("SWSUPPORT0 write/read failed: %04X != %04X\n", - HFA384X_INW(HFA384X_SWSUPPORT0_OFF), HFA384X_MAGIC); - goto failed; - } -#endif - - if (initial || local->pri_only) { - hfa384x_events_only_cmd(dev); - /* get card version information */ - if (prism2_get_version_info(dev, HFA384X_RID_NICID, "NIC") || - prism2_get_version_info(dev, HFA384X_RID_PRIID, "PRI")) { - hfa384x_disable_interrupts(dev); - goto failed; - } - - if (prism2_get_version_info(dev, HFA384X_RID_STAID, "STA")) { - printk(KERN_DEBUG "%s: Failed to read STA f/w version " - "- only Primary f/w present\n", dev->name); - local->pri_only = 1; - return 0; - } - local->pri_only = 0; - hfa384x_disable_interrupts(dev); - } - - /* FIX: could convert allocate_fid to use sleeping CmdCompl wait and - * enable interrupts before this. This would also require some sort of - * sleeping AllocEv waiting */ - - /* allocate TX FIDs */ - local->txfid_len = PRISM2_TXFID_LEN; - for (i = 0; i < PRISM2_TXFID_COUNT; i++) { - local->txfid[i] = hfa384x_allocate_fid(dev, local->txfid_len); - if (local->txfid[i] == 0xffff && local->txfid_len > 1600) { - local->txfid[i] = hfa384x_allocate_fid(dev, 1600); - if (local->txfid[i] != 0xffff) { - printk(KERN_DEBUG "%s: Using shorter TX FID " - "(1600 bytes)\n", dev->name); - local->txfid_len = 1600; - } - } - if (local->txfid[i] == 0xffff) - goto failed; - local->intransmitfid[i] = PRISM2_TXFID_EMPTY; - } - - hfa384x_events_only_cmd(dev); - - if (initial) { - u8 addr[ETH_ALEN] = {}; - struct list_head *ptr; - - prism2_check_sta_fw_version(local); - - if (hfa384x_get_rid(dev, HFA384X_RID_CNFOWNMACADDR, - addr, ETH_ALEN, 1) < 0) { - printk("%s: could not get own MAC address\n", - dev->name); - } - eth_hw_addr_set(dev, addr); - list_for_each(ptr, &local->hostap_interfaces) { - iface = list_entry(ptr, struct hostap_interface, list); - eth_hw_addr_inherit(iface->dev, dev); - } - } else if (local->fw_ap) - prism2_check_sta_fw_version(local); - - prism2_setup_rids(dev); - - /* MAC is now configured, but port 0 is not yet enabled */ - return 0; - - failed: - if (!local->no_pri) - printk(KERN_WARNING "%s: Initialization failed\n", dev_info); - return 1; -} - - -static int prism2_hw_enable(struct net_device *dev, int initial) -{ - struct hostap_interface *iface; - local_info_t *local; - int was_resetting; - - iface = netdev_priv(dev); - local = iface->local; - was_resetting = local->hw_resetting; - - if (hfa384x_cmd(dev, HFA384X_CMDCODE_ENABLE, 0, NULL, NULL)) { - printk("%s: MAC port 0 enabling failed\n", dev->name); - return 1; - } - - local->hw_ready = 1; - local->hw_reset_tries = 0; - local->hw_resetting = 0; - hfa384x_enable_interrupts(dev); - - /* at least D-Link DWL-650 seems to require additional port reset - * before it starts acting as an AP, so reset port automatically - * here just in case */ - if (initial && prism2_reset_port(dev)) { - printk("%s: MAC port 0 resetting failed\n", dev->name); - return 1; - } - - if (was_resetting && netif_queue_stopped(dev)) { - /* If hw_reset() was called during pending transmit, netif - * queue was stopped. Wake it up now since the wlan card has - * been resetted. */ - netif_wake_queue(dev); - } - - return 0; -} - - -static int prism2_hw_config(struct net_device *dev, int initial) -{ - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->hw_downloading) - return 1; - - if (prism2_hw_init(dev, initial)) { - return local->no_pri ? 0 : 1; - } - - if (prism2_hw_init2(dev, initial)) - return 1; - - /* Enable firmware if secondary image is loaded and at least one of the - * netdevices is up. */ - if (!local->pri_only && - (initial == 0 || (initial == 2 && local->num_dev_open > 0))) { - if (!local->dev_enabled) - prism2_callback(local, PRISM2_CALLBACK_ENABLE); - local->dev_enabled = 1; - return prism2_hw_enable(dev, initial); - } - - return 0; -} - - -static void prism2_hw_shutdown(struct net_device *dev, int no_disable) -{ - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - /* Allow only command completion events during disable */ - hfa384x_events_only_cmd(dev); - - local->hw_ready = 0; - if (local->dev_enabled) - prism2_callback(local, PRISM2_CALLBACK_DISABLE); - local->dev_enabled = 0; - - if (local->func->card_present && !local->func->card_present(local)) { - printk(KERN_DEBUG "%s: card already removed or not configured " - "during shutdown\n", dev->name); - return; - } - - if ((no_disable & HOSTAP_HW_NO_DISABLE) == 0 && - hfa384x_cmd(dev, HFA384X_CMDCODE_DISABLE, 0, NULL, NULL)) - printk(KERN_WARNING "%s: Shutdown failed\n", dev_info); - - hfa384x_disable_interrupts(dev); - - if (no_disable & HOSTAP_HW_ENABLE_CMDCOMPL) - hfa384x_events_only_cmd(dev); - else - prism2_clear_cmd_queue(local); -} - - -static void prism2_hw_reset(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - -#if 0 - static long last_reset = 0; - - /* do not reset card more than once per second to avoid ending up in a - * busy loop resetting the card */ - if (time_before_eq(jiffies, last_reset + HZ)) - return; - last_reset = jiffies; -#endif - - iface = netdev_priv(dev); - local = iface->local; - - if (local->hw_downloading) - return; - - if (local->hw_resetting) { - printk(KERN_WARNING "%s: %s: already resetting card - " - "ignoring reset request\n", dev_info, dev->name); - return; - } - - local->hw_reset_tries++; - if (local->hw_reset_tries > 10) { - printk(KERN_WARNING "%s: too many reset tries, skipping\n", - dev->name); - return; - } - - printk(KERN_WARNING "%s: %s: resetting card\n", dev_info, dev->name); - hfa384x_disable_interrupts(dev); - local->hw_resetting = 1; - if (local->func->cor_sreset) { - /* Host system seems to hang in some cases with high traffic - * load or shared interrupts during COR sreset. Disable shared - * interrupts during reset to avoid these crashes. COS sreset - * takes quite a long time, so it is unfortunate that this - * seems to be needed. Anyway, I do not know of any better way - * of avoiding the crash. */ - disable_irq(dev->irq); - local->func->cor_sreset(local); - enable_irq(dev->irq); - } - prism2_hw_shutdown(dev, 1); - prism2_hw_config(dev, 0); - local->hw_resetting = 0; - -#ifdef PRISM2_DOWNLOAD_SUPPORT - if (local->dl_pri) { - printk(KERN_DEBUG "%s: persistent download of primary " - "firmware\n", dev->name); - if (prism2_download_genesis(local, local->dl_pri) < 0) - printk(KERN_WARNING "%s: download (PRI) failed\n", - dev->name); - } - - if (local->dl_sec) { - printk(KERN_DEBUG "%s: persistent download of secondary " - "firmware\n", dev->name); - if (prism2_download_volatile(local, local->dl_sec) < 0) - printk(KERN_WARNING "%s: download (SEC) failed\n", - dev->name); - } -#endif /* PRISM2_DOWNLOAD_SUPPORT */ - - /* TODO: restore beacon TIM bits for STAs that have buffered frames */ -} - - -static void prism2_schedule_reset(local_info_t *local) -{ - schedule_work(&local->reset_queue); -} - - -/* Called only as scheduled task after noticing card timeout in interrupt - * context */ -static void handle_reset_queue(struct work_struct *work) -{ - local_info_t *local = container_of(work, local_info_t, reset_queue); - - printk(KERN_DEBUG "%s: scheduled card reset\n", local->dev->name); - prism2_hw_reset(local->dev); - - if (netif_queue_stopped(local->dev)) { - int i; - - for (i = 0; i < PRISM2_TXFID_COUNT; i++) - if (local->intransmitfid[i] == PRISM2_TXFID_EMPTY) { - PDEBUG(DEBUG_EXTRA, "prism2_tx_timeout: " - "wake up queue\n"); - netif_wake_queue(local->dev); - break; - } - } -} - - -static int prism2_get_txfid_idx(local_info_t *local) -{ - int idx, end; - unsigned long flags; - - spin_lock_irqsave(&local->txfidlock, flags); - end = idx = local->next_txfid; - do { - if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) { - local->intransmitfid[idx] = PRISM2_TXFID_RESERVED; - spin_unlock_irqrestore(&local->txfidlock, flags); - return idx; - } - idx++; - if (idx >= PRISM2_TXFID_COUNT) - idx = 0; - } while (idx != end); - spin_unlock_irqrestore(&local->txfidlock, flags); - - PDEBUG(DEBUG_EXTRA2, "prism2_get_txfid_idx: no room in txfid buf: " - "packet dropped\n"); - local->dev->stats.tx_dropped++; - - return -1; -} - - -/* Called only from hardware IRQ */ -static void prism2_transmit_cb(struct net_device *dev, long context, - u16 resp0, u16 res) -{ - struct hostap_interface *iface; - local_info_t *local; - int idx = (int) context; - - iface = netdev_priv(dev); - local = iface->local; - - if (res) { - printk(KERN_DEBUG "%s: prism2_transmit_cb - res=0x%02x\n", - dev->name, res); - return; - } - - if (idx < 0 || idx >= PRISM2_TXFID_COUNT) { - printk(KERN_DEBUG "%s: prism2_transmit_cb called with invalid " - "idx=%d\n", dev->name, idx); - return; - } - - if (!test_and_clear_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) { - printk(KERN_DEBUG "%s: driver bug: prism2_transmit_cb called " - "with no pending transmit\n", dev->name); - } - - if (netif_queue_stopped(dev)) { - /* ready for next TX, so wake up queue that was stopped in - * prism2_transmit() */ - netif_wake_queue(dev); - } - - spin_lock(&local->txfidlock); - - /* With reclaim, Resp0 contains new txfid for transmit; the old txfid - * will be automatically allocated for the next TX frame */ - local->intransmitfid[idx] = resp0; - - PDEBUG(DEBUG_FID, "%s: prism2_transmit_cb: txfid[%d]=0x%04x, " - "resp0=0x%04x, transmit_txfid=0x%04x\n", - dev->name, idx, local->txfid[idx], - resp0, local->intransmitfid[local->next_txfid]); - - idx++; - if (idx >= PRISM2_TXFID_COUNT) - idx = 0; - local->next_txfid = idx; - - /* check if all TX buffers are occupied */ - do { - if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) { - spin_unlock(&local->txfidlock); - return; - } - idx++; - if (idx >= PRISM2_TXFID_COUNT) - idx = 0; - } while (idx != local->next_txfid); - spin_unlock(&local->txfidlock); - - /* no empty TX buffers, stop queue */ - netif_stop_queue(dev); -} - - -/* Called only from software IRQ if PCI bus master is not used (with bus master - * this can be called both from software and hardware IRQ) */ -static int prism2_transmit(struct net_device *dev, int idx) -{ - struct hostap_interface *iface; - local_info_t *local; - int res; - - iface = netdev_priv(dev); - local = iface->local; - - /* The driver tries to stop netif queue so that there would not be - * more than one attempt to transmit frames going on; check that this - * is really the case */ - - if (test_and_set_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) { - printk(KERN_DEBUG "%s: driver bug - prism2_transmit() called " - "when previous TX was pending\n", dev->name); - return -1; - } - - /* stop the queue for the time that transmit is pending */ - netif_stop_queue(dev); - - /* transmit packet */ - res = hfa384x_cmd_callback( - dev, - HFA384X_CMDCODE_TRANSMIT | HFA384X_CMD_TX_RECLAIM, - local->txfid[idx], - prism2_transmit_cb, (long) idx); - - if (res) { - printk(KERN_DEBUG "%s: prism2_transmit: CMDCODE_TRANSMIT " - "failed (res=%d)\n", dev->name, res); - dev->stats.tx_dropped++; - netif_wake_queue(dev); - return -1; - } - netif_trans_update(dev); - - /* Since we did not wait for command completion, the card continues - * to process on the background and we will finish handling when - * command completion event is handled (prism2_cmd_ev() function) */ - - return 0; -} - - -/* Send IEEE 802.11 frame (convert the header into Prism2 TX descriptor and - * send the payload with this descriptor) */ -/* Called only from software IRQ */ -static int prism2_tx_80211(struct sk_buff *skb, struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - struct hfa384x_tx_frame txdesc; - struct hostap_skb_tx_data *meta; - int hdr_len, data_len, idx, res, ret = -1; - u16 tx_control; - - iface = netdev_priv(dev); - local = iface->local; - - meta = (struct hostap_skb_tx_data *) skb->cb; - - prism2_callback(local, PRISM2_CALLBACK_TX_START); - - if ((local->func->card_present && !local->func->card_present(local)) || - !local->hw_ready || local->hw_downloading || local->pri_only) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: prism2_tx_80211: hw not ready -" - " skipping\n", dev->name); - } - goto fail; - } - - memset(&txdesc, 0, sizeof(txdesc)); - - /* skb->data starts with txdesc->frame_control */ - hdr_len = sizeof(txdesc.header); - BUILD_BUG_ON(hdr_len != 24); - skb_copy_from_linear_data(skb, &txdesc.header, hdr_len); - if (ieee80211_is_data(txdesc.frame_control) && - ieee80211_has_a4(txdesc.frame_control) && - skb->len >= 30) { - /* Addr4 */ - skb_copy_from_linear_data_offset(skb, hdr_len, txdesc.addr4, - ETH_ALEN); - hdr_len += ETH_ALEN; - } - - tx_control = local->tx_control; - if (meta->tx_cb_idx) { - tx_control |= HFA384X_TX_CTRL_TX_OK; - txdesc.sw_support = cpu_to_le32(meta->tx_cb_idx); - } - txdesc.tx_control = cpu_to_le16(tx_control); - txdesc.tx_rate = meta->rate; - - data_len = skb->len - hdr_len; - txdesc.data_len = cpu_to_le16(data_len); - txdesc.len = cpu_to_be16(data_len); - - idx = prism2_get_txfid_idx(local); - if (idx < 0) - goto fail; - - if (local->frame_dump & PRISM2_DUMP_TX_HDR) - hostap_dump_tx_header(dev->name, &txdesc); - - spin_lock(&local->baplock); - res = hfa384x_setup_bap(dev, BAP0, local->txfid[idx], 0); - - if (!res) - res = hfa384x_to_bap(dev, BAP0, &txdesc, sizeof(txdesc)); - if (!res) - res = hfa384x_to_bap(dev, BAP0, skb->data + hdr_len, - skb->len - hdr_len); - spin_unlock(&local->baplock); - - if (!res) - res = prism2_transmit(dev, idx); - if (res) { - printk(KERN_DEBUG "%s: prism2_tx_80211 - to BAP0 failed\n", - dev->name); - local->intransmitfid[idx] = PRISM2_TXFID_EMPTY; - schedule_work(&local->reset_queue); - goto fail; - } - - ret = 0; - -fail: - prism2_callback(local, PRISM2_CALLBACK_TX_END); - return ret; -} - - -/* Some SMP systems have reported number of odd errors with hostap_pci. fid - * register has changed values between consecutive reads for an unknown reason. - * This should really not happen, so more debugging is needed. This test - * version is a bit slower, but it will detect most of such register changes - * and will try to get the correct fid eventually. */ -#define EXTRA_FID_READ_TESTS - -static u16 prism2_read_fid_reg(struct net_device *dev, u16 reg) -{ -#ifdef EXTRA_FID_READ_TESTS - u16 val, val2, val3; - int i; - - for (i = 0; i < 10; i++) { - val = HFA384X_INW(reg); - val2 = HFA384X_INW(reg); - val3 = HFA384X_INW(reg); - - if (val == val2 && val == val3) - return val; - - printk(KERN_DEBUG "%s: detected fid change (try=%d, reg=%04x):" - " %04x %04x %04x\n", - dev->name, i, reg, val, val2, val3); - if ((val == val2 || val == val3) && val != 0) - return val; - if (val2 == val3 && val2 != 0) - return val2; - } - printk(KERN_WARNING "%s: Uhhuh.. could not read good fid from reg " - "%04x (%04x %04x %04x)\n", dev->name, reg, val, val2, val3); - return val; -#else /* EXTRA_FID_READ_TESTS */ - return HFA384X_INW(reg); -#endif /* EXTRA_FID_READ_TESTS */ -} - - -/* Called only as a tasklet (software IRQ) */ -static void prism2_rx(local_info_t *local) -{ - struct net_device *dev = local->dev; - int res, rx_pending = 0; - u16 len, hdr_len, rxfid, status, macport; - struct hfa384x_rx_frame rxdesc; - struct sk_buff *skb = NULL; - - prism2_callback(local, PRISM2_CALLBACK_RX_START); - - rxfid = prism2_read_fid_reg(dev, HFA384X_RXFID_OFF); -#ifndef final_version - if (rxfid == 0) { - rxfid = HFA384X_INW(HFA384X_RXFID_OFF); - printk(KERN_DEBUG "prism2_rx: rxfid=0 (next 0x%04x)\n", - rxfid); - if (rxfid == 0) { - schedule_work(&local->reset_queue); - goto rx_dropped; - } - /* try to continue with the new rxfid value */ - } -#endif - - spin_lock(&local->baplock); - res = hfa384x_setup_bap(dev, BAP0, rxfid, 0); - if (!res) - res = hfa384x_from_bap(dev, BAP0, &rxdesc, sizeof(rxdesc)); - - if (res) { - spin_unlock(&local->baplock); - printk(KERN_DEBUG "%s: copy from BAP0 failed %d\n", dev->name, - res); - if (res == -ETIMEDOUT) { - schedule_work(&local->reset_queue); - } - goto rx_dropped; - } - - len = le16_to_cpu(rxdesc.data_len); - hdr_len = sizeof(rxdesc); - status = le16_to_cpu(rxdesc.status); - macport = (status >> 8) & 0x07; - - /* Drop frames with too large reported payload length. Monitor mode - * seems to sometimes pass frames (e.g., ctrl::ack) with signed and - * negative value, so allow also values 65522 .. 65534 (-14 .. -2) for - * macport 7 */ - if (len > PRISM2_DATA_MAXLEN + 8 /* WEP */) { - if (macport == 7 && local->iw_mode == IW_MODE_MONITOR) { - if (len >= (u16) -14) { - hdr_len -= 65535 - len; - hdr_len--; - } - len = 0; - } else { - spin_unlock(&local->baplock); - printk(KERN_DEBUG "%s: Received frame with invalid " - "length 0x%04x\n", dev->name, len); - hostap_dump_rx_header(dev->name, &rxdesc); - goto rx_dropped; - } - } - - skb = dev_alloc_skb(len + hdr_len); - if (!skb) { - spin_unlock(&local->baplock); - printk(KERN_DEBUG "%s: RX failed to allocate skb\n", - dev->name); - goto rx_dropped; - } - skb->dev = dev; - skb_put_data(skb, &rxdesc, hdr_len); - - if (len > 0) - res = hfa384x_from_bap(dev, BAP0, skb_put(skb, len), len); - spin_unlock(&local->baplock); - if (res) { - printk(KERN_DEBUG "%s: RX failed to read " - "frame data\n", dev->name); - goto rx_dropped; - } - - skb_queue_tail(&local->rx_list, skb); - tasklet_schedule(&local->rx_tasklet); - - rx_exit: - prism2_callback(local, PRISM2_CALLBACK_RX_END); - if (!rx_pending) { - HFA384X_OUTW(HFA384X_EV_RX, HFA384X_EVACK_OFF); - } - - return; - - rx_dropped: - dev->stats.rx_dropped++; - if (skb) - dev_kfree_skb(skb); - goto rx_exit; -} - - -/* Called only as a tasklet (software IRQ) */ -static void hostap_rx_skb(local_info_t *local, struct sk_buff *skb) -{ - struct hfa384x_rx_frame *rxdesc; - struct net_device *dev = skb->dev; - struct hostap_80211_rx_status stats; - int hdrlen, rx_hdrlen; - - rx_hdrlen = sizeof(*rxdesc); - if (skb->len < sizeof(*rxdesc)) { - /* Allow monitor mode to receive shorter frames */ - if (local->iw_mode == IW_MODE_MONITOR && - skb->len >= sizeof(*rxdesc) - 30) { - rx_hdrlen = skb->len; - } else { - dev_kfree_skb(skb); - return; - } - } - - rxdesc = (struct hfa384x_rx_frame *) skb->data; - - if (local->frame_dump & PRISM2_DUMP_RX_HDR && - skb->len >= sizeof(*rxdesc)) - hostap_dump_rx_header(dev->name, rxdesc); - - if (le16_to_cpu(rxdesc->status) & HFA384X_RX_STATUS_FCSERR && - (!local->monitor_allow_fcserr || - local->iw_mode != IW_MODE_MONITOR)) - goto drop; - - if (skb->len > PRISM2_DATA_MAXLEN) { - printk(KERN_DEBUG "%s: RX: len(%d) > MAX(%d)\n", - dev->name, skb->len, PRISM2_DATA_MAXLEN); - goto drop; - } - - stats.mac_time = le32_to_cpu(rxdesc->time); - stats.signal = rxdesc->signal - local->rssi_to_dBm; - stats.noise = rxdesc->silence - local->rssi_to_dBm; - stats.rate = rxdesc->rate; - - /* Convert Prism2 RX structure into IEEE 802.11 header */ - hdrlen = hostap_80211_get_hdrlen(rxdesc->frame_control); - if (hdrlen > rx_hdrlen) - hdrlen = rx_hdrlen; - - memmove(skb_pull(skb, rx_hdrlen - hdrlen), - &rxdesc->frame_control, hdrlen); - - hostap_80211_rx(dev, skb, &stats); - return; - - drop: - dev_kfree_skb(skb); -} - - -/* Called only as a tasklet (software IRQ) */ -static void hostap_rx_tasklet(struct tasklet_struct *t) -{ - local_info_t *local = from_tasklet(local, t, rx_tasklet); - struct sk_buff *skb; - - while ((skb = skb_dequeue(&local->rx_list)) != NULL) - hostap_rx_skb(local, skb); -} - - -/* Called only from hardware IRQ */ -static void prism2_alloc_ev(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - int idx; - u16 fid; - - iface = netdev_priv(dev); - local = iface->local; - - fid = prism2_read_fid_reg(dev, HFA384X_ALLOCFID_OFF); - - PDEBUG(DEBUG_FID, "FID: interrupt: ALLOC - fid=0x%04x\n", fid); - - spin_lock(&local->txfidlock); - idx = local->next_alloc; - - do { - if (local->txfid[idx] == fid) { - PDEBUG(DEBUG_FID, "FID: found matching txfid[%d]\n", - idx); - -#ifndef final_version - if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) - printk("Already released txfid found at idx " - "%d\n", idx); - if (local->intransmitfid[idx] == PRISM2_TXFID_RESERVED) - printk("Already reserved txfid found at idx " - "%d\n", idx); -#endif - local->intransmitfid[idx] = PRISM2_TXFID_EMPTY; - idx++; - local->next_alloc = idx >= PRISM2_TXFID_COUNT ? 0 : - idx; - - if (!test_bit(HOSTAP_BITS_TRANSMIT, &local->bits) && - netif_queue_stopped(dev)) - netif_wake_queue(dev); - - spin_unlock(&local->txfidlock); - return; - } - - idx++; - if (idx >= PRISM2_TXFID_COUNT) - idx = 0; - } while (idx != local->next_alloc); - - printk(KERN_WARNING "%s: could not find matching txfid (0x%04x, new " - "read 0x%04x) for alloc event\n", dev->name, fid, - HFA384X_INW(HFA384X_ALLOCFID_OFF)); - printk(KERN_DEBUG "TXFIDs:"); - for (idx = 0; idx < PRISM2_TXFID_COUNT; idx++) - printk(" %04x[%04x]", local->txfid[idx], - local->intransmitfid[idx]); - printk("\n"); - spin_unlock(&local->txfidlock); - - /* FIX: should probably schedule reset; reference to one txfid was lost - * completely.. Bad things will happen if we run out of txfids - * Actually, this will cause netdev watchdog to notice TX timeout and - * then card reset after all txfids have been leaked. */ -} - - -/* Called only as a tasklet (software IRQ) */ -static void hostap_tx_callback(local_info_t *local, - struct hfa384x_tx_frame *txdesc, int ok, - char *payload) -{ - u16 sw_support, hdrlen, len; - struct sk_buff *skb; - struct hostap_tx_callback_info *cb; - - /* Make sure that frame was from us. */ - if (!ether_addr_equal(txdesc->addr2, local->dev->dev_addr)) { - printk(KERN_DEBUG "%s: TX callback - foreign frame\n", - local->dev->name); - return; - } - - sw_support = le32_to_cpu(txdesc->sw_support); - - spin_lock(&local->lock); - cb = local->tx_callback; - while (cb != NULL && cb->idx != sw_support) - cb = cb->next; - spin_unlock(&local->lock); - - if (cb == NULL) { - printk(KERN_DEBUG "%s: could not find TX callback (idx %d)\n", - local->dev->name, sw_support); - return; - } - - hdrlen = hostap_80211_get_hdrlen(txdesc->frame_control); - len = le16_to_cpu(txdesc->data_len); - skb = dev_alloc_skb(hdrlen + len); - if (skb == NULL) { - printk(KERN_DEBUG "%s: hostap_tx_callback failed to allocate " - "skb\n", local->dev->name); - return; - } - - skb_put_data(skb, (void *)&txdesc->frame_control, hdrlen); - if (payload) - skb_put_data(skb, payload, len); - - skb->dev = local->dev; - skb_reset_mac_header(skb); - - cb->func(skb, ok, cb->data); -} - - -/* Called only as a tasklet (software IRQ) */ -static int hostap_tx_compl_read(local_info_t *local, int error, - struct hfa384x_tx_frame *txdesc, - char **payload) -{ - u16 fid, len; - int res, ret = 0; - struct net_device *dev = local->dev; - - fid = prism2_read_fid_reg(dev, HFA384X_TXCOMPLFID_OFF); - - PDEBUG(DEBUG_FID, "interrupt: TX (err=%d) - fid=0x%04x\n", fid, error); - - spin_lock(&local->baplock); - res = hfa384x_setup_bap(dev, BAP0, fid, 0); - if (!res) - res = hfa384x_from_bap(dev, BAP0, txdesc, sizeof(*txdesc)); - if (res) { - PDEBUG(DEBUG_EXTRA, "%s: TX (err=%d) - fid=0x%04x - could not " - "read txdesc\n", dev->name, error, fid); - if (res == -ETIMEDOUT) { - schedule_work(&local->reset_queue); - } - ret = -1; - goto fail; - } - if (txdesc->sw_support) { - len = le16_to_cpu(txdesc->data_len); - if (len < PRISM2_DATA_MAXLEN) { - *payload = kmalloc(len, GFP_ATOMIC); - if (*payload == NULL || - hfa384x_from_bap(dev, BAP0, *payload, len)) { - PDEBUG(DEBUG_EXTRA, "%s: could not read TX " - "frame payload\n", dev->name); - kfree(*payload); - *payload = NULL; - ret = -1; - goto fail; - } - } - } - - fail: - spin_unlock(&local->baplock); - - return ret; -} - - -/* Called only as a tasklet (software IRQ) */ -static void prism2_tx_ev(local_info_t *local) -{ - struct net_device *dev = local->dev; - char *payload = NULL; - struct hfa384x_tx_frame txdesc; - - if (hostap_tx_compl_read(local, 0, &txdesc, &payload)) - goto fail; - - if (local->frame_dump & PRISM2_DUMP_TX_HDR) { - PDEBUG(DEBUG_EXTRA, "%s: TX - status=0x%04x " - "retry_count=%d tx_rate=%d seq_ctrl=%d " - "duration_id=%d\n", - dev->name, le16_to_cpu(txdesc.status), - txdesc.retry_count, txdesc.tx_rate, - le16_to_cpu(txdesc.seq_ctrl), - le16_to_cpu(txdesc.duration_id)); - } - - if (txdesc.sw_support) - hostap_tx_callback(local, &txdesc, 1, payload); - kfree(payload); - - fail: - HFA384X_OUTW(HFA384X_EV_TX, HFA384X_EVACK_OFF); -} - - -/* Called only as a tasklet (software IRQ) */ -static void hostap_sta_tx_exc_tasklet(struct tasklet_struct *t) -{ - local_info_t *local = from_tasklet(local, t, sta_tx_exc_tasklet); - struct sk_buff *skb; - - while ((skb = skb_dequeue(&local->sta_tx_exc_list)) != NULL) { - struct hfa384x_tx_frame *txdesc = - (struct hfa384x_tx_frame *) skb->data; - - if (skb->len >= sizeof(*txdesc)) { - /* Convert Prism2 RX structure into IEEE 802.11 header - */ - int hdrlen = hostap_80211_get_hdrlen(txdesc->frame_control); - memmove(skb_pull(skb, sizeof(*txdesc) - hdrlen), - &txdesc->frame_control, hdrlen); - - hostap_handle_sta_tx_exc(local, skb); - } - dev_kfree_skb(skb); - } -} - - -/* Called only as a tasklet (software IRQ) */ -static void prism2_txexc(local_info_t *local) -{ - struct net_device *dev = local->dev; - u16 status, fc; - int show_dump, res; - char *payload = NULL; - struct hfa384x_tx_frame txdesc; - - show_dump = local->frame_dump & PRISM2_DUMP_TXEXC_HDR; - dev->stats.tx_errors++; - - res = hostap_tx_compl_read(local, 1, &txdesc, &payload); - HFA384X_OUTW(HFA384X_EV_TXEXC, HFA384X_EVACK_OFF); - if (res) - return; - - status = le16_to_cpu(txdesc.status); - - /* We produce a TXDROP event only for retry or lifetime - * exceeded, because that's the only status that really mean - * that this particular node went away. - * Other errors means that *we* screwed up. - Jean II */ - if (status & (HFA384X_TX_STATUS_RETRYERR | HFA384X_TX_STATUS_AGEDERR)) - { - union iwreq_data wrqu; - - /* Copy 802.11 dest address. */ - memcpy(wrqu.addr.sa_data, txdesc.addr1, ETH_ALEN); - wrqu.addr.sa_family = ARPHRD_ETHER; - wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL); - } else - show_dump = 1; - - if (local->iw_mode == IW_MODE_MASTER || - local->iw_mode == IW_MODE_REPEAT || - local->wds_type & HOSTAP_WDS_AP_CLIENT) { - struct sk_buff *skb; - skb = dev_alloc_skb(sizeof(txdesc)); - if (skb) { - skb_put_data(skb, &txdesc, sizeof(txdesc)); - skb_queue_tail(&local->sta_tx_exc_list, skb); - tasklet_schedule(&local->sta_tx_exc_tasklet); - } - } - - if (txdesc.sw_support) - hostap_tx_callback(local, &txdesc, 0, payload); - kfree(payload); - - if (!show_dump) - return; - - PDEBUG(DEBUG_EXTRA, "%s: TXEXC - status=0x%04x (%s%s%s%s)" - " tx_control=%04x\n", - dev->name, status, - status & HFA384X_TX_STATUS_RETRYERR ? "[RetryErr]" : "", - status & HFA384X_TX_STATUS_AGEDERR ? "[AgedErr]" : "", - status & HFA384X_TX_STATUS_DISCON ? "[Discon]" : "", - status & HFA384X_TX_STATUS_FORMERR ? "[FormErr]" : "", - le16_to_cpu(txdesc.tx_control)); - - fc = le16_to_cpu(txdesc.frame_control); - PDEBUG(DEBUG_EXTRA, " retry_count=%d tx_rate=%d fc=0x%04x " - "(%s%s%s::%d%s%s)\n", - txdesc.retry_count, txdesc.tx_rate, fc, - ieee80211_is_mgmt(txdesc.frame_control) ? "Mgmt" : "", - ieee80211_is_ctl(txdesc.frame_control) ? "Ctrl" : "", - ieee80211_is_data(txdesc.frame_control) ? "Data" : "", - (fc & IEEE80211_FCTL_STYPE) >> 4, - ieee80211_has_tods(txdesc.frame_control) ? " ToDS" : "", - ieee80211_has_fromds(txdesc.frame_control) ? " FromDS" : ""); - PDEBUG(DEBUG_EXTRA, " A1=%pM A2=%pM A3=%pM A4=%pM\n", - txdesc.addr1, txdesc.addr2, - txdesc.addr3, txdesc.addr4); -} - - -/* Called only as a tasklet (software IRQ) */ -static void hostap_info_tasklet(struct tasklet_struct *t) -{ - local_info_t *local = from_tasklet(local, t, info_tasklet); - struct sk_buff *skb; - - while ((skb = skb_dequeue(&local->info_list)) != NULL) { - hostap_info_process(local, skb); - dev_kfree_skb(skb); - } -} - - -/* Called only as a tasklet (software IRQ) */ -static void prism2_info(local_info_t *local) -{ - struct net_device *dev = local->dev; - u16 fid; - int res, left; - struct hfa384x_info_frame info; - struct sk_buff *skb; - - fid = HFA384X_INW(HFA384X_INFOFID_OFF); - - spin_lock(&local->baplock); - res = hfa384x_setup_bap(dev, BAP0, fid, 0); - if (!res) - res = hfa384x_from_bap(dev, BAP0, &info, sizeof(info)); - if (res) { - spin_unlock(&local->baplock); - printk(KERN_DEBUG "Could not get info frame (fid=0x%04x)\n", - fid); - if (res == -ETIMEDOUT) { - schedule_work(&local->reset_queue); - } - goto out; - } - - left = (le16_to_cpu(info.len) - 1) * 2; - - if (info.len & cpu_to_le16(0x8000) || info.len == 0 || left > 2060) { - /* data register seems to give 0x8000 in some error cases even - * though busy bit is not set in offset register; - * in addition, length must be at least 1 due to type field */ - spin_unlock(&local->baplock); - printk(KERN_DEBUG "%s: Received info frame with invalid " - "length 0x%04x (type 0x%04x)\n", dev->name, - le16_to_cpu(info.len), le16_to_cpu(info.type)); - goto out; - } - - skb = dev_alloc_skb(sizeof(info) + left); - if (skb == NULL) { - spin_unlock(&local->baplock); - printk(KERN_DEBUG "%s: Could not allocate skb for info " - "frame\n", dev->name); - goto out; - } - - skb_put_data(skb, &info, sizeof(info)); - if (left > 0 && hfa384x_from_bap(dev, BAP0, skb_put(skb, left), left)) - { - spin_unlock(&local->baplock); - printk(KERN_WARNING "%s: Info frame read failed (fid=0x%04x, " - "len=0x%04x, type=0x%04x\n", dev->name, fid, - le16_to_cpu(info.len), le16_to_cpu(info.type)); - dev_kfree_skb(skb); - goto out; - } - spin_unlock(&local->baplock); - - skb_queue_tail(&local->info_list, skb); - tasklet_schedule(&local->info_tasklet); - - out: - HFA384X_OUTW(HFA384X_EV_INFO, HFA384X_EVACK_OFF); -} - - -/* Called only as a tasklet (software IRQ) */ -static void hostap_bap_tasklet(struct tasklet_struct *t) -{ - local_info_t *local = from_tasklet(local, t, bap_tasklet); - struct net_device *dev = local->dev; - u16 ev; - int frames = 30; - - if (local->func->card_present && !local->func->card_present(local)) - return; - - set_bit(HOSTAP_BITS_BAP_TASKLET, &local->bits); - - /* Process all pending BAP events without generating new interrupts - * for them */ - while (frames-- > 0) { - ev = HFA384X_INW(HFA384X_EVSTAT_OFF); - if (ev == 0xffff || !(ev & HFA384X_BAP0_EVENTS)) - break; - if (ev & HFA384X_EV_RX) - prism2_rx(local); - if (ev & HFA384X_EV_INFO) - prism2_info(local); - if (ev & HFA384X_EV_TX) - prism2_tx_ev(local); - if (ev & HFA384X_EV_TXEXC) - prism2_txexc(local); - } - - set_bit(HOSTAP_BITS_BAP_TASKLET2, &local->bits); - clear_bit(HOSTAP_BITS_BAP_TASKLET, &local->bits); - - /* Enable interrupts for new BAP events */ - hfa384x_events_all(dev); - clear_bit(HOSTAP_BITS_BAP_TASKLET2, &local->bits); -} - - -/* Called only from hardware IRQ */ -static void prism2_infdrop(struct net_device *dev) -{ - static unsigned long last_inquire = 0; - - PDEBUG(DEBUG_EXTRA, "%s: INFDROP event\n", dev->name); - - /* some firmware versions seem to get stuck with - * full CommTallies in high traffic load cases; every - * packet will then cause INFDROP event and CommTallies - * info frame will not be sent automatically. Try to - * get out of this state by inquiring CommTallies. */ - if (!last_inquire || time_after(jiffies, last_inquire + HZ)) { - hfa384x_cmd_callback(dev, HFA384X_CMDCODE_INQUIRE, - HFA384X_INFO_COMMTALLIES, NULL, 0); - last_inquire = jiffies; - } -} - - -/* Called only from hardware IRQ */ -static void prism2_ev_tick(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - u16 evstat, inten; - static int prev_stuck = 0; - - iface = netdev_priv(dev); - local = iface->local; - - if (time_after(jiffies, local->last_tick_timer + 5 * HZ) && - local->last_tick_timer) { - evstat = HFA384X_INW(HFA384X_EVSTAT_OFF); - inten = HFA384X_INW(HFA384X_INTEN_OFF); - if (!prev_stuck) { - printk(KERN_INFO "%s: SW TICK stuck? " - "bits=0x%lx EvStat=%04x IntEn=%04x\n", - dev->name, local->bits, evstat, inten); - } - local->sw_tick_stuck++; - if ((evstat & HFA384X_BAP0_EVENTS) && - (inten & HFA384X_BAP0_EVENTS)) { - printk(KERN_INFO "%s: trying to recover from IRQ " - "hang\n", dev->name); - hfa384x_events_no_bap0(dev); - } - prev_stuck = 1; - } else - prev_stuck = 0; -} - - -/* Called only from hardware IRQ */ -static void prism2_check_magic(local_info_t *local) -{ - /* at least PCI Prism2.5 with bus mastering seems to sometimes - * return 0x0000 in SWSUPPORT0 for unknown reason, but re-reading the - * register once or twice seems to get the correct value.. PCI cards - * cannot anyway be removed during normal operation, so there is not - * really any need for this verification with them. */ - -#ifndef PRISM2_PCI -#ifndef final_version - static unsigned long last_magic_err = 0; - struct net_device *dev = local->dev; - - if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != HFA384X_MAGIC) { - if (!local->hw_ready) - return; - HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF); - if (time_after(jiffies, last_magic_err + 10 * HZ)) { - printk("%s: Interrupt, but SWSUPPORT0 does not match: " - "%04X != %04X - card removed?\n", dev->name, - HFA384X_INW(HFA384X_SWSUPPORT0_OFF), - HFA384X_MAGIC); - last_magic_err = jiffies; - } else if (net_ratelimit()) { - printk(KERN_DEBUG "%s: interrupt - SWSUPPORT0=%04x " - "MAGIC=%04x\n", dev->name, - HFA384X_INW(HFA384X_SWSUPPORT0_OFF), - HFA384X_MAGIC); - } - if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != 0xffff) - schedule_work(&local->reset_queue); - return; - } -#endif /* final_version */ -#endif /* !PRISM2_PCI */ -} - - -/* Called only from hardware IRQ */ -static irqreturn_t prism2_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct hostap_interface *iface; - local_info_t *local; - int events = 0; - u16 ev; - - iface = netdev_priv(dev); - local = iface->local; - - /* Detect early interrupt before driver is fully configured */ - spin_lock(&local->irq_init_lock); - if (!dev->base_addr) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: Interrupt, but dev not configured\n", - dev->name); - } - spin_unlock(&local->irq_init_lock); - return IRQ_HANDLED; - } - spin_unlock(&local->irq_init_lock); - - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INTERRUPT, 0, 0); - - if (local->func->card_present && !local->func->card_present(local)) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: Interrupt, but dev not OK\n", - dev->name); - } - return IRQ_HANDLED; - } - - prism2_check_magic(local); - - for (;;) { - ev = HFA384X_INW(HFA384X_EVSTAT_OFF); - if (ev == 0xffff) { - if (local->shutdown) - return IRQ_HANDLED; - HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF); - printk(KERN_DEBUG "%s: prism2_interrupt: ev=0xffff\n", - dev->name); - return IRQ_HANDLED; - } - - ev &= HFA384X_INW(HFA384X_INTEN_OFF); - if (ev == 0) - break; - - if (ev & HFA384X_EV_CMD) { - prism2_cmd_ev(dev); - } - - /* Above events are needed even before hw is ready, but other - * events should be skipped during initialization. This may - * change for AllocEv if allocate_fid is implemented without - * busy waiting. */ - if (!local->hw_ready || local->hw_resetting || - !local->dev_enabled) { - ev = HFA384X_INW(HFA384X_EVSTAT_OFF); - if (ev & HFA384X_EV_CMD) - goto next_event; - if ((ev & HFA384X_EVENT_MASK) == 0) - return IRQ_HANDLED; - if (local->dev_enabled && (ev & ~HFA384X_EV_TICK) && - net_ratelimit()) { - printk(KERN_DEBUG "%s: prism2_interrupt: hw " - "not ready; skipping events 0x%04x " - "(IntEn=0x%04x)%s%s%s\n", - dev->name, ev, - HFA384X_INW(HFA384X_INTEN_OFF), - !local->hw_ready ? " (!hw_ready)" : "", - local->hw_resetting ? - " (hw_resetting)" : "", - !local->dev_enabled ? - " (!dev_enabled)" : ""); - } - HFA384X_OUTW(ev, HFA384X_EVACK_OFF); - return IRQ_HANDLED; - } - - if (ev & HFA384X_EV_TICK) { - prism2_ev_tick(dev); - HFA384X_OUTW(HFA384X_EV_TICK, HFA384X_EVACK_OFF); - } - - if (ev & HFA384X_EV_ALLOC) { - prism2_alloc_ev(dev); - HFA384X_OUTW(HFA384X_EV_ALLOC, HFA384X_EVACK_OFF); - } - - /* Reading data from the card is quite time consuming, so do it - * in tasklets. TX, TXEXC, RX, and INFO events will be ACKed - * and unmasked after needed data has been read completely. */ - if (ev & HFA384X_BAP0_EVENTS) { - hfa384x_events_no_bap0(dev); - tasklet_schedule(&local->bap_tasklet); - } - -#ifndef final_version - if (ev & HFA384X_EV_WTERR) { - PDEBUG(DEBUG_EXTRA, "%s: WTERR event\n", dev->name); - HFA384X_OUTW(HFA384X_EV_WTERR, HFA384X_EVACK_OFF); - } -#endif /* final_version */ - - if (ev & HFA384X_EV_INFDROP) { - prism2_infdrop(dev); - HFA384X_OUTW(HFA384X_EV_INFDROP, HFA384X_EVACK_OFF); - } - - next_event: - events++; - if (events >= PRISM2_MAX_INTERRUPT_EVENTS) { - PDEBUG(DEBUG_EXTRA, "prism2_interrupt: >%d events " - "(EvStat=0x%04x)\n", - PRISM2_MAX_INTERRUPT_EVENTS, - HFA384X_INW(HFA384X_EVSTAT_OFF)); - break; - } - } - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INTERRUPT, 0, 1); - return IRQ_RETVAL(events); -} - - -static void prism2_check_sta_fw_version(local_info_t *local) -{ - struct hfa384x_comp_ident comp; - int id, variant, major, minor; - - if (hfa384x_get_rid(local->dev, HFA384X_RID_STAID, - &comp, sizeof(comp), 1) < 0) - return; - - local->fw_ap = 0; - id = le16_to_cpu(comp.id); - if (id != HFA384X_COMP_ID_STA) { - if (id == HFA384X_COMP_ID_FW_AP) - local->fw_ap = 1; - return; - } - - major = __le16_to_cpu(comp.major); - minor = __le16_to_cpu(comp.minor); - variant = __le16_to_cpu(comp.variant); - local->sta_fw_ver = PRISM2_FW_VER(major, minor, variant); - - /* Station firmware versions before 1.4.x seem to have a bug in - * firmware-based WEP encryption when using Host AP mode, so use - * host_encrypt as a default for them. Firmware version 1.4.9 is the - * first one that has been seen to produce correct encryption, but the - * bug might be fixed before that (although, at least 1.4.2 is broken). - */ - local->fw_encrypt_ok = local->sta_fw_ver >= PRISM2_FW_VER(1,4,9); - - if (local->iw_mode == IW_MODE_MASTER && !local->host_encrypt && - !local->fw_encrypt_ok) { - printk(KERN_DEBUG "%s: defaulting to host-based encryption as " - "a workaround for firmware bug in Host AP mode WEP\n", - local->dev->name); - local->host_encrypt = 1; - } - - /* IEEE 802.11 standard compliant WDS frames (4 addresses) were broken - * in station firmware versions before 1.5.x. With these versions, the - * driver uses a workaround with bogus frame format (4th address after - * the payload). This is not compatible with other AP devices. Since - * the firmware bug is fixed in the latest station firmware versions, - * automatically enable standard compliant mode for cards using station - * firmware version 1.5.0 or newer. */ - if (local->sta_fw_ver >= PRISM2_FW_VER(1,5,0)) - local->wds_type |= HOSTAP_WDS_STANDARD_FRAME; - else { - printk(KERN_DEBUG "%s: defaulting to bogus WDS frame as a " - "workaround for firmware bug in Host AP mode WDS\n", - local->dev->name); - } - - hostap_check_sta_fw_version(local->ap, local->sta_fw_ver); -} - - -static void hostap_passive_scan(struct timer_list *t) -{ - local_info_t *local = from_timer(local, t, passive_scan_timer); - struct net_device *dev = local->dev; - u16 chan; - - if (local->passive_scan_interval <= 0) - return; - - if (local->passive_scan_state == PASSIVE_SCAN_LISTEN) { - int max_tries = 16; - - /* Even though host system does not really know when the WLAN - * MAC is sending frames, try to avoid changing channels for - * passive scanning when a host-generated frame is being - * transmitted */ - if (test_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) { - printk(KERN_DEBUG "%s: passive scan detected pending " - "TX - delaying\n", dev->name); - local->passive_scan_timer.expires = jiffies + HZ / 10; - add_timer(&local->passive_scan_timer); - return; - } - - do { - local->passive_scan_channel++; - if (local->passive_scan_channel > 14) - local->passive_scan_channel = 1; - max_tries--; - } while (!(local->channel_mask & - (1 << (local->passive_scan_channel - 1))) && - max_tries > 0); - - if (max_tries == 0) { - printk(KERN_INFO "%s: no allowed passive scan channels" - " found\n", dev->name); - return; - } - - printk(KERN_DEBUG "%s: passive scan channel %d\n", - dev->name, local->passive_scan_channel); - chan = local->passive_scan_channel; - local->passive_scan_state = PASSIVE_SCAN_WAIT; - local->passive_scan_timer.expires = jiffies + HZ / 10; - } else { - chan = local->channel; - local->passive_scan_state = PASSIVE_SCAN_LISTEN; - local->passive_scan_timer.expires = jiffies + - local->passive_scan_interval * HZ; - } - - if (hfa384x_cmd_callback(dev, HFA384X_CMDCODE_TEST | - (HFA384X_TEST_CHANGE_CHANNEL << 8), - chan, NULL, 0)) - printk(KERN_ERR "%s: passive scan channel set %d " - "failed\n", dev->name, chan); - - add_timer(&local->passive_scan_timer); -} - - -/* Called only as a scheduled task when communications quality values should - * be updated. */ -static void handle_comms_qual_update(struct work_struct *work) -{ - local_info_t *local = - container_of(work, local_info_t, comms_qual_update); - prism2_update_comms_qual(local->dev); -} - - -/* Software watchdog - called as a timer. Hardware interrupt (Tick event) is - * used to monitor that local->last_tick_timer is being updated. If not, - * interrupt busy-loop is assumed and driver tries to recover by masking out - * some events. */ -static void hostap_tick_timer(struct timer_list *t) -{ - static unsigned long last_inquire = 0; - local_info_t *local = from_timer(local, t, tick_timer); - local->last_tick_timer = jiffies; - - /* Inquire CommTallies every 10 seconds to keep the statistics updated - * more often during low load and when using 32-bit tallies. */ - if ((!last_inquire || time_after(jiffies, last_inquire + 10 * HZ)) && - !local->hw_downloading && local->hw_ready && - !local->hw_resetting && local->dev_enabled) { - hfa384x_cmd_callback(local->dev, HFA384X_CMDCODE_INQUIRE, - HFA384X_INFO_COMMTALLIES, NULL, 0); - last_inquire = jiffies; - } - - if ((local->last_comms_qual_update == 0 || - time_after(jiffies, local->last_comms_qual_update + 10 * HZ)) && - (local->iw_mode == IW_MODE_INFRA || - local->iw_mode == IW_MODE_ADHOC)) { - schedule_work(&local->comms_qual_update); - } - - local->tick_timer.expires = jiffies + 2 * HZ; - add_timer(&local->tick_timer); -} - - -#if !defined(PRISM2_NO_PROCFS_DEBUG) && defined(CONFIG_PROC_FS) -static u16 hfa384x_read_reg(struct net_device *dev, u16 reg) -{ - return HFA384X_INW(reg); -} - -static int prism2_registers_proc_show(struct seq_file *m, void *v) -{ - local_info_t *local = m->private; - -#define SHOW_REG(n) \ - seq_printf(m, #n "=%04x\n", hfa384x_read_reg(local->dev, HFA384X_##n##_OFF)) - - SHOW_REG(CMD); - SHOW_REG(PARAM0); - SHOW_REG(PARAM1); - SHOW_REG(PARAM2); - SHOW_REG(STATUS); - SHOW_REG(RESP0); - SHOW_REG(RESP1); - SHOW_REG(RESP2); - SHOW_REG(INFOFID); - SHOW_REG(CONTROL); - SHOW_REG(SELECT0); - SHOW_REG(SELECT1); - SHOW_REG(OFFSET0); - SHOW_REG(OFFSET1); - SHOW_REG(RXFID); - SHOW_REG(ALLOCFID); - SHOW_REG(TXCOMPLFID); - SHOW_REG(SWSUPPORT0); - SHOW_REG(SWSUPPORT1); - SHOW_REG(SWSUPPORT2); - SHOW_REG(EVSTAT); - SHOW_REG(INTEN); - SHOW_REG(EVACK); - /* Do not read data registers, because they change the state of the - * MAC (offset += 2) */ - /* SHOW_REG(DATA0); */ - /* SHOW_REG(DATA1); */ - SHOW_REG(AUXPAGE); - SHOW_REG(AUXOFFSET); - /* SHOW_REG(AUXDATA); */ -#ifdef PRISM2_PCI - SHOW_REG(PCICOR); - SHOW_REG(PCIHCR); - SHOW_REG(PCI_M0_ADDRH); - SHOW_REG(PCI_M0_ADDRL); - SHOW_REG(PCI_M0_LEN); - SHOW_REG(PCI_M0_CTL); - SHOW_REG(PCI_STATUS); - SHOW_REG(PCI_M1_ADDRH); - SHOW_REG(PCI_M1_ADDRL); - SHOW_REG(PCI_M1_LEN); - SHOW_REG(PCI_M1_CTL); -#endif /* PRISM2_PCI */ - - return 0; -} -#endif - -struct set_tim_data { - struct list_head list; - int aid; - int set; -}; - -static int prism2_set_tim(struct net_device *dev, int aid, int set) -{ - struct list_head *ptr; - struct set_tim_data *new_entry; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - new_entry = kzalloc(sizeof(*new_entry), GFP_ATOMIC); - if (new_entry == NULL) - return -ENOMEM; - - new_entry->aid = aid; - new_entry->set = set; - - spin_lock_bh(&local->set_tim_lock); - list_for_each(ptr, &local->set_tim_list) { - struct set_tim_data *entry = - list_entry(ptr, struct set_tim_data, list); - if (entry->aid == aid) { - PDEBUG(DEBUG_PS2, "%s: prism2_set_tim: aid=%d " - "set=%d ==> %d\n", - local->dev->name, aid, entry->set, set); - entry->set = set; - kfree(new_entry); - new_entry = NULL; - break; - } - } - if (new_entry) - list_add_tail(&new_entry->list, &local->set_tim_list); - spin_unlock_bh(&local->set_tim_lock); - - schedule_work(&local->set_tim_queue); - - return 0; -} - - -static void handle_set_tim_queue(struct work_struct *work) -{ - local_info_t *local = container_of(work, local_info_t, set_tim_queue); - struct set_tim_data *entry; - u16 val; - - for (;;) { - entry = NULL; - spin_lock_bh(&local->set_tim_lock); - if (!list_empty(&local->set_tim_list)) { - entry = list_entry(local->set_tim_list.next, - struct set_tim_data, list); - list_del(&entry->list); - } - spin_unlock_bh(&local->set_tim_lock); - if (!entry) - break; - - PDEBUG(DEBUG_PS2, "%s: handle_set_tim_queue: aid=%d set=%d\n", - local->dev->name, entry->aid, entry->set); - - val = entry->aid; - if (entry->set) - val |= 0x8000; - if (hostap_set_word(local->dev, HFA384X_RID_CNFTIMCTRL, val)) { - printk(KERN_DEBUG "%s: set_tim failed (aid=%d " - "set=%d)\n", - local->dev->name, entry->aid, entry->set); - } - - kfree(entry); - } -} - - -static void prism2_clear_set_tim_queue(local_info_t *local) -{ - struct list_head *ptr, *n; - - list_for_each_safe(ptr, n, &local->set_tim_list) { - struct set_tim_data *entry; - entry = list_entry(ptr, struct set_tim_data, list); - list_del(&entry->list); - kfree(entry); - } -} - - -/* - * HostAP uses two layers of net devices, where the inner - * layer gets called all the time from the outer layer. - * This is a natural nesting, which needs a split lock type. - */ -static struct lock_class_key hostap_netdev_xmit_lock_key; -static struct lock_class_key hostap_netdev_addr_lock_key; - -static void prism2_set_lockdep_class_one(struct net_device *dev, - struct netdev_queue *txq, - void *_unused) -{ - lockdep_set_class(&txq->_xmit_lock, - &hostap_netdev_xmit_lock_key); -} - -static void prism2_set_lockdep_class(struct net_device *dev) -{ - lockdep_set_class(&dev->addr_list_lock, - &hostap_netdev_addr_lock_key); - netdev_for_each_tx_queue(dev, prism2_set_lockdep_class_one, NULL); -} - -static struct net_device * -prism2_init_local_data(struct prism2_helper_functions *funcs, int card_idx, - struct device *sdev) -{ - struct net_device *dev; - struct hostap_interface *iface; - struct local_info *local; - int len, i, ret; - - if (funcs == NULL) - return NULL; - - len = strlen(dev_template); - if (len >= IFNAMSIZ || strstr(dev_template, "%d") == NULL) { - printk(KERN_WARNING "hostap: Invalid dev_template='%s'\n", - dev_template); - return NULL; - } - - len = sizeof(struct hostap_interface) + - 3 + sizeof(struct local_info) + - 3 + sizeof(struct ap_data); - - dev = alloc_etherdev(len); - if (dev == NULL) - return NULL; - - iface = netdev_priv(dev); - local = (struct local_info *) ((((long) (iface + 1)) + 3) & ~3); - local->ap = (struct ap_data *) ((((long) (local + 1)) + 3) & ~3); - local->dev = iface->dev = dev; - iface->local = local; - iface->type = HOSTAP_INTERFACE_MASTER; - INIT_LIST_HEAD(&local->hostap_interfaces); - - local->hw_module = THIS_MODULE; - -#ifdef PRISM2_IO_DEBUG - local->io_debug_enabled = 1; -#endif /* PRISM2_IO_DEBUG */ - - local->func = funcs; - local->func->cmd = hfa384x_cmd; - local->func->read_regs = hfa384x_read_regs; - local->func->get_rid = hfa384x_get_rid; - local->func->set_rid = hfa384x_set_rid; - local->func->hw_enable = prism2_hw_enable; - local->func->hw_config = prism2_hw_config; - local->func->hw_reset = prism2_hw_reset; - local->func->hw_shutdown = prism2_hw_shutdown; - local->func->reset_port = prism2_reset_port; - local->func->schedule_reset = prism2_schedule_reset; -#ifdef PRISM2_DOWNLOAD_SUPPORT - local->func->read_aux_proc_ops = &prism2_download_aux_dump_proc_ops; - local->func->download = prism2_download; -#endif /* PRISM2_DOWNLOAD_SUPPORT */ - local->func->tx = prism2_tx_80211; - local->func->set_tim = prism2_set_tim; - local->func->need_tx_headroom = 0; /* no need to add txdesc in - * skb->data (FIX: maybe for DMA bus - * mastering? */ - - local->mtu = mtu; - - rwlock_init(&local->iface_lock); - spin_lock_init(&local->txfidlock); - spin_lock_init(&local->cmdlock); - spin_lock_init(&local->baplock); - spin_lock_init(&local->lock); - spin_lock_init(&local->irq_init_lock); - mutex_init(&local->rid_bap_mtx); - - if (card_idx < 0 || card_idx >= MAX_PARM_DEVICES) - card_idx = 0; - local->card_idx = card_idx; - - len = strlen(essid); - memcpy(local->essid, essid, - len > MAX_SSID_LEN ? MAX_SSID_LEN : len); - local->essid[MAX_SSID_LEN] = '\0'; - i = GET_INT_PARM(iw_mode, card_idx); - if ((i >= IW_MODE_ADHOC && i <= IW_MODE_REPEAT) || - i == IW_MODE_MONITOR) { - local->iw_mode = i; - } else { - printk(KERN_WARNING "prism2: Unknown iw_mode %d; using " - "IW_MODE_MASTER\n", i); - local->iw_mode = IW_MODE_MASTER; - } - local->channel = GET_INT_PARM(channel, card_idx); - local->beacon_int = GET_INT_PARM(beacon_int, card_idx); - local->dtim_period = GET_INT_PARM(dtim_period, card_idx); - local->wds_max_connections = 16; - local->tx_control = HFA384X_TX_CTRL_FLAGS; - local->manual_retry_count = -1; - local->rts_threshold = 2347; - local->fragm_threshold = 2346; - local->rssi_to_dBm = 100; /* default; to be overriden by - * cnfDbmAdjust, if available */ - local->auth_algs = PRISM2_AUTH_OPEN | PRISM2_AUTH_SHARED_KEY; - local->sram_type = -1; - local->scan_channel_mask = 0xffff; - local->monitor_type = PRISM2_MONITOR_RADIOTAP; - - /* Initialize task queue structures */ - INIT_WORK(&local->reset_queue, handle_reset_queue); - INIT_WORK(&local->set_multicast_list_queue, - hostap_set_multicast_list_queue); - - INIT_WORK(&local->set_tim_queue, handle_set_tim_queue); - INIT_LIST_HEAD(&local->set_tim_list); - spin_lock_init(&local->set_tim_lock); - - INIT_WORK(&local->comms_qual_update, handle_comms_qual_update); - - /* Initialize tasklets for handling hardware IRQ related operations - * outside hw IRQ handler */ - tasklet_setup(&local->bap_tasklet, hostap_bap_tasklet); - tasklet_setup(&local->info_tasklet, hostap_info_tasklet); - hostap_info_init(local); - - tasklet_setup(&local->rx_tasklet, hostap_rx_tasklet); - skb_queue_head_init(&local->rx_list); - - tasklet_setup(&local->sta_tx_exc_tasklet, - hostap_sta_tx_exc_tasklet); - skb_queue_head_init(&local->sta_tx_exc_list); - - INIT_LIST_HEAD(&local->cmd_queue); - init_waitqueue_head(&local->hostscan_wq); - - lib80211_crypt_info_init(&local->crypt_info, dev->name, &local->lock); - - timer_setup(&local->passive_scan_timer, hostap_passive_scan, 0); - timer_setup(&local->tick_timer, hostap_tick_timer, 0); - local->tick_timer.expires = jiffies + 2 * HZ; - add_timer(&local->tick_timer); - - INIT_LIST_HEAD(&local->bss_list); - - hostap_setup_dev(dev, local, HOSTAP_INTERFACE_MASTER); - - dev->type = ARPHRD_IEEE80211; - dev->header_ops = &hostap_80211_ops; - - rtnl_lock(); - ret = dev_alloc_name(dev, "wifi%d"); - SET_NETDEV_DEV(dev, sdev); - if (ret >= 0) - ret = register_netdevice(dev); - - prism2_set_lockdep_class(dev); - rtnl_unlock(); - if (ret < 0) { - printk(KERN_WARNING "%s: register netdevice failed!\n", - dev_info); - goto fail; - } - printk(KERN_INFO "%s: Registered netdevice %s\n", dev_info, dev->name); - - hostap_init_data(local); - return dev; - - fail: - free_netdev(dev); - return NULL; -} - - -static int hostap_hw_ready(struct net_device *dev) -{ - struct hostap_interface *iface; - struct local_info *local; - - iface = netdev_priv(dev); - local = iface->local; - local->ddev = hostap_add_interface(local, HOSTAP_INTERFACE_MAIN, 0, - "", dev_template); - - if (local->ddev) { - if (local->iw_mode == IW_MODE_INFRA || - local->iw_mode == IW_MODE_ADHOC) { - netif_carrier_off(local->dev); - netif_carrier_off(local->ddev); - } - hostap_init_proc(local); -#ifndef PRISM2_NO_PROCFS_DEBUG - proc_create_single_data("registers", 0, local->proc, - prism2_registers_proc_show, local); -#endif /* PRISM2_NO_PROCFS_DEBUG */ - hostap_init_ap_proc(local); - return 0; - } - - return -1; -} - - -static void prism2_free_local_data(struct net_device *dev) -{ - struct hostap_tx_callback_info *tx_cb, *tx_cb_prev; - int i; - struct hostap_interface *iface; - struct local_info *local; - struct list_head *ptr, *n; - - if (dev == NULL) - return; - - iface = netdev_priv(dev); - local = iface->local; - - /* Unregister all netdevs before freeing local data. */ - list_for_each_safe(ptr, n, &local->hostap_interfaces) { - iface = list_entry(ptr, struct hostap_interface, list); - if (iface->type == HOSTAP_INTERFACE_MASTER) { - /* special handling for this interface below */ - continue; - } - hostap_remove_interface(iface->dev, 0, 1); - } - - unregister_netdev(local->dev); - - flush_work(&local->reset_queue); - flush_work(&local->set_multicast_list_queue); - flush_work(&local->set_tim_queue); -#ifndef PRISM2_NO_STATION_MODES - flush_work(&local->info_queue); -#endif - flush_work(&local->comms_qual_update); - - lib80211_crypt_info_free(&local->crypt_info); - - if (timer_pending(&local->passive_scan_timer)) - del_timer(&local->passive_scan_timer); - - if (timer_pending(&local->tick_timer)) - del_timer(&local->tick_timer); - - prism2_clear_cmd_queue(local); - - skb_queue_purge(&local->info_list); - skb_queue_purge(&local->rx_list); - skb_queue_purge(&local->sta_tx_exc_list); - - if (local->dev_enabled) - prism2_callback(local, PRISM2_CALLBACK_DISABLE); - - if (local->ap != NULL) - hostap_free_data(local->ap); - -#ifndef PRISM2_NO_PROCFS_DEBUG - if (local->proc != NULL) - remove_proc_entry("registers", local->proc); -#endif /* PRISM2_NO_PROCFS_DEBUG */ - hostap_remove_proc(local); - - tx_cb = local->tx_callback; - while (tx_cb != NULL) { - tx_cb_prev = tx_cb; - tx_cb = tx_cb->next; - kfree(tx_cb_prev); - } - - hostap_set_hostapd(local, 0, 0); - hostap_set_hostapd_sta(local, 0, 0); - - for (i = 0; i < PRISM2_FRAG_CACHE_LEN; i++) { - if (local->frag_cache[i].skb != NULL) - dev_kfree_skb(local->frag_cache[i].skb); - } - -#ifdef PRISM2_DOWNLOAD_SUPPORT - prism2_download_free_data(local->dl_pri); - prism2_download_free_data(local->dl_sec); -#endif /* PRISM2_DOWNLOAD_SUPPORT */ - - prism2_clear_set_tim_queue(local); - - list_for_each_safe(ptr, n, &local->bss_list) { - struct hostap_bss_info *bss = - list_entry(ptr, struct hostap_bss_info, list); - kfree(bss); - } - - kfree(local->pda); - kfree(local->last_scan_results); - kfree(local->generic_elem); - - free_netdev(local->dev); -} - - -#if defined(PRISM2_PCI) || defined(PRISM2_PCCARD) -static void __maybe_unused prism2_suspend(struct net_device *dev) -{ - struct hostap_interface *iface; - struct local_info *local; - union iwreq_data wrqu; - - iface = netdev_priv(dev); - local = iface->local; - - /* Send disconnect event, e.g., to trigger reassociation after resume - * if wpa_supplicant is used. */ - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL); - - /* Disable hardware and firmware */ - prism2_hw_shutdown(dev, 0); -} -#endif /* PRISM2_PCI || PRISM2_PCCARD */ - - -/* These might at some point be compiled separately and used as separate - * kernel modules or linked into one */ -#ifdef PRISM2_DOWNLOAD_SUPPORT -#include "hostap_download.c" -#endif /* PRISM2_DOWNLOAD_SUPPORT */ - -#ifdef PRISM2_CALLBACK -/* External hostap_callback.c file can be used to, e.g., blink activity led. - * This can use platform specific code and must define prism2_callback() - * function (if PRISM2_CALLBACK is not defined, these function calls are not - * used. */ -#include "hostap_callback.c" -#endif /* PRISM2_CALLBACK */ diff --git a/drivers/net/wireless/intersil/hostap/hostap_info.c b/drivers/net/wireless/intersil/hostap/hostap_info.c deleted file mode 100644 index da8c30f10d923..0000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_info.c +++ /dev/null @@ -1,509 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Host AP driver Info Frame processing (part of hostap.o module) */ - -#include -#include -#include -#include -#include -#include "hostap_wlan.h" -#include "hostap.h" -#include "hostap_ap.h" - -/* Called only as a tasklet (software IRQ) */ -static void prism2_info_commtallies16(local_info_t *local, unsigned char *buf, - int left) -{ - struct hfa384x_comm_tallies *tallies; - - if (left < sizeof(struct hfa384x_comm_tallies)) { - printk(KERN_DEBUG "%s: too short (len=%d) commtallies " - "info frame\n", local->dev->name, left); - return; - } - - tallies = (struct hfa384x_comm_tallies *) buf; -#define ADD_COMM_TALLIES(name) \ -local->comm_tallies.name += le16_to_cpu(tallies->name) - ADD_COMM_TALLIES(tx_unicast_frames); - ADD_COMM_TALLIES(tx_multicast_frames); - ADD_COMM_TALLIES(tx_fragments); - ADD_COMM_TALLIES(tx_unicast_octets); - ADD_COMM_TALLIES(tx_multicast_octets); - ADD_COMM_TALLIES(tx_deferred_transmissions); - ADD_COMM_TALLIES(tx_single_retry_frames); - ADD_COMM_TALLIES(tx_multiple_retry_frames); - ADD_COMM_TALLIES(tx_retry_limit_exceeded); - ADD_COMM_TALLIES(tx_discards); - ADD_COMM_TALLIES(rx_unicast_frames); - ADD_COMM_TALLIES(rx_multicast_frames); - ADD_COMM_TALLIES(rx_fragments); - ADD_COMM_TALLIES(rx_unicast_octets); - ADD_COMM_TALLIES(rx_multicast_octets); - ADD_COMM_TALLIES(rx_fcs_errors); - ADD_COMM_TALLIES(rx_discards_no_buffer); - ADD_COMM_TALLIES(tx_discards_wrong_sa); - ADD_COMM_TALLIES(rx_discards_wep_undecryptable); - ADD_COMM_TALLIES(rx_message_in_msg_fragments); - ADD_COMM_TALLIES(rx_message_in_bad_msg_fragments); -#undef ADD_COMM_TALLIES -} - - -/* Called only as a tasklet (software IRQ) */ -static void prism2_info_commtallies32(local_info_t *local, unsigned char *buf, - int left) -{ - struct hfa384x_comm_tallies32 *tallies; - - if (left < sizeof(struct hfa384x_comm_tallies32)) { - printk(KERN_DEBUG "%s: too short (len=%d) commtallies32 " - "info frame\n", local->dev->name, left); - return; - } - - tallies = (struct hfa384x_comm_tallies32 *) buf; -#define ADD_COMM_TALLIES(name) \ -local->comm_tallies.name += le32_to_cpu(tallies->name) - ADD_COMM_TALLIES(tx_unicast_frames); - ADD_COMM_TALLIES(tx_multicast_frames); - ADD_COMM_TALLIES(tx_fragments); - ADD_COMM_TALLIES(tx_unicast_octets); - ADD_COMM_TALLIES(tx_multicast_octets); - ADD_COMM_TALLIES(tx_deferred_transmissions); - ADD_COMM_TALLIES(tx_single_retry_frames); - ADD_COMM_TALLIES(tx_multiple_retry_frames); - ADD_COMM_TALLIES(tx_retry_limit_exceeded); - ADD_COMM_TALLIES(tx_discards); - ADD_COMM_TALLIES(rx_unicast_frames); - ADD_COMM_TALLIES(rx_multicast_frames); - ADD_COMM_TALLIES(rx_fragments); - ADD_COMM_TALLIES(rx_unicast_octets); - ADD_COMM_TALLIES(rx_multicast_octets); - ADD_COMM_TALLIES(rx_fcs_errors); - ADD_COMM_TALLIES(rx_discards_no_buffer); - ADD_COMM_TALLIES(tx_discards_wrong_sa); - ADD_COMM_TALLIES(rx_discards_wep_undecryptable); - ADD_COMM_TALLIES(rx_message_in_msg_fragments); - ADD_COMM_TALLIES(rx_message_in_bad_msg_fragments); -#undef ADD_COMM_TALLIES -} - - -/* Called only as a tasklet (software IRQ) */ -static void prism2_info_commtallies(local_info_t *local, unsigned char *buf, - int left) -{ - if (local->tallies32) - prism2_info_commtallies32(local, buf, left); - else - prism2_info_commtallies16(local, buf, left); -} - - -#ifndef PRISM2_NO_STATION_MODES -#ifndef PRISM2_NO_DEBUG -static const char* hfa384x_linkstatus_str(u16 linkstatus) -{ - switch (linkstatus) { - case HFA384X_LINKSTATUS_CONNECTED: - return "Connected"; - case HFA384X_LINKSTATUS_DISCONNECTED: - return "Disconnected"; - case HFA384X_LINKSTATUS_AP_CHANGE: - return "Access point change"; - case HFA384X_LINKSTATUS_AP_OUT_OF_RANGE: - return "Access point out of range"; - case HFA384X_LINKSTATUS_AP_IN_RANGE: - return "Access point in range"; - case HFA384X_LINKSTATUS_ASSOC_FAILED: - return "Association failed"; - default: - return "Unknown"; - } -} -#endif /* PRISM2_NO_DEBUG */ - - -/* Called only as a tasklet (software IRQ) */ -static void prism2_info_linkstatus(local_info_t *local, unsigned char *buf, - int left) -{ - u16 val; - int non_sta_mode; - - /* Alloc new JoinRequests to occur since LinkStatus for the previous - * has been received */ - local->last_join_time = 0; - - if (left != 2) { - printk(KERN_DEBUG "%s: invalid linkstatus info frame " - "length %d\n", local->dev->name, left); - return; - } - - non_sta_mode = local->iw_mode == IW_MODE_MASTER || - local->iw_mode == IW_MODE_REPEAT || - local->iw_mode == IW_MODE_MONITOR; - - val = buf[0] | (buf[1] << 8); - if (!non_sta_mode || val != HFA384X_LINKSTATUS_DISCONNECTED) { - PDEBUG(DEBUG_EXTRA, "%s: LinkStatus=%d (%s)\n", - local->dev->name, val, hfa384x_linkstatus_str(val)); - } - - if (non_sta_mode) { - netif_carrier_on(local->dev); - netif_carrier_on(local->ddev); - return; - } - - /* Get current BSSID later in scheduled task */ - set_bit(PRISM2_INFO_PENDING_LINKSTATUS, &local->pending_info); - local->prev_link_status = val; - schedule_work(&local->info_queue); -} - - -static void prism2_host_roaming(local_info_t *local) -{ - struct hfa384x_join_request req; - struct net_device *dev = local->dev; - struct hfa384x_hostscan_result *selected, *entry; - int i; - unsigned long flags; - - if (local->last_join_time && - time_before(jiffies, local->last_join_time + 10 * HZ)) { - PDEBUG(DEBUG_EXTRA, "%s: last join request has not yet been " - "completed - waiting for it before issuing new one\n", - dev->name); - return; - } - - /* ScanResults are sorted: first ESS results in decreasing signal - * quality then IBSS results in similar order. - * Trivial roaming policy: just select the first entry. - * This could probably be improved by adding hysteresis to limit - * number of handoffs, etc. - * - * Could do periodic RID_SCANREQUEST or Inquire F101 to get new - * ScanResults */ - spin_lock_irqsave(&local->lock, flags); - if (local->last_scan_results == NULL || - local->last_scan_results_count == 0) { - spin_unlock_irqrestore(&local->lock, flags); - PDEBUG(DEBUG_EXTRA, "%s: no scan results for host roaming\n", - dev->name); - return; - } - - selected = &local->last_scan_results[0]; - - if (local->preferred_ap[0] || local->preferred_ap[1] || - local->preferred_ap[2] || local->preferred_ap[3] || - local->preferred_ap[4] || local->preferred_ap[5]) { - /* Try to find preferred AP */ - PDEBUG(DEBUG_EXTRA, "%s: Preferred AP BSSID %pM\n", - dev->name, local->preferred_ap); - for (i = 0; i < local->last_scan_results_count; i++) { - entry = &local->last_scan_results[i]; - if (memcmp(local->preferred_ap, entry->bssid, 6) == 0) - { - PDEBUG(DEBUG_EXTRA, "%s: using preferred AP " - "selection\n", dev->name); - selected = entry; - break; - } - } - } - - memcpy(req.bssid, selected->bssid, ETH_ALEN); - req.channel = selected->chid; - spin_unlock_irqrestore(&local->lock, flags); - - PDEBUG(DEBUG_EXTRA, "%s: JoinRequest: BSSID=%pM" - " channel=%d\n", - dev->name, req.bssid, le16_to_cpu(req.channel)); - if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req, - sizeof(req))) { - printk(KERN_DEBUG "%s: JoinRequest failed\n", dev->name); - } - local->last_join_time = jiffies; -} - - -static void hostap_report_scan_complete(local_info_t *local) -{ - union iwreq_data wrqu; - - /* Inform user space about new scan results (just empty event, - * SIOCGIWSCAN can be used to fetch data */ - wrqu.data.length = 0; - wrqu.data.flags = 0; - wireless_send_event(local->dev, SIOCGIWSCAN, &wrqu, NULL); - - /* Allow SIOCGIWSCAN handling to occur since we have received - * scanning result */ - local->scan_timestamp = 0; -} - - -/* Called only as a tasklet (software IRQ) */ -static void prism2_info_scanresults(local_info_t *local, unsigned char *buf, - int left) -{ - u16 *pos; - int new_count, i; - unsigned long flags; - struct hfa384x_scan_result *res; - struct hfa384x_hostscan_result *results, *prev; - - if (left < 4) { - printk(KERN_DEBUG "%s: invalid scanresult info frame " - "length %d\n", local->dev->name, left); - return; - } - - pos = (u16 *) buf; - pos++; - pos++; - left -= 4; - - new_count = left / sizeof(struct hfa384x_scan_result); - results = kmalloc_array(new_count, - sizeof(struct hfa384x_hostscan_result), - GFP_ATOMIC); - if (results == NULL) - return; - - /* Convert to hostscan result format. */ - res = (struct hfa384x_scan_result *) pos; - for (i = 0; i < new_count; i++) { - memcpy(&results[i], &res[i], - sizeof(struct hfa384x_scan_result)); - results[i].atim = 0; - } - - spin_lock_irqsave(&local->lock, flags); - local->last_scan_type = PRISM2_SCAN; - prev = local->last_scan_results; - local->last_scan_results = results; - local->last_scan_results_count = new_count; - spin_unlock_irqrestore(&local->lock, flags); - kfree(prev); - - hostap_report_scan_complete(local); - - /* Perform rest of ScanResults handling later in scheduled task */ - set_bit(PRISM2_INFO_PENDING_SCANRESULTS, &local->pending_info); - schedule_work(&local->info_queue); -} - - -/* Called only as a tasklet (software IRQ) */ -static void prism2_info_hostscanresults(local_info_t *local, - unsigned char *buf, int left) -{ - int i, result_size, copy_len, new_count; - struct hfa384x_hostscan_result *results, *prev; - unsigned long flags; - __le16 *pos; - u8 *ptr; - - wake_up_interruptible(&local->hostscan_wq); - - if (left < 4) { - printk(KERN_DEBUG "%s: invalid hostscanresult info frame " - "length %d\n", local->dev->name, left); - return; - } - - pos = (__le16 *) buf; - copy_len = result_size = le16_to_cpu(*pos); - if (result_size == 0) { - printk(KERN_DEBUG "%s: invalid result_size (0) in " - "hostscanresults\n", local->dev->name); - return; - } - if (copy_len > sizeof(struct hfa384x_hostscan_result)) - copy_len = sizeof(struct hfa384x_hostscan_result); - - pos++; - pos++; - left -= 4; - ptr = (u8 *) pos; - - new_count = left / result_size; - results = kcalloc(new_count, sizeof(struct hfa384x_hostscan_result), - GFP_ATOMIC); - if (results == NULL) - return; - - for (i = 0; i < new_count; i++) { - memcpy(&results[i], ptr, copy_len); - ptr += result_size; - left -= result_size; - } - - if (left) { - printk(KERN_DEBUG "%s: short HostScan result entry (%d/%d)\n", - local->dev->name, left, result_size); - } - - spin_lock_irqsave(&local->lock, flags); - local->last_scan_type = PRISM2_HOSTSCAN; - prev = local->last_scan_results; - local->last_scan_results = results; - local->last_scan_results_count = new_count; - spin_unlock_irqrestore(&local->lock, flags); - kfree(prev); - - hostap_report_scan_complete(local); -} -#endif /* PRISM2_NO_STATION_MODES */ - - -/* Called only as a tasklet (software IRQ) */ -void hostap_info_process(local_info_t *local, struct sk_buff *skb) -{ - struct hfa384x_info_frame *info; - unsigned char *buf; - int left; -#ifndef PRISM2_NO_DEBUG - int i; -#endif /* PRISM2_NO_DEBUG */ - - info = (struct hfa384x_info_frame *) skb->data; - buf = skb->data + sizeof(*info); - left = skb->len - sizeof(*info); - - switch (le16_to_cpu(info->type)) { - case HFA384X_INFO_COMMTALLIES: - prism2_info_commtallies(local, buf, left); - break; - -#ifndef PRISM2_NO_STATION_MODES - case HFA384X_INFO_LINKSTATUS: - prism2_info_linkstatus(local, buf, left); - break; - - case HFA384X_INFO_SCANRESULTS: - prism2_info_scanresults(local, buf, left); - break; - - case HFA384X_INFO_HOSTSCANRESULTS: - prism2_info_hostscanresults(local, buf, left); - break; -#endif /* PRISM2_NO_STATION_MODES */ - -#ifndef PRISM2_NO_DEBUG - default: - PDEBUG(DEBUG_EXTRA, "%s: INFO - len=%d type=0x%04x\n", - local->dev->name, le16_to_cpu(info->len), - le16_to_cpu(info->type)); - PDEBUG(DEBUG_EXTRA, "Unknown info frame:"); - for (i = 0; i < (left < 100 ? left : 100); i++) - PDEBUG2(DEBUG_EXTRA, " %02x", buf[i]); - PDEBUG2(DEBUG_EXTRA, "\n"); - break; -#endif /* PRISM2_NO_DEBUG */ - } -} - - -#ifndef PRISM2_NO_STATION_MODES -static void handle_info_queue_linkstatus(local_info_t *local) -{ - int val = local->prev_link_status; - int connected; - union iwreq_data wrqu; - - connected = - val == HFA384X_LINKSTATUS_CONNECTED || - val == HFA384X_LINKSTATUS_AP_CHANGE || - val == HFA384X_LINKSTATUS_AP_IN_RANGE; - - if (local->func->get_rid(local->dev, HFA384X_RID_CURRENTBSSID, - local->bssid, ETH_ALEN, 1) < 0) { - printk(KERN_DEBUG "%s: could not read CURRENTBSSID after " - "LinkStatus event\n", local->dev->name); - } else { - PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID=%pM\n", - local->dev->name, - (unsigned char *) local->bssid); - if (local->wds_type & HOSTAP_WDS_AP_CLIENT) - hostap_add_sta(local->ap, local->bssid); - } - - /* Get BSSID if we have a valid AP address */ - if (connected) { - netif_carrier_on(local->dev); - netif_carrier_on(local->ddev); - memcpy(wrqu.ap_addr.sa_data, local->bssid, ETH_ALEN); - } else { - netif_carrier_off(local->dev); - netif_carrier_off(local->ddev); - eth_zero_addr(wrqu.ap_addr.sa_data); - } - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - - /* - * Filter out sequential disconnect events in order not to cause a - * flood of SIOCGIWAP events that have a race condition with EAPOL - * frames and can confuse wpa_supplicant about the current association - * status. - */ - if (connected || local->prev_linkstatus_connected) - wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL); - local->prev_linkstatus_connected = connected; -} - - -static void handle_info_queue_scanresults(local_info_t *local) -{ - if (local->host_roaming == 1 && local->iw_mode == IW_MODE_INFRA) - prism2_host_roaming(local); - - if (local->host_roaming == 2 && local->iw_mode == IW_MODE_INFRA && - !is_zero_ether_addr(local->preferred_ap)) { - /* - * Firmware seems to be getting into odd state in host_roaming - * mode 2 when hostscan is used without join command, so try - * to fix this by re-joining the current AP. This does not - * actually trigger a new association if the current AP is - * still in the scan results. - */ - prism2_host_roaming(local); - } -} - - -/* Called only as scheduled task after receiving info frames (used to avoid - * pending too much time in HW IRQ handler). */ -static void handle_info_queue(struct work_struct *work) -{ - local_info_t *local = container_of(work, local_info_t, info_queue); - - if (test_and_clear_bit(PRISM2_INFO_PENDING_LINKSTATUS, - &local->pending_info)) - handle_info_queue_linkstatus(local); - - if (test_and_clear_bit(PRISM2_INFO_PENDING_SCANRESULTS, - &local->pending_info)) - handle_info_queue_scanresults(local); -} -#endif /* PRISM2_NO_STATION_MODES */ - - -void hostap_info_init(local_info_t *local) -{ - skb_queue_head_init(&local->info_list); -#ifndef PRISM2_NO_STATION_MODES - INIT_WORK(&local->info_queue, handle_info_queue); -#endif /* PRISM2_NO_STATION_MODES */ -} - - -EXPORT_SYMBOL(hostap_info_init); -EXPORT_SYMBOL(hostap_info_process); diff --git a/drivers/net/wireless/intersil/hostap/hostap_ioctl.c b/drivers/net/wireless/intersil/hostap/hostap_ioctl.c deleted file mode 100644 index 26162f92e3c3d..0000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_ioctl.c +++ /dev/null @@ -1,3847 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* ioctl() (mostly Linux Wireless Extensions) routines for Host AP driver */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "hostap_wlan.h" -#include "hostap.h" -#include "hostap_ap.h" - -static struct iw_statistics *hostap_get_wireless_stats(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - struct iw_statistics *wstats; - - iface = netdev_priv(dev); - local = iface->local; - - /* Why are we doing that ? Jean II */ - if (iface->type != HOSTAP_INTERFACE_MAIN) - return NULL; - - wstats = &local->wstats; - - wstats->status = 0; - wstats->discard.code = - local->comm_tallies.rx_discards_wep_undecryptable; - wstats->discard.misc = - local->comm_tallies.rx_fcs_errors + - local->comm_tallies.rx_discards_no_buffer + - local->comm_tallies.tx_discards_wrong_sa; - - wstats->discard.retries = - local->comm_tallies.tx_retry_limit_exceeded; - wstats->discard.fragment = - local->comm_tallies.rx_message_in_bad_msg_fragments; - - if (local->iw_mode != IW_MODE_MASTER && - local->iw_mode != IW_MODE_REPEAT) { - - if (prism2_update_comms_qual(dev) == 0) - wstats->qual.updated = IW_QUAL_ALL_UPDATED | - IW_QUAL_DBM; - - wstats->qual.qual = local->comms_qual; - wstats->qual.level = local->avg_signal; - wstats->qual.noise = local->avg_noise; - } else { - wstats->qual.qual = 0; - wstats->qual.level = 0; - wstats->qual.noise = 0; - wstats->qual.updated = IW_QUAL_ALL_INVALID; - } - - return wstats; -} - - -static int prism2_get_datarates(struct net_device *dev, u8 *rates) -{ - struct hostap_interface *iface; - local_info_t *local; - u8 buf[12]; - int len; - u16 val; - - iface = netdev_priv(dev); - local = iface->local; - - len = local->func->get_rid(dev, HFA384X_RID_SUPPORTEDDATARATES, buf, - sizeof(buf), 0); - if (len < 2) - return 0; - - val = le16_to_cpu(*(__le16 *) buf); /* string length */ - - if (len - 2 < val || val > 10) - return 0; - - memcpy(rates, buf + 2, val); - return val; -} - - -static int prism2_get_name(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - u8 rates[10]; - int len, i, over2 = 0; - - len = prism2_get_datarates(dev, rates); - - for (i = 0; i < len; i++) { - if (rates[i] == 0x0b || rates[i] == 0x16) { - over2 = 1; - break; - } - } - - strcpy(wrqu->name, over2 ? "IEEE 802.11b" : "IEEE 802.11-DS"); - - return 0; -} - - -static int prism2_ioctl_siwencode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *keybuf) -{ - struct iw_point *erq = &wrqu->encoding; - struct hostap_interface *iface; - local_info_t *local; - int i; - struct lib80211_crypt_data **crypt; - - iface = netdev_priv(dev); - local = iface->local; - - i = erq->flags & IW_ENCODE_INDEX; - if (i < 1 || i > 4) - i = local->crypt_info.tx_keyidx; - else - i--; - if (i < 0 || i >= WEP_KEYS) - return -EINVAL; - - crypt = &local->crypt_info.crypt[i]; - - if (erq->flags & IW_ENCODE_DISABLED) { - if (*crypt) - lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); - goto done; - } - - if (*crypt != NULL && (*crypt)->ops != NULL && - strcmp((*crypt)->ops->name, "WEP") != 0) { - /* changing to use WEP; deinit previously used algorithm */ - lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); - } - - if (*crypt == NULL) { - struct lib80211_crypt_data *new_crypt; - - /* take WEP into use */ - new_crypt = kzalloc(sizeof(struct lib80211_crypt_data), - GFP_KERNEL); - if (new_crypt == NULL) - return -ENOMEM; - new_crypt->ops = lib80211_get_crypto_ops("WEP"); - if (!new_crypt->ops) { - request_module("lib80211_crypt_wep"); - new_crypt->ops = lib80211_get_crypto_ops("WEP"); - } - if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) - new_crypt->priv = new_crypt->ops->init(i); - if (!new_crypt->ops || !new_crypt->priv) { - kfree(new_crypt); - new_crypt = NULL; - - printk(KERN_WARNING "%s: could not initialize WEP: " - "load module hostap_crypt_wep.o\n", - dev->name); - return -EOPNOTSUPP; - } - *crypt = new_crypt; - } - - if (erq->length > 0) { - int len = erq->length <= 5 ? 5 : 13; - int first = 1, j; - if (len > erq->length) - memset(keybuf + erq->length, 0, len - erq->length); - (*crypt)->ops->set_key(keybuf, len, NULL, (*crypt)->priv); - for (j = 0; j < WEP_KEYS; j++) { - if (j != i && local->crypt_info.crypt[j]) { - first = 0; - break; - } - } - if (first) - local->crypt_info.tx_keyidx = i; - } else { - /* No key data - just set the default TX key index */ - local->crypt_info.tx_keyidx = i; - } - - done: - local->open_wep = erq->flags & IW_ENCODE_OPEN; - - if (hostap_set_encryption(local)) { - printk(KERN_DEBUG "%s: set_encryption failed\n", dev->name); - return -EINVAL; - } - - /* Do not reset port0 if card is in Managed mode since resetting will - * generate new IEEE 802.11 authentication which may end up in looping - * with IEEE 802.1X. Prism2 documentation seem to require port reset - * after WEP configuration. However, keys are apparently changed at - * least in Managed mode. */ - if (local->iw_mode != IW_MODE_INFRA && local->func->reset_port(dev)) { - printk(KERN_DEBUG "%s: reset_port failed\n", dev->name); - return -EINVAL; - } - - return 0; -} - - -static int prism2_ioctl_giwencode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *key) -{ - struct iw_point *erq = &wrqu->encoding; - struct hostap_interface *iface; - local_info_t *local; - int i, len; - u16 val; - struct lib80211_crypt_data *crypt; - - iface = netdev_priv(dev); - local = iface->local; - - i = erq->flags & IW_ENCODE_INDEX; - if (i < 1 || i > 4) - i = local->crypt_info.tx_keyidx; - else - i--; - if (i < 0 || i >= WEP_KEYS) - return -EINVAL; - - crypt = local->crypt_info.crypt[i]; - erq->flags = i + 1; - - if (crypt == NULL || crypt->ops == NULL) { - erq->length = 0; - erq->flags |= IW_ENCODE_DISABLED; - return 0; - } - - if (strcmp(crypt->ops->name, "WEP") != 0) { - /* only WEP is supported with wireless extensions, so just - * report that encryption is used */ - erq->length = 0; - erq->flags |= IW_ENCODE_ENABLED; - return 0; - } - - /* Reads from HFA384X_RID_CNFDEFAULTKEY* return bogus values, so show - * the keys from driver buffer */ - len = crypt->ops->get_key(key, WEP_KEY_LEN, NULL, crypt->priv); - erq->length = (len >= 0 ? len : 0); - - if (local->func->get_rid(dev, HFA384X_RID_CNFWEPFLAGS, &val, 2, 1) < 0) - { - printk("CNFWEPFLAGS reading failed\n"); - return -EOPNOTSUPP; - } - le16_to_cpus(&val); - if (val & HFA384X_WEPFLAGS_PRIVACYINVOKED) - erq->flags |= IW_ENCODE_ENABLED; - else - erq->flags |= IW_ENCODE_DISABLED; - if (val & HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED) - erq->flags |= IW_ENCODE_RESTRICTED; - else - erq->flags |= IW_ENCODE_OPEN; - - return 0; -} - - -static int hostap_set_rate(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - int ret, basic_rates; - - iface = netdev_priv(dev); - local = iface->local; - - basic_rates = local->basic_rates & local->tx_rate_control; - if (!basic_rates || basic_rates != local->basic_rates) { - printk(KERN_INFO "%s: updating basic rate set automatically " - "to match with the new supported rate set\n", - dev->name); - if (!basic_rates) - basic_rates = local->tx_rate_control; - - local->basic_rates = basic_rates; - if (hostap_set_word(dev, HFA384X_RID_CNFBASICRATES, - basic_rates)) - printk(KERN_WARNING "%s: failed to set " - "cnfBasicRates\n", dev->name); - } - - ret = (hostap_set_word(dev, HFA384X_RID_TXRATECONTROL, - local->tx_rate_control) || - hostap_set_word(dev, HFA384X_RID_CNFSUPPORTEDRATES, - local->tx_rate_control) || - local->func->reset_port(dev)); - - if (ret) { - printk(KERN_WARNING "%s: TXRateControl/cnfSupportedRates " - "setting to 0x%x failed\n", - dev->name, local->tx_rate_control); - } - - /* Update TX rate configuration for all STAs based on new operational - * rate set. */ - hostap_update_rates(local); - - return ret; -} - - -static int prism2_ioctl_siwrate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->bitrate; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - if (rrq->fixed) { - switch (rrq->value) { - case 11000000: - local->tx_rate_control = HFA384X_RATES_11MBPS; - break; - case 5500000: - local->tx_rate_control = HFA384X_RATES_5MBPS; - break; - case 2000000: - local->tx_rate_control = HFA384X_RATES_2MBPS; - break; - case 1000000: - local->tx_rate_control = HFA384X_RATES_1MBPS; - break; - default: - local->tx_rate_control = HFA384X_RATES_1MBPS | - HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS | - HFA384X_RATES_11MBPS; - break; - } - } else { - switch (rrq->value) { - case 11000000: - local->tx_rate_control = HFA384X_RATES_1MBPS | - HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS | - HFA384X_RATES_11MBPS; - break; - case 5500000: - local->tx_rate_control = HFA384X_RATES_1MBPS | - HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS; - break; - case 2000000: - local->tx_rate_control = HFA384X_RATES_1MBPS | - HFA384X_RATES_2MBPS; - break; - case 1000000: - local->tx_rate_control = HFA384X_RATES_1MBPS; - break; - default: - local->tx_rate_control = HFA384X_RATES_1MBPS | - HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS | - HFA384X_RATES_11MBPS; - break; - } - } - - return hostap_set_rate(dev); -} - - -static int prism2_ioctl_giwrate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->bitrate; - u16 val; - struct hostap_interface *iface; - local_info_t *local; - int ret = 0; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->func->get_rid(dev, HFA384X_RID_TXRATECONTROL, &val, 2, 1) < - 0) - return -EINVAL; - - if ((val & 0x1) && (val > 1)) - rrq->fixed = 0; - else - rrq->fixed = 1; - - if (local->iw_mode == IW_MODE_MASTER && local->ap != NULL && - !local->fw_tx_rate_control) { - /* HFA384X_RID_CURRENTTXRATE seems to always be 2 Mbps in - * Host AP mode, so use the recorded TX rate of the last sent - * frame */ - rrq->value = local->ap->last_tx_rate > 0 ? - local->ap->last_tx_rate * 100000 : 11000000; - return 0; - } - - if (local->func->get_rid(dev, HFA384X_RID_CURRENTTXRATE, &val, 2, 1) < - 0) - return -EINVAL; - - switch (val) { - case HFA384X_RATES_1MBPS: - rrq->value = 1000000; - break; - case HFA384X_RATES_2MBPS: - rrq->value = 2000000; - break; - case HFA384X_RATES_5MBPS: - rrq->value = 5500000; - break; - case HFA384X_RATES_11MBPS: - rrq->value = 11000000; - break; - default: - /* should not happen */ - rrq->value = 11000000; - ret = -EINVAL; - break; - } - - return ret; -} - - -static int prism2_ioctl_siwsens(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *sens = &wrqu->sens; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - /* Set the desired AP density */ - if (sens->value < 1 || sens->value > 3) - return -EINVAL; - - if (hostap_set_word(dev, HFA384X_RID_CNFSYSTEMSCALE, sens->value) || - local->func->reset_port(dev)) - return -EINVAL; - - return 0; -} - -static int prism2_ioctl_giwsens(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *sens = &wrqu->sens; - struct hostap_interface *iface; - local_info_t *local; - __le16 val; - - iface = netdev_priv(dev); - local = iface->local; - - /* Get the current AP density */ - if (local->func->get_rid(dev, HFA384X_RID_CNFSYSTEMSCALE, &val, 2, 1) < - 0) - return -EINVAL; - - sens->value = le16_to_cpu(val); - sens->fixed = 1; - - return 0; -} - - -/* Deprecated in new wireless extension API */ -static int prism2_ioctl_giwaplist(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_point *data = &wrqu->data; - struct hostap_interface *iface; - local_info_t *local; - struct sockaddr *addr; - struct iw_quality *qual; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->iw_mode != IW_MODE_MASTER) { - printk(KERN_DEBUG "SIOCGIWAPLIST is currently only supported " - "in Host AP mode\n"); - data->length = 0; - return -EOPNOTSUPP; - } - - addr = kmalloc_array(IW_MAX_AP, sizeof(struct sockaddr), GFP_KERNEL); - qual = kmalloc_array(IW_MAX_AP, sizeof(struct iw_quality), GFP_KERNEL); - if (addr == NULL || qual == NULL) { - kfree(addr); - kfree(qual); - data->length = 0; - return -ENOMEM; - } - - data->length = prism2_ap_get_sta_qual(local, addr, qual, IW_MAX_AP, 1); - - memcpy(extra, addr, sizeof(struct sockaddr) * data->length); - data->flags = 1; /* has quality information */ - memcpy(extra + sizeof(struct sockaddr) * data->length, qual, - sizeof(struct iw_quality) * data->length); - - kfree(addr); - kfree(qual); - return 0; -} - - -static int prism2_ioctl_siwrts(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rts = &wrqu->rts; - struct hostap_interface *iface; - local_info_t *local; - __le16 val; - - iface = netdev_priv(dev); - local = iface->local; - - if (rts->disabled) - val = cpu_to_le16(2347); - else if (rts->value < 0 || rts->value > 2347) - return -EINVAL; - else - val = cpu_to_le16(rts->value); - - if (local->func->set_rid(dev, HFA384X_RID_RTSTHRESHOLD, &val, 2) || - local->func->reset_port(dev)) - return -EINVAL; - - local->rts_threshold = rts->value; - - return 0; -} - -static int prism2_ioctl_giwrts(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rts = &wrqu->rts; - struct hostap_interface *iface; - local_info_t *local; - __le16 val; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->func->get_rid(dev, HFA384X_RID_RTSTHRESHOLD, &val, 2, 1) < - 0) - return -EINVAL; - - rts->value = le16_to_cpu(val); - rts->disabled = (rts->value == 2347); - rts->fixed = 1; - - return 0; -} - - -static int prism2_ioctl_siwfrag(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rts = &wrqu->rts; - struct hostap_interface *iface; - local_info_t *local; - __le16 val; - - iface = netdev_priv(dev); - local = iface->local; - - if (rts->disabled) - val = cpu_to_le16(2346); - else if (rts->value < 256 || rts->value > 2346) - return -EINVAL; - else - val = cpu_to_le16(rts->value & ~0x1); /* even numbers only */ - - local->fragm_threshold = rts->value & ~0x1; - if (local->func->set_rid(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, &val, - 2) - || local->func->reset_port(dev)) - return -EINVAL; - - return 0; -} - -static int prism2_ioctl_giwfrag(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rts = &wrqu->rts; - struct hostap_interface *iface; - local_info_t *local; - __le16 val; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->func->get_rid(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, - &val, 2, 1) < 0) - return -EINVAL; - - rts->value = le16_to_cpu(val); - rts->disabled = (rts->value == 2346); - rts->fixed = 1; - - return 0; -} - - -#ifndef PRISM2_NO_STATION_MODES -static int hostap_join_ap(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - struct hfa384x_join_request req; - unsigned long flags; - int i; - struct hfa384x_hostscan_result *entry; - - iface = netdev_priv(dev); - local = iface->local; - - memcpy(req.bssid, local->preferred_ap, ETH_ALEN); - req.channel = 0; - - spin_lock_irqsave(&local->lock, flags); - for (i = 0; i < local->last_scan_results_count; i++) { - if (!local->last_scan_results) - break; - entry = &local->last_scan_results[i]; - if (ether_addr_equal(local->preferred_ap, entry->bssid)) { - req.channel = entry->chid; - break; - } - } - spin_unlock_irqrestore(&local->lock, flags); - - if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req, - sizeof(req))) { - printk(KERN_DEBUG "%s: JoinRequest %pM failed\n", - dev->name, local->preferred_ap); - return -1; - } - - printk(KERN_DEBUG "%s: Trying to join BSSID %pM\n", - dev->name, local->preferred_ap); - - return 0; -} -#endif /* PRISM2_NO_STATION_MODES */ - - -static int prism2_ioctl_siwap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct sockaddr *ap_addr = &wrqu->ap_addr; -#ifdef PRISM2_NO_STATION_MODES - return -EOPNOTSUPP; -#else /* PRISM2_NO_STATION_MODES */ - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - memcpy(local->preferred_ap, &ap_addr->sa_data, ETH_ALEN); - - if (local->host_roaming == 1 && local->iw_mode == IW_MODE_INFRA) { - struct hfa384x_scan_request scan_req; - memset(&scan_req, 0, sizeof(scan_req)); - scan_req.channel_list = cpu_to_le16(0x3fff); - scan_req.txrate = cpu_to_le16(HFA384X_RATES_1MBPS); - if (local->func->set_rid(dev, HFA384X_RID_SCANREQUEST, - &scan_req, sizeof(scan_req))) { - printk(KERN_DEBUG "%s: ScanResults request failed - " - "preferred AP delayed to next unsolicited " - "scan\n", dev->name); - } - } else if (local->host_roaming == 2 && - local->iw_mode == IW_MODE_INFRA) { - if (hostap_join_ap(dev)) - return -EINVAL; - } else { - printk(KERN_DEBUG "%s: Preferred AP (SIOCSIWAP) is used only " - "in Managed mode when host_roaming is enabled\n", - dev->name); - } - - return 0; -#endif /* PRISM2_NO_STATION_MODES */ -} - -static int prism2_ioctl_giwap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct sockaddr *ap_addr = &wrqu->ap_addr; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - ap_addr->sa_family = ARPHRD_ETHER; - switch (iface->type) { - case HOSTAP_INTERFACE_AP: - memcpy(&ap_addr->sa_data, dev->dev_addr, ETH_ALEN); - break; - case HOSTAP_INTERFACE_STA: - memcpy(&ap_addr->sa_data, local->assoc_ap_addr, ETH_ALEN); - break; - case HOSTAP_INTERFACE_WDS: - memcpy(&ap_addr->sa_data, iface->u.wds.remote_addr, ETH_ALEN); - break; - default: - if (local->func->get_rid(dev, HFA384X_RID_CURRENTBSSID, - &ap_addr->sa_data, ETH_ALEN, 1) < 0) - return -EOPNOTSUPP; - - /* local->bssid is also updated in LinkStatus handler when in - * station mode */ - memcpy(local->bssid, &ap_addr->sa_data, ETH_ALEN); - break; - } - - return 0; -} - - -static int prism2_ioctl_siwnickn(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *nickname) -{ - struct iw_point *data = &wrqu->data; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - memset(local->name, 0, sizeof(local->name)); - memcpy(local->name, nickname, data->length); - local->name_set = 1; - - if (hostap_set_string(dev, HFA384X_RID_CNFOWNNAME, local->name) || - local->func->reset_port(dev)) - return -EINVAL; - - return 0; -} - -static int prism2_ioctl_giwnickn(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *nickname) -{ - struct iw_point *data = &wrqu->data; - struct hostap_interface *iface; - local_info_t *local; - int len; - char name[MAX_NAME_LEN + 3]; - u16 val; - - iface = netdev_priv(dev); - local = iface->local; - - len = local->func->get_rid(dev, HFA384X_RID_CNFOWNNAME, - &name, MAX_NAME_LEN + 2, 0); - val = le16_to_cpu(*(__le16 *) name); - if (len > MAX_NAME_LEN + 2 || len < 0 || val > MAX_NAME_LEN) - return -EOPNOTSUPP; - - name[val + 2] = '\0'; - data->length = val + 1; - memcpy(nickname, name + 2, val + 1); - - return 0; -} - - -static int prism2_ioctl_siwfreq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_freq *freq = &wrqu->freq; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - /* freq => chan. */ - if (freq->e == 1 && - freq->m / 100000 >= freq_list[0] && - freq->m / 100000 <= freq_list[FREQ_COUNT - 1]) { - int ch; - int fr = freq->m / 100000; - for (ch = 0; ch < FREQ_COUNT; ch++) { - if (fr == freq_list[ch]) { - freq->e = 0; - freq->m = ch + 1; - break; - } - } - } - - if (freq->e != 0 || freq->m < 1 || freq->m > FREQ_COUNT || - !(local->channel_mask & (1 << (freq->m - 1)))) - return -EINVAL; - - local->channel = freq->m; /* channel is used in prism2_setup_rids() */ - if (hostap_set_word(dev, HFA384X_RID_CNFOWNCHANNEL, local->channel) || - local->func->reset_port(dev)) - return -EINVAL; - - return 0; -} - -static int prism2_ioctl_giwfreq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_freq *freq = &wrqu->freq; - struct hostap_interface *iface; - local_info_t *local; - u16 val; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->func->get_rid(dev, HFA384X_RID_CURRENTCHANNEL, &val, 2, 1) < - 0) - return -EINVAL; - - le16_to_cpus(&val); - if (val < 1 || val > FREQ_COUNT) - return -EINVAL; - - freq->m = freq_list[val - 1] * 100000; - freq->e = 1; - - return 0; -} - - -static void hostap_monitor_set_type(local_info_t *local) -{ - struct net_device *dev = local->ddev; - - if (dev == NULL) - return; - - if (local->monitor_type == PRISM2_MONITOR_PRISM || - local->monitor_type == PRISM2_MONITOR_CAPHDR) { - dev->type = ARPHRD_IEEE80211_PRISM; - } else if (local->monitor_type == PRISM2_MONITOR_RADIOTAP) { - dev->type = ARPHRD_IEEE80211_RADIOTAP; - } else { - dev->type = ARPHRD_IEEE80211; - } -} - - -static int prism2_ioctl_siwessid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *ssid) -{ - struct iw_point *data = &wrqu->data; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - if (iface->type == HOSTAP_INTERFACE_WDS) - return -EOPNOTSUPP; - - if (data->flags == 0) - ssid[0] = '\0'; /* ANY */ - - if (local->iw_mode == IW_MODE_MASTER && ssid[0] == '\0') { - /* Setting SSID to empty string seems to kill the card in - * Host AP mode */ - printk(KERN_DEBUG "%s: Host AP mode does not support " - "'Any' essid\n", dev->name); - return -EINVAL; - } - - memcpy(local->essid, ssid, data->length); - local->essid[data->length] = '\0'; - - if ((!local->fw_ap && - hostap_set_string(dev, HFA384X_RID_CNFDESIREDSSID, local->essid)) - || hostap_set_string(dev, HFA384X_RID_CNFOWNSSID, local->essid) || - local->func->reset_port(dev)) - return -EINVAL; - - return 0; -} - -static int prism2_ioctl_giwessid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *essid) -{ - struct iw_point *data = &wrqu->data; - struct hostap_interface *iface; - local_info_t *local; - u16 val; - - iface = netdev_priv(dev); - local = iface->local; - - if (iface->type == HOSTAP_INTERFACE_WDS) - return -EOPNOTSUPP; - - data->flags = 1; /* active */ - if (local->iw_mode == IW_MODE_MASTER) { - data->length = strlen(local->essid); - memcpy(essid, local->essid, IW_ESSID_MAX_SIZE); - } else { - int len; - char ssid[MAX_SSID_LEN + 2]; - memset(ssid, 0, sizeof(ssid)); - len = local->func->get_rid(dev, HFA384X_RID_CURRENTSSID, - &ssid, MAX_SSID_LEN + 2, 0); - val = le16_to_cpu(*(__le16 *) ssid); - if (len > MAX_SSID_LEN + 2 || len < 0 || val > MAX_SSID_LEN) { - return -EOPNOTSUPP; - } - data->length = val; - memcpy(essid, ssid + 2, IW_ESSID_MAX_SIZE); - } - - return 0; -} - - -static int prism2_ioctl_giwrange(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_point *data = &wrqu->data; - struct hostap_interface *iface; - local_info_t *local; - struct iw_range *range = (struct iw_range *) extra; - u8 rates[10]; - u16 val; - int i, len, over2; - - iface = netdev_priv(dev); - local = iface->local; - - data->length = sizeof(struct iw_range); - memset(range, 0, sizeof(struct iw_range)); - - /* TODO: could fill num_txpower and txpower array with - * something; however, there are 128 different values.. */ - - range->txpower_capa = IW_TXPOW_DBM; - - if (local->iw_mode == IW_MODE_INFRA || local->iw_mode == IW_MODE_ADHOC) - { - range->min_pmp = 1 * 1024; - range->max_pmp = 65535 * 1024; - range->min_pmt = 1 * 1024; - range->max_pmt = 1000 * 1024; - range->pmp_flags = IW_POWER_PERIOD; - range->pmt_flags = IW_POWER_TIMEOUT; - range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | - IW_POWER_UNICAST_R | IW_POWER_ALL_R; - } - - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 18; - - range->retry_capa = IW_RETRY_LIMIT; - range->retry_flags = IW_RETRY_LIMIT; - range->min_retry = 0; - range->max_retry = 255; - - range->num_channels = FREQ_COUNT; - - val = 0; - for (i = 0; i < FREQ_COUNT; i++) { - if (local->channel_mask & (1 << i)) { - range->freq[val].i = i + 1; - range->freq[val].m = freq_list[i] * 100000; - range->freq[val].e = 1; - val++; - } - if (val == IW_MAX_FREQUENCIES) - break; - } - range->num_frequency = val; - - if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1)) { - range->max_qual.qual = 70; /* what is correct max? This was not - * documented exactly. At least - * 69 has been observed. */ - range->max_qual.level = 0; /* dB */ - range->max_qual.noise = 0; /* dB */ - - /* What would be suitable values for "average/typical" qual? */ - range->avg_qual.qual = 20; - range->avg_qual.level = -60; - range->avg_qual.noise = -95; - } else { - range->max_qual.qual = 92; /* 0 .. 92 */ - range->max_qual.level = 154; /* 27 .. 154 */ - range->max_qual.noise = 154; /* 27 .. 154 */ - } - range->sensitivity = 3; - - range->max_encoding_tokens = WEP_KEYS; - range->num_encoding_sizes = 2; - range->encoding_size[0] = 5; - range->encoding_size[1] = 13; - - over2 = 0; - len = prism2_get_datarates(dev, rates); - range->num_bitrates = 0; - for (i = 0; i < len; i++) { - if (range->num_bitrates < IW_MAX_BITRATES) { - range->bitrate[range->num_bitrates] = - rates[i] * 500000; - range->num_bitrates++; - } - if (rates[i] == 0x0b || rates[i] == 0x16) - over2 = 1; - } - /* estimated maximum TCP throughput values (bps) */ - range->throughput = over2 ? 5500000 : 1500000; - - range->min_rts = 0; - range->max_rts = 2347; - range->min_frag = 256; - range->max_frag = 2346; - - /* Event capability (kernel + driver) */ - range->event_capa[0] = (IW_EVENT_CAPA_K_0 | - IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) | - IW_EVENT_CAPA_MASK(SIOCGIWAP) | - IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); - range->event_capa[1] = IW_EVENT_CAPA_K_1; - range->event_capa[4] = (IW_EVENT_CAPA_MASK(IWEVTXDROP) | - IW_EVENT_CAPA_MASK(IWEVCUSTOM) | - IW_EVENT_CAPA_MASK(IWEVREGISTERED) | - IW_EVENT_CAPA_MASK(IWEVEXPIRED)); - - range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | - IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; - - if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1)) - range->scan_capa = IW_SCAN_CAPA_ESSID; - - return 0; -} - - -static int hostap_monitor_mode_enable(local_info_t *local) -{ - struct net_device *dev = local->dev; - - printk(KERN_DEBUG "Enabling monitor mode\n"); - hostap_monitor_set_type(local); - - if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, - HFA384X_PORTTYPE_PSEUDO_IBSS)) { - printk(KERN_DEBUG "Port type setting for monitor mode " - "failed\n"); - return -EOPNOTSUPP; - } - - /* Host decrypt is needed to get the IV and ICV fields; - * however, monitor mode seems to remove WEP flag from frame - * control field */ - if (hostap_set_word(dev, HFA384X_RID_CNFWEPFLAGS, - HFA384X_WEPFLAGS_HOSTENCRYPT | - HFA384X_WEPFLAGS_HOSTDECRYPT)) { - printk(KERN_DEBUG "WEP flags setting failed\n"); - return -EOPNOTSUPP; - } - - if (local->func->reset_port(dev) || - local->func->cmd(dev, HFA384X_CMDCODE_TEST | - (HFA384X_TEST_MONITOR << 8), - 0, NULL, NULL)) { - printk(KERN_DEBUG "Setting monitor mode failed\n"); - return -EOPNOTSUPP; - } - - return 0; -} - - -static int hostap_monitor_mode_disable(local_info_t *local) -{ - struct net_device *dev = local->ddev; - - if (dev == NULL) - return -1; - - printk(KERN_DEBUG "%s: Disabling monitor mode\n", dev->name); - dev->type = ARPHRD_ETHER; - - if (local->func->cmd(dev, HFA384X_CMDCODE_TEST | - (HFA384X_TEST_STOP << 8), - 0, NULL, NULL)) - return -1; - return hostap_set_encryption(local); -} - - -static int prism2_ioctl_siwmode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - __u32 *mode = &wrqu->mode; - struct hostap_interface *iface; - local_info_t *local; - int double_reset = 0; - - iface = netdev_priv(dev); - local = iface->local; - - if (*mode != IW_MODE_ADHOC && *mode != IW_MODE_INFRA && - *mode != IW_MODE_MASTER && *mode != IW_MODE_REPEAT && - *mode != IW_MODE_MONITOR) - return -EOPNOTSUPP; - -#ifdef PRISM2_NO_STATION_MODES - if (*mode == IW_MODE_ADHOC || *mode == IW_MODE_INFRA) - return -EOPNOTSUPP; -#endif /* PRISM2_NO_STATION_MODES */ - - if (*mode == local->iw_mode) - return 0; - - if (*mode == IW_MODE_MASTER && local->essid[0] == '\0') { - printk(KERN_WARNING "%s: empty SSID not allowed in Master " - "mode\n", dev->name); - return -EINVAL; - } - - if (local->iw_mode == IW_MODE_MONITOR) - hostap_monitor_mode_disable(local); - - if ((local->iw_mode == IW_MODE_ADHOC || - local->iw_mode == IW_MODE_MONITOR) && *mode == IW_MODE_MASTER) { - /* There seems to be a firmware bug in at least STA f/w v1.5.6 - * that leaves beacon frames to use IBSS type when moving from - * IBSS to Host AP mode. Doing double Port0 reset seems to be - * enough to workaround this. */ - double_reset = 1; - } - - printk(KERN_DEBUG "prism2: %s: operating mode changed " - "%d -> %d\n", dev->name, local->iw_mode, *mode); - local->iw_mode = *mode; - - if (local->iw_mode == IW_MODE_MONITOR) - hostap_monitor_mode_enable(local); - else if (local->iw_mode == IW_MODE_MASTER && !local->host_encrypt && - !local->fw_encrypt_ok) { - printk(KERN_DEBUG "%s: defaulting to host-based encryption as " - "a workaround for firmware bug in Host AP mode WEP\n", - dev->name); - local->host_encrypt = 1; - } - - if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, - hostap_get_porttype(local))) - return -EOPNOTSUPP; - - if (local->func->reset_port(dev)) - return -EINVAL; - if (double_reset && local->func->reset_port(dev)) - return -EINVAL; - - if (local->iw_mode != IW_MODE_INFRA && local->iw_mode != IW_MODE_ADHOC) - { - /* netif_carrier is used only in client modes for now, so make - * sure carrier is on when moving to non-client modes. */ - netif_carrier_on(local->dev); - netif_carrier_on(local->ddev); - } - return 0; -} - - -static int prism2_ioctl_giwmode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - __u32 *mode = &wrqu->mode; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - switch (iface->type) { - case HOSTAP_INTERFACE_STA: - *mode = IW_MODE_INFRA; - break; - case HOSTAP_INTERFACE_WDS: - *mode = IW_MODE_REPEAT; - break; - default: - *mode = local->iw_mode; - break; - } - return 0; -} - - -static int prism2_ioctl_siwpower(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *wrq = &wrqu->power; -#ifdef PRISM2_NO_STATION_MODES - return -EOPNOTSUPP; -#else /* PRISM2_NO_STATION_MODES */ - int ret = 0; - - if (wrq->disabled) - return hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 0); - - switch (wrq->flags & IW_POWER_MODE) { - case IW_POWER_UNICAST_R: - ret = hostap_set_word(dev, HFA384X_RID_CNFMULTICASTRECEIVE, 0); - if (ret) - return ret; - ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1); - if (ret) - return ret; - break; - case IW_POWER_ALL_R: - ret = hostap_set_word(dev, HFA384X_RID_CNFMULTICASTRECEIVE, 1); - if (ret) - return ret; - ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1); - if (ret) - return ret; - break; - case IW_POWER_ON: - break; - default: - return -EINVAL; - } - - if (wrq->flags & IW_POWER_TIMEOUT) { - ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1); - if (ret) - return ret; - ret = hostap_set_word(dev, HFA384X_RID_CNFPMHOLDOVERDURATION, - wrq->value / 1024); - if (ret) - return ret; - } - if (wrq->flags & IW_POWER_PERIOD) { - ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1); - if (ret) - return ret; - ret = hostap_set_word(dev, HFA384X_RID_CNFMAXSLEEPDURATION, - wrq->value / 1024); - if (ret) - return ret; - } - - return ret; -#endif /* PRISM2_NO_STATION_MODES */ -} - - -static int prism2_ioctl_giwpower(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->power; -#ifdef PRISM2_NO_STATION_MODES - return -EOPNOTSUPP; -#else /* PRISM2_NO_STATION_MODES */ - struct hostap_interface *iface; - local_info_t *local; - __le16 enable, mcast; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->func->get_rid(dev, HFA384X_RID_CNFPMENABLED, &enable, 2, 1) - < 0) - return -EINVAL; - - if (!le16_to_cpu(enable)) { - rrq->disabled = 1; - return 0; - } - - rrq->disabled = 0; - - if ((rrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { - __le16 timeout; - if (local->func->get_rid(dev, - HFA384X_RID_CNFPMHOLDOVERDURATION, - &timeout, 2, 1) < 0) - return -EINVAL; - - rrq->flags = IW_POWER_TIMEOUT; - rrq->value = le16_to_cpu(timeout) * 1024; - } else { - __le16 period; - if (local->func->get_rid(dev, HFA384X_RID_CNFMAXSLEEPDURATION, - &period, 2, 1) < 0) - return -EINVAL; - - rrq->flags = IW_POWER_PERIOD; - rrq->value = le16_to_cpu(period) * 1024; - } - - if (local->func->get_rid(dev, HFA384X_RID_CNFMULTICASTRECEIVE, &mcast, - 2, 1) < 0) - return -EINVAL; - - if (le16_to_cpu(mcast)) - rrq->flags |= IW_POWER_ALL_R; - else - rrq->flags |= IW_POWER_UNICAST_R; - - return 0; -#endif /* PRISM2_NO_STATION_MODES */ -} - - -static int prism2_ioctl_siwretry(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->retry; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - if (rrq->disabled) - return -EINVAL; - - /* setting retry limits is not supported with the current station - * firmware code; simulate this with alternative retry count for now */ - if (rrq->flags == IW_RETRY_LIMIT) { - if (rrq->value < 0) { - /* disable manual retry count setting and use firmware - * defaults */ - local->manual_retry_count = -1; - local->tx_control &= ~HFA384X_TX_CTRL_ALT_RTRY; - } else { - if (hostap_set_word(dev, HFA384X_RID_CNFALTRETRYCOUNT, - rrq->value)) { - printk(KERN_DEBUG "%s: Alternate retry count " - "setting to %d failed\n", - dev->name, rrq->value); - return -EOPNOTSUPP; - } - - local->manual_retry_count = rrq->value; - local->tx_control |= HFA384X_TX_CTRL_ALT_RTRY; - } - return 0; - } - - return -EOPNOTSUPP; - -#if 0 - /* what could be done, if firmware would support this.. */ - - if (rrq->flags & IW_RETRY_LIMIT) { - if (rrq->flags & IW_RETRY_LONG) - HFA384X_RID_LONGRETRYLIMIT = rrq->value; - else if (rrq->flags & IW_RETRY_SHORT) - HFA384X_RID_SHORTRETRYLIMIT = rrq->value; - else { - HFA384X_RID_LONGRETRYLIMIT = rrq->value; - HFA384X_RID_SHORTRETRYLIMIT = rrq->value; - } - - } - - if (rrq->flags & IW_RETRY_LIFETIME) { - HFA384X_RID_MAXTRANSMITLIFETIME = rrq->value / 1024; - } - - return 0; -#endif /* 0 */ -} - -static int prism2_ioctl_giwretry(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->retry; - struct hostap_interface *iface; - local_info_t *local; - __le16 shortretry, longretry, lifetime, altretry; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->func->get_rid(dev, HFA384X_RID_SHORTRETRYLIMIT, &shortretry, - 2, 1) < 0 || - local->func->get_rid(dev, HFA384X_RID_LONGRETRYLIMIT, &longretry, - 2, 1) < 0 || - local->func->get_rid(dev, HFA384X_RID_MAXTRANSMITLIFETIME, - &lifetime, 2, 1) < 0) - return -EINVAL; - - rrq->disabled = 0; - - if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { - rrq->flags = IW_RETRY_LIFETIME; - rrq->value = le16_to_cpu(lifetime) * 1024; - } else { - if (local->manual_retry_count >= 0) { - rrq->flags = IW_RETRY_LIMIT; - if (local->func->get_rid(dev, - HFA384X_RID_CNFALTRETRYCOUNT, - &altretry, 2, 1) >= 0) - rrq->value = le16_to_cpu(altretry); - else - rrq->value = local->manual_retry_count; - } else if ((rrq->flags & IW_RETRY_LONG)) { - rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; - rrq->value = le16_to_cpu(longretry); - } else { - rrq->flags = IW_RETRY_LIMIT; - rrq->value = le16_to_cpu(shortretry); - if (shortretry != longretry) - rrq->flags |= IW_RETRY_SHORT; - } - } - return 0; -} - - -/* Note! This TX power controlling is experimental and should not be used in - * production use. It just sets raw power register and does not use any kind of - * feedback information from the measured TX power (CR58). This is now - * commented out to make sure that it is not used by accident. TX power - * configuration will be enabled again after proper algorithm using feedback - * has been implemented. */ - -#ifdef RAW_TXPOWER_SETTING -/* Map HFA386x's CR31 to and from dBm with some sort of ad hoc mapping.. - * This version assumes following mapping: - * CR31 is 7-bit value with -64 to +63 range. - * -64 is mapped into +20dBm and +63 into -43dBm. - * This is certainly not an exact mapping for every card, but at least - * increasing dBm value should correspond to increasing TX power. - */ - -static int prism2_txpower_hfa386x_to_dBm(u16 val) -{ - signed char tmp; - - if (val > 255) - val = 255; - - tmp = val; - tmp >>= 2; - - return -12 - tmp; -} - -static u16 prism2_txpower_dBm_to_hfa386x(int val) -{ - signed char tmp; - - if (val > 20) - return 128; - else if (val < -43) - return 127; - - tmp = val; - tmp = -12 - tmp; - tmp <<= 2; - - return (unsigned char) tmp; -} -#endif /* RAW_TXPOWER_SETTING */ - - -static int prism2_ioctl_siwtxpow(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->txpower; - struct hostap_interface *iface; - local_info_t *local; -#ifdef RAW_TXPOWER_SETTING - char *tmp; -#endif - u16 val; - int ret = 0; - - iface = netdev_priv(dev); - local = iface->local; - - if (rrq->disabled) { - if (local->txpower_type != PRISM2_TXPOWER_OFF) { - val = 0xff; /* use all standby and sleep modes */ - ret = local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, - HFA386X_CR_A_D_TEST_MODES2, - &val, NULL); - printk(KERN_DEBUG "%s: Turning radio off: %s\n", - dev->name, ret ? "failed" : "OK"); - local->txpower_type = PRISM2_TXPOWER_OFF; - } - return (ret ? -EOPNOTSUPP : 0); - } - - if (local->txpower_type == PRISM2_TXPOWER_OFF) { - val = 0; /* disable all standby and sleep modes */ - ret = local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, - HFA386X_CR_A_D_TEST_MODES2, &val, NULL); - printk(KERN_DEBUG "%s: Turning radio on: %s\n", - dev->name, ret ? "failed" : "OK"); - local->txpower_type = PRISM2_TXPOWER_UNKNOWN; - } - -#ifdef RAW_TXPOWER_SETTING - if (!rrq->fixed && local->txpower_type != PRISM2_TXPOWER_AUTO) { - printk(KERN_DEBUG "Setting ALC on\n"); - val = HFA384X_TEST_CFG_BIT_ALC; - local->func->cmd(dev, HFA384X_CMDCODE_TEST | - (HFA384X_TEST_CFG_BITS << 8), 1, &val, NULL); - local->txpower_type = PRISM2_TXPOWER_AUTO; - return 0; - } - - if (local->txpower_type != PRISM2_TXPOWER_FIXED) { - printk(KERN_DEBUG "Setting ALC off\n"); - val = HFA384X_TEST_CFG_BIT_ALC; - local->func->cmd(dev, HFA384X_CMDCODE_TEST | - (HFA384X_TEST_CFG_BITS << 8), 0, &val, NULL); - local->txpower_type = PRISM2_TXPOWER_FIXED; - } - - if (rrq->flags == IW_TXPOW_DBM) - tmp = "dBm"; - else if (rrq->flags == IW_TXPOW_MWATT) - tmp = "mW"; - else - tmp = "UNKNOWN"; - printk(KERN_DEBUG "Setting TX power to %d %s\n", rrq->value, tmp); - - if (rrq->flags != IW_TXPOW_DBM) { - printk("SIOCSIWTXPOW with mW is not supported; use dBm\n"); - return -EOPNOTSUPP; - } - - local->txpower = rrq->value; - val = prism2_txpower_dBm_to_hfa386x(local->txpower); - if (local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, - HFA386X_CR_MANUAL_TX_POWER, &val, NULL)) - ret = -EOPNOTSUPP; -#else /* RAW_TXPOWER_SETTING */ - if (rrq->fixed) - ret = -EOPNOTSUPP; -#endif /* RAW_TXPOWER_SETTING */ - - return ret; -} - -static int prism2_ioctl_giwtxpow(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ -#ifdef RAW_TXPOWER_SETTING - struct iw_param *rrq = &wrqu->txpower; - struct hostap_interface *iface; - local_info_t *local; - u16 resp0; - - iface = netdev_priv(dev); - local = iface->local; - - rrq->flags = IW_TXPOW_DBM; - rrq->disabled = 0; - rrq->fixed = 0; - - if (local->txpower_type == PRISM2_TXPOWER_AUTO) { - if (local->func->cmd(dev, HFA384X_CMDCODE_READMIF, - HFA386X_CR_MANUAL_TX_POWER, - NULL, &resp0) == 0) { - rrq->value = prism2_txpower_hfa386x_to_dBm(resp0); - } else { - /* Could not get real txpower; guess 15 dBm */ - rrq->value = 15; - } - } else if (local->txpower_type == PRISM2_TXPOWER_OFF) { - rrq->value = 0; - rrq->disabled = 1; - } else if (local->txpower_type == PRISM2_TXPOWER_FIXED) { - rrq->value = local->txpower; - rrq->fixed = 1; - } else { - printk("SIOCGIWTXPOW - unknown txpower_type=%d\n", - local->txpower_type); - } - return 0; -#else /* RAW_TXPOWER_SETTING */ - return -EOPNOTSUPP; -#endif /* RAW_TXPOWER_SETTING */ -} - - -#ifndef PRISM2_NO_STATION_MODES - -/* HostScan request works with and without host_roaming mode. In addition, it - * does not break current association. However, it requires newer station - * firmware version (>= 1.3.1) than scan request. */ -static int prism2_request_hostscan(struct net_device *dev, - u8 *ssid, u8 ssid_len) -{ - struct hostap_interface *iface; - local_info_t *local; - struct hfa384x_hostscan_request scan_req; - - iface = netdev_priv(dev); - local = iface->local; - - memset(&scan_req, 0, sizeof(scan_req)); - scan_req.channel_list = cpu_to_le16(local->channel_mask & - local->scan_channel_mask); - scan_req.txrate = cpu_to_le16(HFA384X_RATES_1MBPS); - if (ssid) { - if (ssid_len > 32) - return -EINVAL; - scan_req.target_ssid_len = cpu_to_le16(ssid_len); - memcpy(scan_req.target_ssid, ssid, ssid_len); - } - - if (local->func->set_rid(dev, HFA384X_RID_HOSTSCAN, &scan_req, - sizeof(scan_req))) { - printk(KERN_DEBUG "%s: HOSTSCAN failed\n", dev->name); - return -EINVAL; - } - return 0; -} - - -static int prism2_request_scan(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - struct hfa384x_scan_request scan_req; - int ret = 0; - - iface = netdev_priv(dev); - local = iface->local; - - memset(&scan_req, 0, sizeof(scan_req)); - scan_req.channel_list = cpu_to_le16(local->channel_mask & - local->scan_channel_mask); - scan_req.txrate = cpu_to_le16(HFA384X_RATES_1MBPS); - - /* FIX: - * It seems to be enough to set roaming mode for a short moment to - * host-based and then setup scanrequest data and return the mode to - * firmware-based. - * - * Master mode would need to drop to Managed mode for a short while - * to make scanning work.. Or sweep through the different channels and - * use passive scan based on beacons. */ - - if (!local->host_roaming) - hostap_set_word(dev, HFA384X_RID_CNFROAMINGMODE, - HFA384X_ROAMING_HOST); - - if (local->func->set_rid(dev, HFA384X_RID_SCANREQUEST, &scan_req, - sizeof(scan_req))) { - printk(KERN_DEBUG "SCANREQUEST failed\n"); - ret = -EINVAL; - } - - if (!local->host_roaming) - hostap_set_word(dev, HFA384X_RID_CNFROAMINGMODE, - HFA384X_ROAMING_FIRMWARE); - - return ret; -} - -#else /* !PRISM2_NO_STATION_MODES */ - -static inline int prism2_request_hostscan(struct net_device *dev, - u8 *ssid, u8 ssid_len) -{ - return -EOPNOTSUPP; -} - - -static inline int prism2_request_scan(struct net_device *dev) -{ - return -EOPNOTSUPP; -} - -#endif /* !PRISM2_NO_STATION_MODES */ - - -static int prism2_ioctl_siwscan(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_point *data = &wrqu->data; - struct hostap_interface *iface; - local_info_t *local; - int ret; - u8 *ssid = NULL, ssid_len = 0; - struct iw_scan_req *req = (struct iw_scan_req *) extra; - - iface = netdev_priv(dev); - local = iface->local; - - if (data->length < sizeof(struct iw_scan_req)) - req = NULL; - - if (local->iw_mode == IW_MODE_MASTER) { - /* In master mode, we just return the results of our local - * tables, so we don't need to start anything... - * Jean II */ - data->length = 0; - return 0; - } - - if (!local->dev_enabled) - return -ENETDOWN; - - if (req && data->flags & IW_SCAN_THIS_ESSID) { - ssid = req->essid; - ssid_len = req->essid_len; - - if (ssid_len && - ((local->iw_mode != IW_MODE_INFRA && - local->iw_mode != IW_MODE_ADHOC) || - (local->sta_fw_ver < PRISM2_FW_VER(1,3,1)))) - return -EOPNOTSUPP; - } - - if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1)) - ret = prism2_request_hostscan(dev, ssid, ssid_len); - else - ret = prism2_request_scan(dev); - - if (ret == 0) - local->scan_timestamp = jiffies; - - /* Could inquire F101, F103 or wait for SIOCGIWSCAN and read RID */ - - return ret; -} - - -#ifndef PRISM2_NO_STATION_MODES -static char * __prism2_translate_scan(local_info_t *local, - struct iw_request_info *info, - struct hfa384x_hostscan_result *scan, - struct hostap_bss_info *bss, - char *current_ev, char *end_buf) -{ - int i, chan; - struct iw_event iwe; - char *current_val; - u16 capabilities; - u8 *pos; - u8 *ssid, *bssid; - size_t ssid_len; - char *buf; - - if (bss) { - ssid = bss->ssid; - ssid_len = bss->ssid_len; - bssid = bss->bssid; - } else { - ssid = scan->ssid; - ssid_len = le16_to_cpu(scan->ssid_len); - bssid = scan->bssid; - } - if (ssid_len > 32) - ssid_len = 32; - - /* First entry *MUST* be the AP MAC address */ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, bssid, ETH_ALEN); - current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, - IW_EV_ADDR_LEN); - - /* Other entries will be displayed in the order we give them */ - - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWESSID; - iwe.u.data.length = ssid_len; - iwe.u.data.flags = 1; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, ssid); - - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWMODE; - if (bss) { - capabilities = bss->capab_info; - } else { - capabilities = le16_to_cpu(scan->capability); - } - if (capabilities & (WLAN_CAPABILITY_ESS | - WLAN_CAPABILITY_IBSS)) { - if (capabilities & WLAN_CAPABILITY_ESS) - iwe.u.mode = IW_MODE_MASTER; - else - iwe.u.mode = IW_MODE_ADHOC; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_UINT_LEN); - } - - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWFREQ; - if (scan) { - chan = le16_to_cpu(scan->chid); - } else if (bss) { - chan = bss->chan; - } else { - chan = 0; - } - - if (chan > 0) { - iwe.u.freq.m = freq_list[chan - 1] * 100000; - iwe.u.freq.e = 1; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_FREQ_LEN); - } - - if (scan) { - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVQUAL; - if (local->last_scan_type == PRISM2_HOSTSCAN) { - iwe.u.qual.level = le16_to_cpu(scan->sl); - iwe.u.qual.noise = le16_to_cpu(scan->anl); - } else { - iwe.u.qual.level = - HFA384X_LEVEL_TO_dBm(le16_to_cpu(scan->sl)); - iwe.u.qual.noise = - HFA384X_LEVEL_TO_dBm(le16_to_cpu(scan->anl)); - } - iwe.u.qual.updated = IW_QUAL_LEVEL_UPDATED - | IW_QUAL_NOISE_UPDATED - | IW_QUAL_QUAL_INVALID - | IW_QUAL_DBM; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_QUAL_LEN); - } - - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWENCODE; - if (capabilities & WLAN_CAPABILITY_PRIVACY) - iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - iwe.u.data.length = 0; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, ""); - - /* TODO: add SuppRates into BSS table */ - if (scan) { - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWRATE; - current_val = current_ev + iwe_stream_lcp_len(info); - pos = scan->sup_rates; - for (i = 0; i < sizeof(scan->sup_rates); i++) { - if (pos[i] == 0) - break; - /* Bit rate given in 500 kb/s units (+ 0x80) */ - iwe.u.bitrate.value = ((pos[i] & 0x7f) * 500000); - current_val = iwe_stream_add_value( - info, current_ev, current_val, end_buf, &iwe, - IW_EV_PARAM_LEN); - } - /* Check if we added any event */ - if ((current_val - current_ev) > iwe_stream_lcp_len(info)) - current_ev = current_val; - } - - /* TODO: add BeaconInt,resp_rate,atim into BSS table */ - buf = kmalloc(MAX_WPA_IE_LEN * 2 + 30, GFP_ATOMIC); - if (buf && scan) { - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVCUSTOM; - sprintf(buf, "bcn_int=%d", le16_to_cpu(scan->beacon_interval)); - iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, buf); - - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVCUSTOM; - sprintf(buf, "resp_rate=%d", le16_to_cpu(scan->rate)); - iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, buf); - - if (local->last_scan_type == PRISM2_HOSTSCAN && - (capabilities & WLAN_CAPABILITY_IBSS)) { - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVCUSTOM; - sprintf(buf, "atim=%d", le16_to_cpu(scan->atim)); - iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(info, current_ev, - end_buf, &iwe, buf); - } - } - kfree(buf); - - if (bss && bss->wpa_ie_len > 0 && bss->wpa_ie_len <= MAX_WPA_IE_LEN) { - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVGENIE; - iwe.u.data.length = bss->wpa_ie_len; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, bss->wpa_ie); - } - - if (bss && bss->rsn_ie_len > 0 && bss->rsn_ie_len <= MAX_WPA_IE_LEN) { - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVGENIE; - iwe.u.data.length = bss->rsn_ie_len; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, bss->rsn_ie); - } - - return current_ev; -} - - -/* Translate scan data returned from the card to a card independent - * format that the Wireless Tools will understand - Jean II */ -static inline int prism2_translate_scan(local_info_t *local, - struct iw_request_info *info, - char *buffer, int buflen) -{ - struct hfa384x_hostscan_result *scan; - int entry; - char *current_ev = buffer; - char *end_buf = buffer + buflen; - struct list_head *ptr; - - spin_lock_bh(&local->lock); - - list_for_each(ptr, &local->bss_list) { - struct hostap_bss_info *bss; - bss = list_entry(ptr, struct hostap_bss_info, list); - bss->included = 0; - } - - for (entry = 0; entry < local->last_scan_results_count; entry++) { - int found = 0; - scan = &local->last_scan_results[entry]; - - /* Report every SSID if the AP is using multiple SSIDs. If no - * BSS record is found (e.g., when WPA mode is disabled), - * report the AP once. */ - list_for_each(ptr, &local->bss_list) { - struct hostap_bss_info *bss; - bss = list_entry(ptr, struct hostap_bss_info, list); - if (ether_addr_equal(bss->bssid, scan->bssid)) { - bss->included = 1; - current_ev = __prism2_translate_scan( - local, info, scan, bss, current_ev, - end_buf); - found++; - } - } - if (!found) { - current_ev = __prism2_translate_scan( - local, info, scan, NULL, current_ev, end_buf); - } - /* Check if there is space for one more entry */ - if ((end_buf - current_ev) <= IW_EV_ADDR_LEN) { - /* Ask user space to try again with a bigger buffer */ - spin_unlock_bh(&local->lock); - return -E2BIG; - } - } - - /* Prism2 firmware has limits (32 at least in some versions) for number - * of BSSes in scan results. Extend this limit by using local BSS list. - */ - list_for_each(ptr, &local->bss_list) { - struct hostap_bss_info *bss; - bss = list_entry(ptr, struct hostap_bss_info, list); - if (bss->included) - continue; - current_ev = __prism2_translate_scan(local, info, NULL, bss, - current_ev, end_buf); - /* Check if there is space for one more entry */ - if ((end_buf - current_ev) <= IW_EV_ADDR_LEN) { - /* Ask user space to try again with a bigger buffer */ - spin_unlock_bh(&local->lock); - return -E2BIG; - } - } - - spin_unlock_bh(&local->lock); - - return current_ev - buffer; -} -#endif /* PRISM2_NO_STATION_MODES */ - - -static inline int prism2_ioctl_giwscan_sta(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *extra) -{ -#ifdef PRISM2_NO_STATION_MODES - return -EOPNOTSUPP; -#else /* PRISM2_NO_STATION_MODES */ - struct hostap_interface *iface; - local_info_t *local; - int res; - - iface = netdev_priv(dev); - local = iface->local; - - /* Wait until the scan is finished. We can probably do better - * than that - Jean II */ - if (local->scan_timestamp && - time_before(jiffies, local->scan_timestamp + 3 * HZ)) { - /* Important note : we don't want to block the caller - * until results are ready for various reasons. - * First, managing wait queues is complex and racy - * (there may be multiple simultaneous callers). - * Second, we grab some rtnetlink lock before coming - * here (in dev_ioctl()). - * Third, the caller can wait on the Wireless Event - * - Jean II */ - return -EAGAIN; - } - local->scan_timestamp = 0; - - res = prism2_translate_scan(local, info, extra, data->length); - - if (res >= 0) { - data->length = res; - return 0; - } else { - data->length = 0; - return res; - } -#endif /* PRISM2_NO_STATION_MODES */ -} - - -static int prism2_ioctl_giwscan(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_point *data = &wrqu->data; - struct hostap_interface *iface; - local_info_t *local; - int res; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->iw_mode == IW_MODE_MASTER) { - /* In MASTER mode, it doesn't make sense to go around - * scanning the frequencies and make the stations we serve - * wait when what the user is really interested about is the - * list of stations and access points we are talking to. - * So, just extract results from our cache... - * Jean II */ - - /* Translate to WE format */ - res = prism2_ap_translate_scan(dev, info, extra); - if (res >= 0) { - printk(KERN_DEBUG "Scan result translation succeeded " - "(length=%d)\n", res); - data->length = res; - return 0; - } else { - printk(KERN_DEBUG - "Scan result translation failed (res=%d)\n", - res); - data->length = 0; - return res; - } - } else { - /* Station mode */ - return prism2_ioctl_giwscan_sta(dev, info, data, extra); - } -} - - -static const struct iw_priv_args prism2_priv[] = { - { PRISM2_IOCTL_MONITOR, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "monitor" }, - { PRISM2_IOCTL_READMIF, - IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "readmif" }, - { PRISM2_IOCTL_WRITEMIF, - IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 2, 0, "writemif" }, - { PRISM2_IOCTL_RESET, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "reset" }, - { PRISM2_IOCTL_INQUIRE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "inquire" }, - { PRISM2_IOCTL_SET_RID_WORD, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_rid_word" }, - { PRISM2_IOCTL_MACCMD, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "maccmd" }, - { PRISM2_IOCTL_WDS_ADD, - IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "wds_add" }, - { PRISM2_IOCTL_WDS_DEL, - IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "wds_del" }, - { PRISM2_IOCTL_ADDMAC, - IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "addmac" }, - { PRISM2_IOCTL_DELMAC, - IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "delmac" }, - { PRISM2_IOCTL_KICKMAC, - IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "kickmac" }, - /* --- raw access to sub-ioctls --- */ - { PRISM2_IOCTL_PRISM2_PARAM, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "prism2_param" }, - { PRISM2_IOCTL_GET_PRISM2_PARAM, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getprism2_param" }, - /* --- sub-ioctls handlers --- */ - { PRISM2_IOCTL_PRISM2_PARAM, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "" }, - { PRISM2_IOCTL_GET_PRISM2_PARAM, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "" }, - /* --- sub-ioctls definitions --- */ - { PRISM2_PARAM_TXRATECTRL, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "txratectrl" }, - { PRISM2_PARAM_TXRATECTRL, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gettxratectrl" }, - { PRISM2_PARAM_BEACON_INT, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "beacon_int" }, - { PRISM2_PARAM_BEACON_INT, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbeacon_int" }, -#ifndef PRISM2_NO_STATION_MODES - { PRISM2_PARAM_PSEUDO_IBSS, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "pseudo_ibss" }, - { PRISM2_PARAM_PSEUDO_IBSS, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getpseudo_ibss" }, -#endif /* PRISM2_NO_STATION_MODES */ - { PRISM2_PARAM_ALC, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "alc" }, - { PRISM2_PARAM_ALC, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getalc" }, - { PRISM2_PARAM_DUMP, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dump" }, - { PRISM2_PARAM_DUMP, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdump" }, - { PRISM2_PARAM_OTHER_AP_POLICY, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "other_ap_policy" }, - { PRISM2_PARAM_OTHER_AP_POLICY, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getother_ap_pol" }, - { PRISM2_PARAM_AP_MAX_INACTIVITY, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "max_inactivity" }, - { PRISM2_PARAM_AP_MAX_INACTIVITY, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmax_inactivi" }, - { PRISM2_PARAM_AP_BRIDGE_PACKETS, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "bridge_packets" }, - { PRISM2_PARAM_AP_BRIDGE_PACKETS, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbridge_packe" }, - { PRISM2_PARAM_DTIM_PERIOD, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dtim_period" }, - { PRISM2_PARAM_DTIM_PERIOD, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdtim_period" }, - { PRISM2_PARAM_AP_NULLFUNC_ACK, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "nullfunc_ack" }, - { PRISM2_PARAM_AP_NULLFUNC_ACK, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getnullfunc_ack" }, - { PRISM2_PARAM_MAX_WDS, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "max_wds" }, - { PRISM2_PARAM_MAX_WDS, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmax_wds" }, - { PRISM2_PARAM_AP_AUTOM_AP_WDS, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "autom_ap_wds" }, - { PRISM2_PARAM_AP_AUTOM_AP_WDS, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getautom_ap_wds" }, - { PRISM2_PARAM_AP_AUTH_ALGS, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ap_auth_algs" }, - { PRISM2_PARAM_AP_AUTH_ALGS, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getap_auth_algs" }, - { PRISM2_PARAM_MONITOR_ALLOW_FCSERR, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "allow_fcserr" }, - { PRISM2_PARAM_MONITOR_ALLOW_FCSERR, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getallow_fcserr" }, - { PRISM2_PARAM_HOST_ENCRYPT, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_encrypt" }, - { PRISM2_PARAM_HOST_ENCRYPT, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_encrypt" }, - { PRISM2_PARAM_HOST_DECRYPT, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_decrypt" }, - { PRISM2_PARAM_HOST_DECRYPT, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_decrypt" }, -#ifndef PRISM2_NO_STATION_MODES - { PRISM2_PARAM_HOST_ROAMING, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_roaming" }, - { PRISM2_PARAM_HOST_ROAMING, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_roaming" }, -#endif /* PRISM2_NO_STATION_MODES */ - { PRISM2_PARAM_BCRX_STA_KEY, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "bcrx_sta_key" }, - { PRISM2_PARAM_BCRX_STA_KEY, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbcrx_sta_key" }, - { PRISM2_PARAM_IEEE_802_1X, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ieee_802_1x" }, - { PRISM2_PARAM_IEEE_802_1X, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getieee_802_1x" }, - { PRISM2_PARAM_ANTSEL_TX, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "antsel_tx" }, - { PRISM2_PARAM_ANTSEL_TX, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getantsel_tx" }, - { PRISM2_PARAM_ANTSEL_RX, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "antsel_rx" }, - { PRISM2_PARAM_ANTSEL_RX, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getantsel_rx" }, - { PRISM2_PARAM_MONITOR_TYPE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "monitor_type" }, - { PRISM2_PARAM_MONITOR_TYPE, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmonitor_type" }, - { PRISM2_PARAM_WDS_TYPE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wds_type" }, - { PRISM2_PARAM_WDS_TYPE, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getwds_type" }, - { PRISM2_PARAM_HOSTSCAN, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostscan" }, - { PRISM2_PARAM_HOSTSCAN, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostscan" }, - { PRISM2_PARAM_AP_SCAN, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ap_scan" }, - { PRISM2_PARAM_AP_SCAN, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getap_scan" }, - { PRISM2_PARAM_ENH_SEC, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "enh_sec" }, - { PRISM2_PARAM_ENH_SEC, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getenh_sec" }, -#ifdef PRISM2_IO_DEBUG - { PRISM2_PARAM_IO_DEBUG, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "io_debug" }, - { PRISM2_PARAM_IO_DEBUG, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getio_debug" }, -#endif /* PRISM2_IO_DEBUG */ - { PRISM2_PARAM_BASIC_RATES, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "basic_rates" }, - { PRISM2_PARAM_BASIC_RATES, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbasic_rates" }, - { PRISM2_PARAM_OPER_RATES, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "oper_rates" }, - { PRISM2_PARAM_OPER_RATES, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getoper_rates" }, - { PRISM2_PARAM_HOSTAPD, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostapd" }, - { PRISM2_PARAM_HOSTAPD, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostapd" }, - { PRISM2_PARAM_HOSTAPD_STA, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostapd_sta" }, - { PRISM2_PARAM_HOSTAPD_STA, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostapd_sta" }, - { PRISM2_PARAM_WPA, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wpa" }, - { PRISM2_PARAM_WPA, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getwpa" }, - { PRISM2_PARAM_PRIVACY_INVOKED, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "privacy_invoked" }, - { PRISM2_PARAM_PRIVACY_INVOKED, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getprivacy_invo" }, - { PRISM2_PARAM_TKIP_COUNTERMEASURES, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "tkip_countermea" }, - { PRISM2_PARAM_TKIP_COUNTERMEASURES, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gettkip_counter" }, - { PRISM2_PARAM_DROP_UNENCRYPTED, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "drop_unencrypte" }, - { PRISM2_PARAM_DROP_UNENCRYPTED, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdrop_unencry" }, - { PRISM2_PARAM_SCAN_CHANNEL_MASK, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "scan_channels" }, - { PRISM2_PARAM_SCAN_CHANNEL_MASK, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getscan_channel" }, -}; - - -static int prism2_ioctl_priv_prism2_param(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *uwrq, char *extra) -{ - struct hostap_interface *iface; - local_info_t *local; - int *i = (int *) extra; - int param = *i; - int value = *(i + 1); - int ret = 0; - u16 val; - - iface = netdev_priv(dev); - local = iface->local; - - switch (param) { - case PRISM2_PARAM_TXRATECTRL: - local->fw_tx_rate_control = value; - break; - - case PRISM2_PARAM_BEACON_INT: - if (hostap_set_word(dev, HFA384X_RID_CNFBEACONINT, value) || - local->func->reset_port(dev)) - ret = -EINVAL; - else - local->beacon_int = value; - break; - -#ifndef PRISM2_NO_STATION_MODES - case PRISM2_PARAM_PSEUDO_IBSS: - if (value == local->pseudo_adhoc) - break; - - if (value != 0 && value != 1) { - ret = -EINVAL; - break; - } - - printk(KERN_DEBUG "prism2: %s: pseudo IBSS change %d -> %d\n", - dev->name, local->pseudo_adhoc, value); - local->pseudo_adhoc = value; - if (local->iw_mode != IW_MODE_ADHOC) - break; - - if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, - hostap_get_porttype(local))) { - ret = -EOPNOTSUPP; - break; - } - - if (local->func->reset_port(dev)) - ret = -EINVAL; - break; -#endif /* PRISM2_NO_STATION_MODES */ - - case PRISM2_PARAM_ALC: - printk(KERN_DEBUG "%s: %s ALC\n", dev->name, - value == 0 ? "Disabling" : "Enabling"); - val = HFA384X_TEST_CFG_BIT_ALC; - local->func->cmd(dev, HFA384X_CMDCODE_TEST | - (HFA384X_TEST_CFG_BITS << 8), - value == 0 ? 0 : 1, &val, NULL); - break; - - case PRISM2_PARAM_DUMP: - local->frame_dump = value; - break; - - case PRISM2_PARAM_OTHER_AP_POLICY: - if (value < 0 || value > 3) { - ret = -EINVAL; - break; - } - if (local->ap != NULL) - local->ap->ap_policy = value; - break; - - case PRISM2_PARAM_AP_MAX_INACTIVITY: - if (value < 0 || value > 7 * 24 * 60 * 60) { - ret = -EINVAL; - break; - } - if (local->ap != NULL) - local->ap->max_inactivity = value * HZ; - break; - - case PRISM2_PARAM_AP_BRIDGE_PACKETS: - if (local->ap != NULL) - local->ap->bridge_packets = value; - break; - - case PRISM2_PARAM_DTIM_PERIOD: - if (value < 0 || value > 65535) { - ret = -EINVAL; - break; - } - if (hostap_set_word(dev, HFA384X_RID_CNFOWNDTIMPERIOD, value) - || local->func->reset_port(dev)) - ret = -EINVAL; - else - local->dtim_period = value; - break; - - case PRISM2_PARAM_AP_NULLFUNC_ACK: - if (local->ap != NULL) - local->ap->nullfunc_ack = value; - break; - - case PRISM2_PARAM_MAX_WDS: - local->wds_max_connections = value; - break; - - case PRISM2_PARAM_AP_AUTOM_AP_WDS: - if (local->ap != NULL) { - if (!local->ap->autom_ap_wds && value) { - /* add WDS link to all APs in STA table */ - hostap_add_wds_links(local); - } - local->ap->autom_ap_wds = value; - } - break; - - case PRISM2_PARAM_AP_AUTH_ALGS: - local->auth_algs = value; - if (hostap_set_auth_algs(local)) - ret = -EINVAL; - break; - - case PRISM2_PARAM_MONITOR_ALLOW_FCSERR: - local->monitor_allow_fcserr = value; - break; - - case PRISM2_PARAM_HOST_ENCRYPT: - local->host_encrypt = value; - if (hostap_set_encryption(local) || - local->func->reset_port(dev)) - ret = -EINVAL; - break; - - case PRISM2_PARAM_HOST_DECRYPT: - local->host_decrypt = value; - if (hostap_set_encryption(local) || - local->func->reset_port(dev)) - ret = -EINVAL; - break; - -#ifndef PRISM2_NO_STATION_MODES - case PRISM2_PARAM_HOST_ROAMING: - if (value < 0 || value > 2) { - ret = -EINVAL; - break; - } - local->host_roaming = value; - if (hostap_set_roaming(local) || local->func->reset_port(dev)) - ret = -EINVAL; - break; -#endif /* PRISM2_NO_STATION_MODES */ - - case PRISM2_PARAM_BCRX_STA_KEY: - local->bcrx_sta_key = value; - break; - - case PRISM2_PARAM_IEEE_802_1X: - local->ieee_802_1x = value; - break; - - case PRISM2_PARAM_ANTSEL_TX: - if (value < 0 || value > HOSTAP_ANTSEL_HIGH) { - ret = -EINVAL; - break; - } - local->antsel_tx = value; - hostap_set_antsel(local); - break; - - case PRISM2_PARAM_ANTSEL_RX: - if (value < 0 || value > HOSTAP_ANTSEL_HIGH) { - ret = -EINVAL; - break; - } - local->antsel_rx = value; - hostap_set_antsel(local); - break; - - case PRISM2_PARAM_MONITOR_TYPE: - if (value != PRISM2_MONITOR_80211 && - value != PRISM2_MONITOR_CAPHDR && - value != PRISM2_MONITOR_PRISM && - value != PRISM2_MONITOR_RADIOTAP) { - ret = -EINVAL; - break; - } - local->monitor_type = value; - if (local->iw_mode == IW_MODE_MONITOR) - hostap_monitor_set_type(local); - break; - - case PRISM2_PARAM_WDS_TYPE: - local->wds_type = value; - break; - - case PRISM2_PARAM_HOSTSCAN: - { - struct hfa384x_hostscan_request scan_req; - u16 rate; - - memset(&scan_req, 0, sizeof(scan_req)); - scan_req.channel_list = cpu_to_le16(0x3fff); - switch (value) { - case 1: rate = HFA384X_RATES_1MBPS; break; - case 2: rate = HFA384X_RATES_2MBPS; break; - case 3: rate = HFA384X_RATES_5MBPS; break; - case 4: rate = HFA384X_RATES_11MBPS; break; - default: rate = HFA384X_RATES_1MBPS; break; - } - scan_req.txrate = cpu_to_le16(rate); - /* leave SSID empty to accept all SSIDs */ - - if (local->iw_mode == IW_MODE_MASTER) { - if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, - HFA384X_PORTTYPE_BSS) || - local->func->reset_port(dev)) - printk(KERN_DEBUG "Leaving Host AP mode " - "for HostScan failed\n"); - } - - if (local->func->set_rid(dev, HFA384X_RID_HOSTSCAN, &scan_req, - sizeof(scan_req))) { - printk(KERN_DEBUG "HOSTSCAN failed\n"); - ret = -EINVAL; - } - if (local->iw_mode == IW_MODE_MASTER) { - wait_queue_entry_t __wait; - init_waitqueue_entry(&__wait, current); - add_wait_queue(&local->hostscan_wq, &__wait); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ); - if (signal_pending(current)) - ret = -EINTR; - set_current_state(TASK_RUNNING); - remove_wait_queue(&local->hostscan_wq, &__wait); - - if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, - HFA384X_PORTTYPE_HOSTAP) || - local->func->reset_port(dev)) - printk(KERN_DEBUG "Returning to Host AP mode " - "after HostScan failed\n"); - } - break; - } - - case PRISM2_PARAM_AP_SCAN: - local->passive_scan_interval = value; - if (timer_pending(&local->passive_scan_timer)) - del_timer(&local->passive_scan_timer); - if (value > 0 && value < INT_MAX / HZ) { - local->passive_scan_timer.expires = jiffies + - local->passive_scan_interval * HZ; - add_timer(&local->passive_scan_timer); - } - break; - - case PRISM2_PARAM_ENH_SEC: - if (value < 0 || value > 3) { - ret = -EINVAL; - break; - } - local->enh_sec = value; - if (hostap_set_word(dev, HFA384X_RID_CNFENHSECURITY, - local->enh_sec) || - local->func->reset_port(dev)) { - printk(KERN_INFO "%s: cnfEnhSecurity requires STA f/w " - "1.6.3 or newer\n", dev->name); - ret = -EOPNOTSUPP; - } - break; - -#ifdef PRISM2_IO_DEBUG - case PRISM2_PARAM_IO_DEBUG: - local->io_debug_enabled = value; - break; -#endif /* PRISM2_IO_DEBUG */ - - case PRISM2_PARAM_BASIC_RATES: - if ((value & local->tx_rate_control) != value || value == 0) { - printk(KERN_INFO "%s: invalid basic rate set - basic " - "rates must be in supported rate set\n", - dev->name); - ret = -EINVAL; - break; - } - local->basic_rates = value; - if (hostap_set_word(dev, HFA384X_RID_CNFBASICRATES, - local->basic_rates) || - local->func->reset_port(dev)) - ret = -EINVAL; - break; - - case PRISM2_PARAM_OPER_RATES: - local->tx_rate_control = value; - if (hostap_set_rate(dev)) - ret = -EINVAL; - break; - - case PRISM2_PARAM_HOSTAPD: - ret = hostap_set_hostapd(local, value, 1); - break; - - case PRISM2_PARAM_HOSTAPD_STA: - ret = hostap_set_hostapd_sta(local, value, 1); - break; - - case PRISM2_PARAM_WPA: - local->wpa = value; - if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0)) - ret = -EOPNOTSUPP; - else if (hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE, - value ? 1 : 0)) - ret = -EINVAL; - break; - - case PRISM2_PARAM_PRIVACY_INVOKED: - local->privacy_invoked = value; - if (hostap_set_encryption(local) || - local->func->reset_port(dev)) - ret = -EINVAL; - break; - - case PRISM2_PARAM_TKIP_COUNTERMEASURES: - local->tkip_countermeasures = value; - break; - - case PRISM2_PARAM_DROP_UNENCRYPTED: - local->drop_unencrypted = value; - break; - - case PRISM2_PARAM_SCAN_CHANNEL_MASK: - local->scan_channel_mask = value; - break; - - default: - printk(KERN_DEBUG "%s: prism2_param: unknown param %d\n", - dev->name, param); - ret = -EOPNOTSUPP; - break; - } - - return ret; -} - - -static int prism2_ioctl_priv_get_prism2_param(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct hostap_interface *iface; - local_info_t *local; - int *param = (int *) extra; - int ret = 0; - - iface = netdev_priv(dev); - local = iface->local; - - switch (*param) { - case PRISM2_PARAM_TXRATECTRL: - *param = local->fw_tx_rate_control; - break; - - case PRISM2_PARAM_BEACON_INT: - *param = local->beacon_int; - break; - - case PRISM2_PARAM_PSEUDO_IBSS: - *param = local->pseudo_adhoc; - break; - - case PRISM2_PARAM_ALC: - ret = -EOPNOTSUPP; /* FIX */ - break; - - case PRISM2_PARAM_DUMP: - *param = local->frame_dump; - break; - - case PRISM2_PARAM_OTHER_AP_POLICY: - if (local->ap != NULL) - *param = local->ap->ap_policy; - else - ret = -EOPNOTSUPP; - break; - - case PRISM2_PARAM_AP_MAX_INACTIVITY: - if (local->ap != NULL) - *param = local->ap->max_inactivity / HZ; - else - ret = -EOPNOTSUPP; - break; - - case PRISM2_PARAM_AP_BRIDGE_PACKETS: - if (local->ap != NULL) - *param = local->ap->bridge_packets; - else - ret = -EOPNOTSUPP; - break; - - case PRISM2_PARAM_DTIM_PERIOD: - *param = local->dtim_period; - break; - - case PRISM2_PARAM_AP_NULLFUNC_ACK: - if (local->ap != NULL) - *param = local->ap->nullfunc_ack; - else - ret = -EOPNOTSUPP; - break; - - case PRISM2_PARAM_MAX_WDS: - *param = local->wds_max_connections; - break; - - case PRISM2_PARAM_AP_AUTOM_AP_WDS: - if (local->ap != NULL) - *param = local->ap->autom_ap_wds; - else - ret = -EOPNOTSUPP; - break; - - case PRISM2_PARAM_AP_AUTH_ALGS: - *param = local->auth_algs; - break; - - case PRISM2_PARAM_MONITOR_ALLOW_FCSERR: - *param = local->monitor_allow_fcserr; - break; - - case PRISM2_PARAM_HOST_ENCRYPT: - *param = local->host_encrypt; - break; - - case PRISM2_PARAM_HOST_DECRYPT: - *param = local->host_decrypt; - break; - - case PRISM2_PARAM_HOST_ROAMING: - *param = local->host_roaming; - break; - - case PRISM2_PARAM_BCRX_STA_KEY: - *param = local->bcrx_sta_key; - break; - - case PRISM2_PARAM_IEEE_802_1X: - *param = local->ieee_802_1x; - break; - - case PRISM2_PARAM_ANTSEL_TX: - *param = local->antsel_tx; - break; - - case PRISM2_PARAM_ANTSEL_RX: - *param = local->antsel_rx; - break; - - case PRISM2_PARAM_MONITOR_TYPE: - *param = local->monitor_type; - break; - - case PRISM2_PARAM_WDS_TYPE: - *param = local->wds_type; - break; - - case PRISM2_PARAM_HOSTSCAN: - ret = -EOPNOTSUPP; - break; - - case PRISM2_PARAM_AP_SCAN: - *param = local->passive_scan_interval; - break; - - case PRISM2_PARAM_ENH_SEC: - *param = local->enh_sec; - break; - -#ifdef PRISM2_IO_DEBUG - case PRISM2_PARAM_IO_DEBUG: - *param = local->io_debug_enabled; - break; -#endif /* PRISM2_IO_DEBUG */ - - case PRISM2_PARAM_BASIC_RATES: - *param = local->basic_rates; - break; - - case PRISM2_PARAM_OPER_RATES: - *param = local->tx_rate_control; - break; - - case PRISM2_PARAM_HOSTAPD: - *param = local->hostapd; - break; - - case PRISM2_PARAM_HOSTAPD_STA: - *param = local->hostapd_sta; - break; - - case PRISM2_PARAM_WPA: - if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0)) - ret = -EOPNOTSUPP; - *param = local->wpa; - break; - - case PRISM2_PARAM_PRIVACY_INVOKED: - *param = local->privacy_invoked; - break; - - case PRISM2_PARAM_TKIP_COUNTERMEASURES: - *param = local->tkip_countermeasures; - break; - - case PRISM2_PARAM_DROP_UNENCRYPTED: - *param = local->drop_unencrypted; - break; - - case PRISM2_PARAM_SCAN_CHANNEL_MASK: - *param = local->scan_channel_mask; - break; - - default: - printk(KERN_DEBUG "%s: get_prism2_param: unknown param %d\n", - dev->name, *param); - ret = -EOPNOTSUPP; - break; - } - - return ret; -} - - -static int prism2_ioctl_priv_readmif(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct hostap_interface *iface; - local_info_t *local; - u16 resp0; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->func->cmd(dev, HFA384X_CMDCODE_READMIF, *extra, NULL, - &resp0)) - return -EOPNOTSUPP; - else - *extra = resp0; - - return 0; -} - - -static int prism2_ioctl_priv_writemif(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct hostap_interface *iface; - local_info_t *local; - u16 cr, val; - - iface = netdev_priv(dev); - local = iface->local; - - cr = *extra; - val = *(extra + 1); - if (local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, cr, &val, NULL)) - return -EOPNOTSUPP; - - return 0; -} - - -#ifdef PRISM2_DOWNLOAD_SUPPORT -static int prism2_ioctl_priv_download(local_info_t *local, struct iw_point *p) -{ - struct prism2_download_param *param; - int ret = 0; - - if (p->length < sizeof(struct prism2_download_param) || - p->length > 1024 || !p->pointer) - return -EINVAL; - - param = memdup_user(p->pointer, p->length); - if (IS_ERR(param)) { - return PTR_ERR(param); - } - - if (p->length < sizeof(struct prism2_download_param) + - param->num_areas * sizeof(struct prism2_download_area)) { - ret = -EINVAL; - goto out; - } - - ret = local->func->download(local, param); - - out: - kfree(param); - return ret; -} -#endif /* PRISM2_DOWNLOAD_SUPPORT */ - - -static int prism2_set_genericelement(struct net_device *dev, u8 *elem, - size_t len) -{ - struct hostap_interface *iface = netdev_priv(dev); - local_info_t *local = iface->local; - u8 *buf; - - /* - * Add 16-bit length in the beginning of the buffer because Prism2 RID - * includes it. - */ - buf = kmalloc(len + 2, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - *((__le16 *) buf) = cpu_to_le16(len); - memcpy(buf + 2, elem, len); - - kfree(local->generic_elem); - local->generic_elem = buf; - local->generic_elem_len = len + 2; - - return local->func->set_rid(local->dev, HFA384X_RID_GENERICELEMENT, - buf, len + 2); -} - - -static int prism2_ioctl_siwauth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *data = &wrqu->param; - struct hostap_interface *iface = netdev_priv(dev); - local_info_t *local = iface->local; - - switch (data->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - case IW_AUTH_CIPHER_PAIRWISE: - case IW_AUTH_CIPHER_GROUP: - case IW_AUTH_KEY_MGMT: - /* - * Host AP driver does not use these parameters and allows - * wpa_supplicant to control them internally. - */ - break; - case IW_AUTH_TKIP_COUNTERMEASURES: - local->tkip_countermeasures = data->value; - break; - case IW_AUTH_DROP_UNENCRYPTED: - local->drop_unencrypted = data->value; - break; - case IW_AUTH_80211_AUTH_ALG: - local->auth_algs = data->value; - break; - case IW_AUTH_WPA_ENABLED: - if (data->value == 0) { - local->wpa = 0; - if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0)) - break; - prism2_set_genericelement(dev, "", 0); - local->host_roaming = 0; - local->privacy_invoked = 0; - if (hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE, - 0) || - hostap_set_roaming(local) || - hostap_set_encryption(local) || - local->func->reset_port(dev)) - return -EINVAL; - break; - } - if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0)) - return -EOPNOTSUPP; - local->host_roaming = 2; - local->privacy_invoked = 1; - local->wpa = 1; - if (hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE, 1) || - hostap_set_roaming(local) || - hostap_set_encryption(local) || - local->func->reset_port(dev)) - return -EINVAL; - break; - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - local->ieee_802_1x = data->value; - break; - case IW_AUTH_PRIVACY_INVOKED: - local->privacy_invoked = data->value; - break; - default: - return -EOPNOTSUPP; - } - return 0; -} - - -static int prism2_ioctl_giwauth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *data = &wrqu->param; - struct hostap_interface *iface = netdev_priv(dev); - local_info_t *local = iface->local; - - switch (data->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - case IW_AUTH_CIPHER_PAIRWISE: - case IW_AUTH_CIPHER_GROUP: - case IW_AUTH_KEY_MGMT: - /* - * Host AP driver does not use these parameters and allows - * wpa_supplicant to control them internally. - */ - return -EOPNOTSUPP; - case IW_AUTH_TKIP_COUNTERMEASURES: - data->value = local->tkip_countermeasures; - break; - case IW_AUTH_DROP_UNENCRYPTED: - data->value = local->drop_unencrypted; - break; - case IW_AUTH_80211_AUTH_ALG: - data->value = local->auth_algs; - break; - case IW_AUTH_WPA_ENABLED: - data->value = local->wpa; - break; - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - data->value = local->ieee_802_1x; - break; - default: - return -EOPNOTSUPP; - } - return 0; -} - - -static int prism2_ioctl_siwencodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_point *erq = &wrqu->encoding; - struct hostap_interface *iface = netdev_priv(dev); - local_info_t *local = iface->local; - struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; - int i, ret = 0; - struct lib80211_crypto_ops *ops; - struct lib80211_crypt_data **crypt; - void *sta_ptr; - u8 *addr; - const char *alg, *module; - - i = erq->flags & IW_ENCODE_INDEX; - if (i > WEP_KEYS) - return -EINVAL; - if (i < 1 || i > WEP_KEYS) - i = local->crypt_info.tx_keyidx; - else - i--; - if (i < 0 || i >= WEP_KEYS) - return -EINVAL; - - addr = ext->addr.sa_data; - if (is_broadcast_ether_addr(addr)) { - sta_ptr = NULL; - crypt = &local->crypt_info.crypt[i]; - } else { - if (i != 0) - return -EINVAL; - sta_ptr = ap_crypt_get_ptrs(local->ap, addr, 0, &crypt); - if (sta_ptr == NULL) { - if (local->iw_mode == IW_MODE_INFRA) { - /* - * TODO: add STA entry for the current AP so - * that unicast key can be used. For now, this - * is emulated by using default key idx 0. - */ - i = 0; - crypt = &local->crypt_info.crypt[i]; - } else - return -EINVAL; - } - } - - if ((erq->flags & IW_ENCODE_DISABLED) || - ext->alg == IW_ENCODE_ALG_NONE) { - if (*crypt) - lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); - goto done; - } - - switch (ext->alg) { - case IW_ENCODE_ALG_WEP: - alg = "WEP"; - module = "lib80211_crypt_wep"; - break; - case IW_ENCODE_ALG_TKIP: - alg = "TKIP"; - module = "lib80211_crypt_tkip"; - break; - case IW_ENCODE_ALG_CCMP: - alg = "CCMP"; - module = "lib80211_crypt_ccmp"; - break; - default: - printk(KERN_DEBUG "%s: unsupported algorithm %d\n", - local->dev->name, ext->alg); - ret = -EOPNOTSUPP; - goto done; - } - - ops = lib80211_get_crypto_ops(alg); - if (ops == NULL) { - request_module(module); - ops = lib80211_get_crypto_ops(alg); - } - if (ops == NULL) { - printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n", - local->dev->name, alg); - ret = -EOPNOTSUPP; - goto done; - } - - if (sta_ptr || ext->alg != IW_ENCODE_ALG_WEP) { - /* - * Per station encryption and other than WEP algorithms - * require host-based encryption, so force them on - * automatically. - */ - local->host_decrypt = local->host_encrypt = 1; - } - - if (*crypt == NULL || (*crypt)->ops != ops) { - struct lib80211_crypt_data *new_crypt; - - lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); - - new_crypt = kzalloc(sizeof(struct lib80211_crypt_data), - GFP_KERNEL); - if (new_crypt == NULL) { - ret = -ENOMEM; - goto done; - } - new_crypt->ops = ops; - if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) - new_crypt->priv = new_crypt->ops->init(i); - if (new_crypt->priv == NULL) { - kfree(new_crypt); - ret = -EINVAL; - goto done; - } - - *crypt = new_crypt; - } - - /* - * TODO: if ext_flags does not have IW_ENCODE_EXT_RX_SEQ_VALID, the - * existing seq# should not be changed. - * TODO: if ext_flags has IW_ENCODE_EXT_TX_SEQ_VALID, next TX seq# - * should be changed to something else than zero. - */ - if ((!(ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) || ext->key_len > 0) - && (*crypt)->ops->set_key && - (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq, - (*crypt)->priv) < 0) { - printk(KERN_DEBUG "%s: key setting failed\n", - local->dev->name); - ret = -EINVAL; - goto done; - } - - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { - if (!sta_ptr) - local->crypt_info.tx_keyidx = i; - } - - - if (sta_ptr == NULL && ext->key_len > 0) { - int first = 1, j; - for (j = 0; j < WEP_KEYS; j++) { - if (j != i && local->crypt_info.crypt[j]) { - first = 0; - break; - } - } - if (first) - local->crypt_info.tx_keyidx = i; - } - - done: - if (sta_ptr) - hostap_handle_sta_release(sta_ptr); - - local->open_wep = erq->flags & IW_ENCODE_OPEN; - - /* - * Do not reset port0 if card is in Managed mode since resetting will - * generate new IEEE 802.11 authentication which may end up in looping - * with IEEE 802.1X. Prism2 documentation seem to require port reset - * after WEP configuration. However, keys are apparently changed at - * least in Managed mode. - */ - if (ret == 0 && - (hostap_set_encryption(local) || - (local->iw_mode != IW_MODE_INFRA && - local->func->reset_port(local->dev)))) - ret = -EINVAL; - - return ret; -} - - -static int prism2_ioctl_giwencodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_point *erq = &wrqu->encoding; - struct hostap_interface *iface = netdev_priv(dev); - local_info_t *local = iface->local; - struct lib80211_crypt_data **crypt; - void *sta_ptr; - int max_key_len, i; - struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; - u8 *addr; - - max_key_len = erq->length - sizeof(*ext); - if (max_key_len < 0) - return -EINVAL; - - i = erq->flags & IW_ENCODE_INDEX; - if (i < 1 || i > WEP_KEYS) - i = local->crypt_info.tx_keyidx; - else - i--; - - addr = ext->addr.sa_data; - if (is_broadcast_ether_addr(addr)) { - sta_ptr = NULL; - crypt = &local->crypt_info.crypt[i]; - } else { - i = 0; - sta_ptr = ap_crypt_get_ptrs(local->ap, addr, 0, &crypt); - if (sta_ptr == NULL) - return -EINVAL; - } - erq->flags = i + 1; - memset(ext, 0, sizeof(*ext)); - - if (*crypt == NULL || (*crypt)->ops == NULL) { - ext->alg = IW_ENCODE_ALG_NONE; - ext->key_len = 0; - erq->flags |= IW_ENCODE_DISABLED; - } else { - if (strcmp((*crypt)->ops->name, "WEP") == 0) - ext->alg = IW_ENCODE_ALG_WEP; - else if (strcmp((*crypt)->ops->name, "TKIP") == 0) - ext->alg = IW_ENCODE_ALG_TKIP; - else if (strcmp((*crypt)->ops->name, "CCMP") == 0) - ext->alg = IW_ENCODE_ALG_CCMP; - else - return -EINVAL; - - if ((*crypt)->ops->get_key) { - ext->key_len = - (*crypt)->ops->get_key(ext->key, - max_key_len, - ext->tx_seq, - (*crypt)->priv); - if (ext->key_len && - (ext->alg == IW_ENCODE_ALG_TKIP || - ext->alg == IW_ENCODE_ALG_CCMP)) - ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID; - } - } - - if (sta_ptr) - hostap_handle_sta_release(sta_ptr); - - return 0; -} - - -static int prism2_ioctl_set_encryption(local_info_t *local, - struct prism2_hostapd_param *param, - int param_len) -{ - int ret = 0; - struct lib80211_crypto_ops *ops; - struct lib80211_crypt_data **crypt; - void *sta_ptr; - - param->u.crypt.err = 0; - param->u.crypt.alg[HOSTAP_CRYPT_ALG_NAME_LEN - 1] = '\0'; - - if (param_len != - (int) ((char *) param->u.crypt.key - (char *) param) + - param->u.crypt.key_len) - return -EINVAL; - - if (is_broadcast_ether_addr(param->sta_addr)) { - if (param->u.crypt.idx >= WEP_KEYS) - return -EINVAL; - sta_ptr = NULL; - crypt = &local->crypt_info.crypt[param->u.crypt.idx]; - } else { - if (param->u.crypt.idx) - return -EINVAL; - sta_ptr = ap_crypt_get_ptrs( - local->ap, param->sta_addr, - (param->u.crypt.flags & HOSTAP_CRYPT_FLAG_PERMANENT), - &crypt); - - if (sta_ptr == NULL) { - param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR; - return -EINVAL; - } - } - - if (strcmp(param->u.crypt.alg, "none") == 0) { - if (crypt) - lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); - goto done; - } - - ops = lib80211_get_crypto_ops(param->u.crypt.alg); - if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) { - request_module("lib80211_crypt_wep"); - ops = lib80211_get_crypto_ops(param->u.crypt.alg); - } else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) { - request_module("lib80211_crypt_tkip"); - ops = lib80211_get_crypto_ops(param->u.crypt.alg); - } else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) { - request_module("lib80211_crypt_ccmp"); - ops = lib80211_get_crypto_ops(param->u.crypt.alg); - } - if (ops == NULL) { - printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n", - local->dev->name, param->u.crypt.alg); - param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ALG; - ret = -EINVAL; - goto done; - } - - /* station based encryption and other than WEP algorithms require - * host-based encryption, so force them on automatically */ - local->host_decrypt = local->host_encrypt = 1; - - if (*crypt == NULL || (*crypt)->ops != ops) { - struct lib80211_crypt_data *new_crypt; - - lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); - - new_crypt = kzalloc(sizeof(struct lib80211_crypt_data), - GFP_KERNEL); - if (new_crypt == NULL) { - ret = -ENOMEM; - goto done; - } - new_crypt->ops = ops; - new_crypt->priv = new_crypt->ops->init(param->u.crypt.idx); - if (new_crypt->priv == NULL) { - kfree(new_crypt); - param->u.crypt.err = - HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED; - ret = -EINVAL; - goto done; - } - - *crypt = new_crypt; - } - - if ((!(param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY) || - param->u.crypt.key_len > 0) && (*crypt)->ops->set_key && - (*crypt)->ops->set_key(param->u.crypt.key, - param->u.crypt.key_len, param->u.crypt.seq, - (*crypt)->priv) < 0) { - printk(KERN_DEBUG "%s: key setting failed\n", - local->dev->name); - param->u.crypt.err = HOSTAP_CRYPT_ERR_KEY_SET_FAILED; - ret = -EINVAL; - goto done; - } - - if (param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY) { - if (!sta_ptr) - local->crypt_info.tx_keyidx = param->u.crypt.idx; - else if (param->u.crypt.idx) { - printk(KERN_DEBUG "%s: TX key idx setting failed\n", - local->dev->name); - param->u.crypt.err = - HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED; - ret = -EINVAL; - goto done; - } - } - - done: - if (sta_ptr) - hostap_handle_sta_release(sta_ptr); - - /* Do not reset port0 if card is in Managed mode since resetting will - * generate new IEEE 802.11 authentication which may end up in looping - * with IEEE 802.1X. Prism2 documentation seem to require port reset - * after WEP configuration. However, keys are apparently changed at - * least in Managed mode. */ - if (ret == 0 && - (hostap_set_encryption(local) || - (local->iw_mode != IW_MODE_INFRA && - local->func->reset_port(local->dev)))) { - param->u.crypt.err = HOSTAP_CRYPT_ERR_CARD_CONF_FAILED; - return -EINVAL; - } - - return ret; -} - - -static int prism2_ioctl_get_encryption(local_info_t *local, - struct prism2_hostapd_param *param, - int param_len) -{ - struct lib80211_crypt_data **crypt; - void *sta_ptr; - int max_key_len; - - param->u.crypt.err = 0; - - max_key_len = param_len - - (int) ((char *) param->u.crypt.key - (char *) param); - if (max_key_len < 0) - return -EINVAL; - - if (is_broadcast_ether_addr(param->sta_addr)) { - sta_ptr = NULL; - if (param->u.crypt.idx >= WEP_KEYS) - param->u.crypt.idx = local->crypt_info.tx_keyidx; - crypt = &local->crypt_info.crypt[param->u.crypt.idx]; - } else { - param->u.crypt.idx = 0; - sta_ptr = ap_crypt_get_ptrs(local->ap, param->sta_addr, 0, - &crypt); - - if (sta_ptr == NULL) { - param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR; - return -EINVAL; - } - } - - if (*crypt == NULL || (*crypt)->ops == NULL) { - memcpy(param->u.crypt.alg, "none", 5); - param->u.crypt.key_len = 0; - param->u.crypt.idx = 0xff; - } else { - strscpy(param->u.crypt.alg, (*crypt)->ops->name, - HOSTAP_CRYPT_ALG_NAME_LEN); - param->u.crypt.key_len = 0; - - memset(param->u.crypt.seq, 0, 8); - if ((*crypt)->ops->get_key) { - param->u.crypt.key_len = - (*crypt)->ops->get_key(param->u.crypt.key, - max_key_len, - param->u.crypt.seq, - (*crypt)->priv); - } - } - - if (sta_ptr) - hostap_handle_sta_release(sta_ptr); - - return 0; -} - - -static int prism2_ioctl_get_rid(local_info_t *local, - struct prism2_hostapd_param *param, - int param_len) -{ - int max_len, res; - - max_len = param_len - PRISM2_HOSTAPD_RID_HDR_LEN; - if (max_len < 0) - return -EINVAL; - - res = local->func->get_rid(local->dev, param->u.rid.rid, - param->u.rid.data, param->u.rid.len, 0); - if (res >= 0) { - param->u.rid.len = res; - return 0; - } - - return res; -} - - -static int prism2_ioctl_set_rid(local_info_t *local, - struct prism2_hostapd_param *param, - int param_len) -{ - int max_len; - - max_len = param_len - PRISM2_HOSTAPD_RID_HDR_LEN; - if (max_len < 0 || max_len < param->u.rid.len) - return -EINVAL; - - return local->func->set_rid(local->dev, param->u.rid.rid, - param->u.rid.data, param->u.rid.len); -} - - -static int prism2_ioctl_set_assoc_ap_addr(local_info_t *local, - struct prism2_hostapd_param *param, - int param_len) -{ - printk(KERN_DEBUG "%ssta: associated as client with AP %pM\n", - local->dev->name, param->sta_addr); - memcpy(local->assoc_ap_addr, param->sta_addr, ETH_ALEN); - return 0; -} - - -static int prism2_ioctl_siwgenie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_point *data = &wrqu->data; - return prism2_set_genericelement(dev, extra, data->length); -} - - -static int prism2_ioctl_giwgenie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_point *data = &wrqu->data; - struct hostap_interface *iface = netdev_priv(dev); - local_info_t *local = iface->local; - int len = local->generic_elem_len - 2; - - if (len <= 0 || local->generic_elem == NULL) { - data->length = 0; - return 0; - } - - if (data->length < len) - return -E2BIG; - - data->length = len; - memcpy(extra, local->generic_elem + 2, len); - - return 0; -} - - -static int prism2_ioctl_set_generic_element(local_info_t *local, - struct prism2_hostapd_param *param, - int param_len) -{ - int max_len, len; - - len = param->u.generic_elem.len; - max_len = param_len - PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN; - if (max_len < 0 || max_len < len) - return -EINVAL; - - return prism2_set_genericelement(local->dev, - param->u.generic_elem.data, len); -} - - -static int prism2_ioctl_siwmlme(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct hostap_interface *iface = netdev_priv(dev); - local_info_t *local = iface->local; - struct iw_mlme *mlme = (struct iw_mlme *) extra; - __le16 reason; - - reason = cpu_to_le16(mlme->reason_code); - - switch (mlme->cmd) { - case IW_MLME_DEAUTH: - return prism2_sta_send_mgmt(local, mlme->addr.sa_data, - IEEE80211_STYPE_DEAUTH, - (u8 *) &reason, 2); - case IW_MLME_DISASSOC: - return prism2_sta_send_mgmt(local, mlme->addr.sa_data, - IEEE80211_STYPE_DISASSOC, - (u8 *) &reason, 2); - default: - return -EOPNOTSUPP; - } -} - - -static int prism2_ioctl_mlme(local_info_t *local, - struct prism2_hostapd_param *param) -{ - __le16 reason; - - reason = cpu_to_le16(param->u.mlme.reason_code); - switch (param->u.mlme.cmd) { - case MLME_STA_DEAUTH: - return prism2_sta_send_mgmt(local, param->sta_addr, - IEEE80211_STYPE_DEAUTH, - (u8 *) &reason, 2); - case MLME_STA_DISASSOC: - return prism2_sta_send_mgmt(local, param->sta_addr, - IEEE80211_STYPE_DISASSOC, - (u8 *) &reason, 2); - default: - return -EOPNOTSUPP; - } -} - - -static int prism2_ioctl_scan_req(local_info_t *local, - struct prism2_hostapd_param *param) -{ -#ifndef PRISM2_NO_STATION_MODES - if ((local->iw_mode != IW_MODE_INFRA && - local->iw_mode != IW_MODE_ADHOC) || - (local->sta_fw_ver < PRISM2_FW_VER(1,3,1))) - return -EOPNOTSUPP; - - if (!local->dev_enabled) - return -ENETDOWN; - - return prism2_request_hostscan(local->dev, param->u.scan_req.ssid, - param->u.scan_req.ssid_len); -#else /* PRISM2_NO_STATION_MODES */ - return -EOPNOTSUPP; -#endif /* PRISM2_NO_STATION_MODES */ -} - - -static int prism2_ioctl_priv_hostapd(local_info_t *local, struct iw_point *p) -{ - struct prism2_hostapd_param *param; - int ret = 0; - int ap_ioctl = 0; - - if (p->length < sizeof(struct prism2_hostapd_param) || - p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer) - return -EINVAL; - - param = memdup_user(p->pointer, p->length); - if (IS_ERR(param)) { - return PTR_ERR(param); - } - - switch (param->cmd) { - case PRISM2_SET_ENCRYPTION: - ret = prism2_ioctl_set_encryption(local, param, p->length); - break; - case PRISM2_GET_ENCRYPTION: - ret = prism2_ioctl_get_encryption(local, param, p->length); - break; - case PRISM2_HOSTAPD_GET_RID: - ret = prism2_ioctl_get_rid(local, param, p->length); - break; - case PRISM2_HOSTAPD_SET_RID: - ret = prism2_ioctl_set_rid(local, param, p->length); - break; - case PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR: - ret = prism2_ioctl_set_assoc_ap_addr(local, param, p->length); - break; - case PRISM2_HOSTAPD_SET_GENERIC_ELEMENT: - ret = prism2_ioctl_set_generic_element(local, param, - p->length); - break; - case PRISM2_HOSTAPD_MLME: - ret = prism2_ioctl_mlme(local, param); - break; - case PRISM2_HOSTAPD_SCAN_REQ: - ret = prism2_ioctl_scan_req(local, param); - break; - default: - ret = prism2_hostapd(local->ap, param); - ap_ioctl = 1; - break; - } - - if (ret == 1 || !ap_ioctl) { - if (copy_to_user(p->pointer, param, p->length)) { - ret = -EFAULT; - goto out; - } else if (ap_ioctl) - ret = 0; - } - - out: - kfree(param); - return ret; -} - - -static void prism2_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - strscpy(info->driver, "hostap", sizeof(info->driver)); - snprintf(info->fw_version, sizeof(info->fw_version), - "%d.%d.%d", (local->sta_fw_ver >> 16) & 0xff, - (local->sta_fw_ver >> 8) & 0xff, - local->sta_fw_ver & 0xff); -} - -const struct ethtool_ops prism2_ethtool_ops = { - .get_drvinfo = prism2_get_drvinfo -}; - - -/* Structures to export the Wireless Handlers */ - -static const iw_handler prism2_handler[] = -{ - IW_HANDLER(SIOCGIWNAME, prism2_get_name), - IW_HANDLER(SIOCSIWFREQ, prism2_ioctl_siwfreq), - IW_HANDLER(SIOCGIWFREQ, prism2_ioctl_giwfreq), - IW_HANDLER(SIOCSIWMODE, prism2_ioctl_siwmode), - IW_HANDLER(SIOCGIWMODE, prism2_ioctl_giwmode), - IW_HANDLER(SIOCSIWSENS, prism2_ioctl_siwsens), - IW_HANDLER(SIOCGIWSENS, prism2_ioctl_giwsens), - IW_HANDLER(SIOCGIWRANGE, prism2_ioctl_giwrange), - IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy), - IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy), - IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy), - IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy), - IW_HANDLER(SIOCSIWAP, prism2_ioctl_siwap), - IW_HANDLER(SIOCGIWAP, prism2_ioctl_giwap), - IW_HANDLER(SIOCSIWMLME, prism2_ioctl_siwmlme), - IW_HANDLER(SIOCGIWAPLIST, prism2_ioctl_giwaplist), - IW_HANDLER(SIOCSIWSCAN, prism2_ioctl_siwscan), - IW_HANDLER(SIOCGIWSCAN, prism2_ioctl_giwscan), - IW_HANDLER(SIOCSIWESSID, prism2_ioctl_siwessid), - IW_HANDLER(SIOCGIWESSID, prism2_ioctl_giwessid), - IW_HANDLER(SIOCSIWNICKN, prism2_ioctl_siwnickn), - IW_HANDLER(SIOCGIWNICKN, prism2_ioctl_giwnickn), - IW_HANDLER(SIOCSIWRATE, prism2_ioctl_siwrate), - IW_HANDLER(SIOCGIWRATE, prism2_ioctl_giwrate), - IW_HANDLER(SIOCSIWRTS, prism2_ioctl_siwrts), - IW_HANDLER(SIOCGIWRTS, prism2_ioctl_giwrts), - IW_HANDLER(SIOCSIWFRAG, prism2_ioctl_siwfrag), - IW_HANDLER(SIOCGIWFRAG, prism2_ioctl_giwfrag), - IW_HANDLER(SIOCSIWTXPOW, prism2_ioctl_siwtxpow), - IW_HANDLER(SIOCGIWTXPOW, prism2_ioctl_giwtxpow), - IW_HANDLER(SIOCSIWRETRY, prism2_ioctl_siwretry), - IW_HANDLER(SIOCGIWRETRY, prism2_ioctl_giwretry), - IW_HANDLER(SIOCSIWENCODE, prism2_ioctl_siwencode), - IW_HANDLER(SIOCGIWENCODE, prism2_ioctl_giwencode), - IW_HANDLER(SIOCSIWPOWER, prism2_ioctl_siwpower), - IW_HANDLER(SIOCGIWPOWER, prism2_ioctl_giwpower), - IW_HANDLER(SIOCSIWGENIE, prism2_ioctl_siwgenie), - IW_HANDLER(SIOCGIWGENIE, prism2_ioctl_giwgenie), - IW_HANDLER(SIOCSIWAUTH, prism2_ioctl_siwauth), - IW_HANDLER(SIOCGIWAUTH, prism2_ioctl_giwauth), - IW_HANDLER(SIOCSIWENCODEEXT, prism2_ioctl_siwencodeext), - IW_HANDLER(SIOCGIWENCODEEXT, prism2_ioctl_giwencodeext), -}; - -static const iw_handler prism2_private_handler[] = -{ /* SIOCIWFIRSTPRIV + */ - prism2_ioctl_priv_prism2_param, /* 0 */ - prism2_ioctl_priv_get_prism2_param, /* 1 */ - prism2_ioctl_priv_writemif, /* 2 */ - prism2_ioctl_priv_readmif, /* 3 */ -}; - -const struct iw_handler_def hostap_iw_handler_def = -{ - .num_standard = ARRAY_SIZE(prism2_handler), - .num_private = ARRAY_SIZE(prism2_private_handler), - .num_private_args = ARRAY_SIZE(prism2_priv), - .standard = prism2_handler, - .private = prism2_private_handler, - .private_args = (struct iw_priv_args *) prism2_priv, - .get_wireless_stats = hostap_get_wireless_stats, -}; - - -/* Private ioctls that are not used with iwpriv; - * in SIOCDEVPRIVATE range */ -int hostap_siocdevprivate(struct net_device *dev, struct ifreq *ifr, - void __user *data, int cmd) -{ - struct iwreq *wrq = (struct iwreq *)ifr; - struct hostap_interface *iface; - local_info_t *local; - int ret = 0; - - iface = netdev_priv(dev); - local = iface->local; - - if (in_compat_syscall()) /* not implemented yet */ - return -EOPNOTSUPP; - - switch (cmd) { -#ifdef PRISM2_DOWNLOAD_SUPPORT - case PRISM2_IOCTL_DOWNLOAD: - if (!capable(CAP_NET_ADMIN)) ret = -EPERM; - else ret = prism2_ioctl_priv_download(local, &wrq->u.data); - break; -#endif /* PRISM2_DOWNLOAD_SUPPORT */ - - case PRISM2_IOCTL_HOSTAPD: - if (!capable(CAP_NET_ADMIN)) ret = -EPERM; - else ret = prism2_ioctl_priv_hostapd(local, &wrq->u.data); - break; - - default: - ret = -EOPNOTSUPP; - break; - } - - return ret; -} diff --git a/drivers/net/wireless/intersil/hostap/hostap_main.c b/drivers/net/wireless/intersil/hostap/hostap_main.c deleted file mode 100644 index bf86ac26c2acc..0000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_main.c +++ /dev/null @@ -1,1123 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Host AP (software wireless LAN access point) driver for - * Intersil Prism2/2.5/3 - hostap.o module, common routines - * - * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen - * - * Copyright (c) 2002-2005, Jouni Malinen - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "hostap_wlan.h" -#include "hostap_80211.h" -#include "hostap_ap.h" -#include "hostap.h" - -MODULE_AUTHOR("Jouni Malinen"); -MODULE_DESCRIPTION("Host AP common routines"); -MODULE_LICENSE("GPL"); - -#define TX_TIMEOUT (2 * HZ) - -#define PRISM2_MAX_FRAME_SIZE 2304 -#define PRISM2_MIN_MTU 256 -/* FIX: */ -#define PRISM2_MAX_MTU (PRISM2_MAX_FRAME_SIZE - (6 /* LLC */ + 8 /* WEP */)) - - -struct net_device * hostap_add_interface(struct local_info *local, - int type, int rtnl_locked, - const char *prefix, - const char *name) -{ - struct net_device *dev, *mdev; - struct hostap_interface *iface; - int ret; - - dev = alloc_etherdev(sizeof(struct hostap_interface)); - if (dev == NULL) - return NULL; - - iface = netdev_priv(dev); - iface->dev = dev; - iface->local = local; - iface->type = type; - list_add(&iface->list, &local->hostap_interfaces); - - mdev = local->dev; - eth_hw_addr_inherit(dev, mdev); - dev->base_addr = mdev->base_addr; - dev->irq = mdev->irq; - dev->mem_start = mdev->mem_start; - dev->mem_end = mdev->mem_end; - - hostap_setup_dev(dev, local, type); - dev->needs_free_netdev = true; - - sprintf(dev->name, "%s%s", prefix, name); - if (!rtnl_locked) - rtnl_lock(); - - SET_NETDEV_DEV(dev, mdev->dev.parent); - ret = register_netdevice(dev); - - if (!rtnl_locked) - rtnl_unlock(); - - if (ret < 0) { - printk(KERN_WARNING "%s: failed to add new netdevice!\n", - dev->name); - free_netdev(dev); - return NULL; - } - - printk(KERN_DEBUG "%s: registered netdevice %s\n", - mdev->name, dev->name); - - return dev; -} - - -void hostap_remove_interface(struct net_device *dev, int rtnl_locked, - int remove_from_list) -{ - struct hostap_interface *iface; - - if (!dev) - return; - - iface = netdev_priv(dev); - - if (remove_from_list) { - list_del(&iface->list); - } - - if (dev == iface->local->ddev) - iface->local->ddev = NULL; - else if (dev == iface->local->apdev) - iface->local->apdev = NULL; - else if (dev == iface->local->stadev) - iface->local->stadev = NULL; - - if (rtnl_locked) - unregister_netdevice(dev); - else - unregister_netdev(dev); - - /* 'dev->needs_free_netdev = true' implies device data, including - * private data, will be freed when the device is removed */ -} - - -static inline int prism2_wds_special_addr(u8 *addr) -{ - if (addr[0] || addr[1] || addr[2] || addr[3] || addr[4] || addr[5]) - return 0; - - return 1; -} - - -int prism2_wds_add(local_info_t *local, u8 *remote_addr, - int rtnl_locked) -{ - struct net_device *dev; - struct list_head *ptr; - struct hostap_interface *iface, *empty, *match; - - empty = match = NULL; - read_lock_bh(&local->iface_lock); - list_for_each(ptr, &local->hostap_interfaces) { - iface = list_entry(ptr, struct hostap_interface, list); - if (iface->type != HOSTAP_INTERFACE_WDS) - continue; - - if (prism2_wds_special_addr(iface->u.wds.remote_addr)) - empty = iface; - else if (ether_addr_equal(iface->u.wds.remote_addr, remote_addr)) { - match = iface; - break; - } - } - if (!match && empty && !prism2_wds_special_addr(remote_addr)) { - /* take pre-allocated entry into use */ - memcpy(empty->u.wds.remote_addr, remote_addr, ETH_ALEN); - read_unlock_bh(&local->iface_lock); - printk(KERN_DEBUG "%s: using pre-allocated WDS netdevice %s\n", - local->dev->name, empty->dev->name); - return 0; - } - read_unlock_bh(&local->iface_lock); - - if (!prism2_wds_special_addr(remote_addr)) { - if (match) - return -EEXIST; - hostap_add_sta(local->ap, remote_addr); - } - - if (local->wds_connections >= local->wds_max_connections) - return -ENOBUFS; - - /* verify that there is room for wds# postfix in the interface name */ - if (strlen(local->dev->name) >= IFNAMSIZ - 5) { - printk(KERN_DEBUG "'%s' too long base device name\n", - local->dev->name); - return -EINVAL; - } - - dev = hostap_add_interface(local, HOSTAP_INTERFACE_WDS, rtnl_locked, - local->ddev->name, "wds%d"); - if (dev == NULL) - return -ENOMEM; - - iface = netdev_priv(dev); - memcpy(iface->u.wds.remote_addr, remote_addr, ETH_ALEN); - - local->wds_connections++; - - return 0; -} - - -int prism2_wds_del(local_info_t *local, u8 *remote_addr, - int rtnl_locked, int do_not_remove) -{ - unsigned long flags; - struct list_head *ptr; - struct hostap_interface *iface, *selected = NULL; - - write_lock_irqsave(&local->iface_lock, flags); - list_for_each(ptr, &local->hostap_interfaces) { - iface = list_entry(ptr, struct hostap_interface, list); - if (iface->type != HOSTAP_INTERFACE_WDS) - continue; - - if (ether_addr_equal(iface->u.wds.remote_addr, remote_addr)) { - selected = iface; - break; - } - } - if (selected && !do_not_remove) - list_del(&selected->list); - write_unlock_irqrestore(&local->iface_lock, flags); - - if (selected) { - if (do_not_remove) - eth_zero_addr(selected->u.wds.remote_addr); - else { - hostap_remove_interface(selected->dev, rtnl_locked, 0); - local->wds_connections--; - } - } - - return selected ? 0 : -ENODEV; -} - - -u16 hostap_tx_callback_register(local_info_t *local, - void (*func)(struct sk_buff *, int ok, void *), - void *data) -{ - unsigned long flags; - struct hostap_tx_callback_info *entry; - - entry = kmalloc(sizeof(*entry), GFP_KERNEL); - if (entry == NULL) - return 0; - - entry->func = func; - entry->data = data; - - spin_lock_irqsave(&local->lock, flags); - entry->idx = local->tx_callback ? local->tx_callback->idx + 1 : 1; - entry->next = local->tx_callback; - local->tx_callback = entry; - spin_unlock_irqrestore(&local->lock, flags); - - return entry->idx; -} - - -int hostap_tx_callback_unregister(local_info_t *local, u16 idx) -{ - unsigned long flags; - struct hostap_tx_callback_info *cb, *prev = NULL; - - spin_lock_irqsave(&local->lock, flags); - cb = local->tx_callback; - while (cb != NULL && cb->idx != idx) { - prev = cb; - cb = cb->next; - } - if (cb) { - if (prev == NULL) - local->tx_callback = cb->next; - else - prev->next = cb->next; - kfree(cb); - } - spin_unlock_irqrestore(&local->lock, flags); - - return cb ? 0 : -1; -} - - -/* val is in host byte order */ -int hostap_set_word(struct net_device *dev, int rid, u16 val) -{ - struct hostap_interface *iface; - __le16 tmp = cpu_to_le16(val); - iface = netdev_priv(dev); - return iface->local->func->set_rid(dev, rid, &tmp, 2); -} - - -int hostap_set_string(struct net_device *dev, int rid, const char *val) -{ - struct hostap_interface *iface; - char buf[MAX_SSID_LEN + 2]; - int len; - - iface = netdev_priv(dev); - len = strlen(val); - if (len > MAX_SSID_LEN) - return -1; - memset(buf, 0, sizeof(buf)); - buf[0] = len; /* little endian 16 bit word */ - memcpy(buf + 2, val, len); - - return iface->local->func->set_rid(dev, rid, &buf, MAX_SSID_LEN + 2); -} - - -u16 hostap_get_porttype(local_info_t *local) -{ - if (local->iw_mode == IW_MODE_ADHOC && local->pseudo_adhoc) - return HFA384X_PORTTYPE_PSEUDO_IBSS; - if (local->iw_mode == IW_MODE_ADHOC) - return HFA384X_PORTTYPE_IBSS; - if (local->iw_mode == IW_MODE_INFRA) - return HFA384X_PORTTYPE_BSS; - if (local->iw_mode == IW_MODE_REPEAT) - return HFA384X_PORTTYPE_WDS; - if (local->iw_mode == IW_MODE_MONITOR) - return HFA384X_PORTTYPE_PSEUDO_IBSS; - return HFA384X_PORTTYPE_HOSTAP; -} - - -int hostap_set_encryption(local_info_t *local) -{ - u16 val, old_val; - int i, keylen, len, idx; - char keybuf[WEP_KEY_LEN + 1]; - enum { NONE, WEP, OTHER } encrypt_type; - - idx = local->crypt_info.tx_keyidx; - if (local->crypt_info.crypt[idx] == NULL || - local->crypt_info.crypt[idx]->ops == NULL) - encrypt_type = NONE; - else if (strcmp(local->crypt_info.crypt[idx]->ops->name, "WEP") == 0) - encrypt_type = WEP; - else - encrypt_type = OTHER; - - if (local->func->get_rid(local->dev, HFA384X_RID_CNFWEPFLAGS, &val, 2, - 1) < 0) { - printk(KERN_DEBUG "Could not read current WEP flags.\n"); - goto fail; - } - le16_to_cpus(&val); - old_val = val; - - if (encrypt_type != NONE || local->privacy_invoked) - val |= HFA384X_WEPFLAGS_PRIVACYINVOKED; - else - val &= ~HFA384X_WEPFLAGS_PRIVACYINVOKED; - - if (local->open_wep || encrypt_type == NONE || - ((local->ieee_802_1x || local->wpa) && local->host_decrypt)) - val &= ~HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED; - else - val |= HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED; - - if ((encrypt_type != NONE || local->privacy_invoked) && - (encrypt_type == OTHER || local->host_encrypt)) - val |= HFA384X_WEPFLAGS_HOSTENCRYPT; - else - val &= ~HFA384X_WEPFLAGS_HOSTENCRYPT; - if ((encrypt_type != NONE || local->privacy_invoked) && - (encrypt_type == OTHER || local->host_decrypt)) - val |= HFA384X_WEPFLAGS_HOSTDECRYPT; - else - val &= ~HFA384X_WEPFLAGS_HOSTDECRYPT; - - if (val != old_val && - hostap_set_word(local->dev, HFA384X_RID_CNFWEPFLAGS, val)) { - printk(KERN_DEBUG "Could not write new WEP flags (0x%x)\n", - val); - goto fail; - } - - if (encrypt_type != WEP) - return 0; - - /* 104-bit support seems to require that all the keys are set to the - * same keylen */ - keylen = 6; /* first 5 octets */ - len = local->crypt_info.crypt[idx]->ops->get_key(keybuf, sizeof(keybuf), NULL, - local->crypt_info.crypt[idx]->priv); - if (idx >= 0 && idx < WEP_KEYS && len > 5) - keylen = WEP_KEY_LEN + 1; /* first 13 octets */ - - for (i = 0; i < WEP_KEYS; i++) { - memset(keybuf, 0, sizeof(keybuf)); - if (local->crypt_info.crypt[i]) { - (void) local->crypt_info.crypt[i]->ops->get_key( - keybuf, sizeof(keybuf), - NULL, local->crypt_info.crypt[i]->priv); - } - if (local->func->set_rid(local->dev, - HFA384X_RID_CNFDEFAULTKEY0 + i, - keybuf, keylen)) { - printk(KERN_DEBUG "Could not set key %d (len=%d)\n", - i, keylen); - goto fail; - } - } - if (hostap_set_word(local->dev, HFA384X_RID_CNFWEPDEFAULTKEYID, idx)) { - printk(KERN_DEBUG "Could not set default keyid %d\n", idx); - goto fail; - } - - return 0; - - fail: - printk(KERN_DEBUG "%s: encryption setup failed\n", local->dev->name); - return -1; -} - - -int hostap_set_antsel(local_info_t *local) -{ - u16 val; - int ret = 0; - - if (local->antsel_tx != HOSTAP_ANTSEL_DO_NOT_TOUCH && - local->func->cmd(local->dev, HFA384X_CMDCODE_READMIF, - HFA386X_CR_TX_CONFIGURE, - NULL, &val) == 0) { - val &= ~(BIT(2) | BIT(1)); - switch (local->antsel_tx) { - case HOSTAP_ANTSEL_DIVERSITY: - val |= BIT(1); - break; - case HOSTAP_ANTSEL_LOW: - break; - case HOSTAP_ANTSEL_HIGH: - val |= BIT(2); - break; - } - - if (local->func->cmd(local->dev, HFA384X_CMDCODE_WRITEMIF, - HFA386X_CR_TX_CONFIGURE, &val, NULL)) { - printk(KERN_INFO "%s: setting TX AntSel failed\n", - local->dev->name); - ret = -1; - } - } - - if (local->antsel_rx != HOSTAP_ANTSEL_DO_NOT_TOUCH && - local->func->cmd(local->dev, HFA384X_CMDCODE_READMIF, - HFA386X_CR_RX_CONFIGURE, - NULL, &val) == 0) { - val &= ~(BIT(1) | BIT(0)); - switch (local->antsel_rx) { - case HOSTAP_ANTSEL_DIVERSITY: - break; - case HOSTAP_ANTSEL_LOW: - val |= BIT(0); - break; - case HOSTAP_ANTSEL_HIGH: - val |= BIT(0) | BIT(1); - break; - } - - if (local->func->cmd(local->dev, HFA384X_CMDCODE_WRITEMIF, - HFA386X_CR_RX_CONFIGURE, &val, NULL)) { - printk(KERN_INFO "%s: setting RX AntSel failed\n", - local->dev->name); - ret = -1; - } - } - - return ret; -} - - -int hostap_set_roaming(local_info_t *local) -{ - u16 val; - - switch (local->host_roaming) { - case 1: - val = HFA384X_ROAMING_HOST; - break; - case 2: - val = HFA384X_ROAMING_DISABLED; - break; - case 0: - default: - val = HFA384X_ROAMING_FIRMWARE; - break; - } - - return hostap_set_word(local->dev, HFA384X_RID_CNFROAMINGMODE, val); -} - - -int hostap_set_auth_algs(local_info_t *local) -{ - int val = local->auth_algs; - /* At least STA f/w v0.6.2 seems to have issues with cnfAuthentication - * set to include both Open and Shared Key flags. It tries to use - * Shared Key authentication in that case even if WEP keys are not - * configured.. STA f/w v0.7.6 is able to handle such configuration, - * but it is unknown when this was fixed between 0.6.2 .. 0.7.6. */ - if (local->sta_fw_ver < PRISM2_FW_VER(0,7,0) && - val != PRISM2_AUTH_OPEN && val != PRISM2_AUTH_SHARED_KEY) - val = PRISM2_AUTH_OPEN; - - if (hostap_set_word(local->dev, HFA384X_RID_CNFAUTHENTICATION, val)) { - printk(KERN_INFO "%s: cnfAuthentication setting to 0x%x " - "failed\n", local->dev->name, local->auth_algs); - return -EINVAL; - } - - return 0; -} - - -void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx) -{ - u16 status, fc; - - status = __le16_to_cpu(rx->status); - - printk(KERN_DEBUG "%s: RX status=0x%04x (port=%d, type=%d, " - "fcserr=%d) silence=%d signal=%d rate=%d rxflow=%d; " - "jiffies=%ld\n", - name, status, (status >> 8) & 0x07, status >> 13, status & 1, - rx->silence, rx->signal, rx->rate, rx->rxflow, jiffies); - - fc = __le16_to_cpu(rx->frame_control); - printk(KERN_DEBUG " FC=0x%04x (type=%d:%d) dur=0x%04x seq=0x%04x " - "data_len=%d%s%s\n", - fc, (fc & IEEE80211_FCTL_FTYPE) >> 2, - (fc & IEEE80211_FCTL_STYPE) >> 4, - __le16_to_cpu(rx->duration_id), __le16_to_cpu(rx->seq_ctrl), - __le16_to_cpu(rx->data_len), - fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", - fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); - - printk(KERN_DEBUG " A1=%pM A2=%pM A3=%pM A4=%pM\n", - rx->addr1, rx->addr2, rx->addr3, rx->addr4); - - printk(KERN_DEBUG " dst=%pM src=%pM len=%d\n", - rx->dst_addr, rx->src_addr, - __be16_to_cpu(rx->len)); -} - - -void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx) -{ - u16 fc; - - printk(KERN_DEBUG "%s: TX status=0x%04x retry_count=%d tx_rate=%d " - "tx_control=0x%04x; jiffies=%ld\n", - name, __le16_to_cpu(tx->status), tx->retry_count, tx->tx_rate, - __le16_to_cpu(tx->tx_control), jiffies); - - fc = __le16_to_cpu(tx->frame_control); - printk(KERN_DEBUG " FC=0x%04x (type=%d:%d) dur=0x%04x seq=0x%04x " - "data_len=%d%s%s\n", - fc, (fc & IEEE80211_FCTL_FTYPE) >> 2, - (fc & IEEE80211_FCTL_STYPE) >> 4, - __le16_to_cpu(tx->duration_id), __le16_to_cpu(tx->seq_ctrl), - __le16_to_cpu(tx->data_len), - fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", - fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); - - printk(KERN_DEBUG " A1=%pM A2=%pM A3=%pM A4=%pM\n", - tx->addr1, tx->addr2, tx->addr3, tx->addr4); - - printk(KERN_DEBUG " dst=%pM src=%pM len=%d\n", - tx->dst_addr, tx->src_addr, - __be16_to_cpu(tx->len)); -} - - -static int hostap_80211_header_parse(const struct sk_buff *skb, - unsigned char *haddr) -{ - memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */ - return ETH_ALEN; -} - - -int hostap_80211_get_hdrlen(__le16 fc) -{ - if (ieee80211_is_data(fc) && ieee80211_has_a4 (fc)) - return 30; /* Addr4 */ - else if (ieee80211_is_cts(fc) || ieee80211_is_ack(fc)) - return 10; - else if (ieee80211_is_ctl(fc)) - return 16; - - return 24; -} - - -static int prism2_close(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - - PDEBUG(DEBUG_FLOW, "%s: prism2_close\n", dev->name); - - iface = netdev_priv(dev); - local = iface->local; - - if (dev == local->ddev) { - prism2_sta_deauth(local, WLAN_REASON_DEAUTH_LEAVING); - } -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - if (!local->hostapd && dev == local->dev && - (!local->func->card_present || local->func->card_present(local)) && - local->hw_ready && local->ap && local->iw_mode == IW_MODE_MASTER) - hostap_deauth_all_stas(dev, local->ap, 1); -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - if (dev == local->dev) { - local->func->hw_shutdown(dev, HOSTAP_HW_ENABLE_CMDCOMPL); - } - - if (netif_running(dev)) { - netif_stop_queue(dev); - netif_device_detach(dev); - } - - cancel_work_sync(&local->reset_queue); - cancel_work_sync(&local->set_multicast_list_queue); - cancel_work_sync(&local->set_tim_queue); -#ifndef PRISM2_NO_STATION_MODES - cancel_work_sync(&local->info_queue); -#endif - cancel_work_sync(&local->comms_qual_update); - - module_put(local->hw_module); - - local->num_dev_open--; - - if (dev != local->dev && local->dev->flags & IFF_UP && - local->master_dev_auto_open && local->num_dev_open == 1) { - /* Close master radio interface automatically if it was also - * opened automatically and we are now closing the last - * remaining non-master device. */ - dev_close(local->dev); - } - - return 0; -} - - -static int prism2_open(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - - PDEBUG(DEBUG_FLOW, "%s: prism2_open\n", dev->name); - - iface = netdev_priv(dev); - local = iface->local; - - if (local->no_pri) { - printk(KERN_DEBUG "%s: could not set interface UP - no PRI " - "f/w\n", dev->name); - return -ENODEV; - } - - if ((local->func->card_present && !local->func->card_present(local)) || - local->hw_downloading) - return -ENODEV; - - if (!try_module_get(local->hw_module)) - return -ENODEV; - local->num_dev_open++; - - if (!local->dev_enabled && local->func->hw_enable(dev, 1)) { - printk(KERN_WARNING "%s: could not enable MAC port\n", - dev->name); - prism2_close(dev); - return -ENODEV; - } - if (!local->dev_enabled) - prism2_callback(local, PRISM2_CALLBACK_ENABLE); - local->dev_enabled = 1; - - if (dev != local->dev && !(local->dev->flags & IFF_UP)) { - /* Master radio interface is needed for all operation, so open - * it automatically when any virtual net_device is opened. */ - local->master_dev_auto_open = 1; - dev_open(local->dev, NULL); - } - - netif_device_attach(dev); - netif_start_queue(dev); - - return 0; -} - - -static int prism2_set_mac_address(struct net_device *dev, void *p) -{ - struct hostap_interface *iface; - local_info_t *local; - struct list_head *ptr; - struct sockaddr *addr = p; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->func->set_rid(dev, HFA384X_RID_CNFOWNMACADDR, addr->sa_data, - ETH_ALEN) < 0 || local->func->reset_port(dev)) - return -EINVAL; - - read_lock_bh(&local->iface_lock); - list_for_each(ptr, &local->hostap_interfaces) { - iface = list_entry(ptr, struct hostap_interface, list); - eth_hw_addr_set(iface->dev, addr->sa_data); - } - eth_hw_addr_set(local->dev, addr->sa_data); - read_unlock_bh(&local->iface_lock); - - return 0; -} - - -/* TODO: to be further implemented as soon as Prism2 fully supports - * GroupAddresses and correct documentation is available */ -void hostap_set_multicast_list_queue(struct work_struct *work) -{ - local_info_t *local = - container_of(work, local_info_t, set_multicast_list_queue); - struct net_device *dev = local->dev; - - if (hostap_set_word(dev, HFA384X_RID_PROMISCUOUSMODE, - local->is_promisc)) { - printk(KERN_INFO "%s: %sabling promiscuous mode failed\n", - dev->name, local->is_promisc ? "en" : "dis"); - } -} - - -static void hostap_set_multicast_list(struct net_device *dev) -{ -#if 0 - /* FIX: promiscuous mode seems to be causing a lot of problems with - * some station firmware versions (FCSErr frames, invalid MACPort, etc. - * corrupted incoming frames). This code is now commented out while the - * problems are investigated. */ - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - if ((dev->flags & IFF_ALLMULTI) || (dev->flags & IFF_PROMISC)) { - local->is_promisc = 1; - } else { - local->is_promisc = 0; - } - - schedule_work(&local->set_multicast_list_queue); -#endif -} - - -static void prism2_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - struct hostap_interface *iface; - local_info_t *local; - struct hfa384x_regs regs; - - iface = netdev_priv(dev); - local = iface->local; - - printk(KERN_WARNING "%s Tx timed out! Resetting card\n", dev->name); - netif_stop_queue(local->dev); - - local->func->read_regs(dev, ®s); - printk(KERN_DEBUG "%s: CMD=%04x EVSTAT=%04x " - "OFFSET0=%04x OFFSET1=%04x SWSUPPORT0=%04x\n", - dev->name, regs.cmd, regs.evstat, regs.offset0, regs.offset1, - regs.swsupport0); - - local->func->schedule_reset(local); -} - -const struct header_ops hostap_80211_ops = { - .create = eth_header, - .cache = eth_header_cache, - .cache_update = eth_header_cache_update, - .parse = hostap_80211_header_parse, -}; -EXPORT_SYMBOL(hostap_80211_ops); - - -static const struct net_device_ops hostap_netdev_ops = { - .ndo_start_xmit = hostap_data_start_xmit, - - .ndo_open = prism2_open, - .ndo_stop = prism2_close, - .ndo_siocdevprivate = hostap_siocdevprivate, - .ndo_set_mac_address = prism2_set_mac_address, - .ndo_set_rx_mode = hostap_set_multicast_list, - .ndo_tx_timeout = prism2_tx_timeout, - .ndo_validate_addr = eth_validate_addr, -}; - -static const struct net_device_ops hostap_mgmt_netdev_ops = { - .ndo_start_xmit = hostap_mgmt_start_xmit, - - .ndo_open = prism2_open, - .ndo_stop = prism2_close, - .ndo_siocdevprivate = hostap_siocdevprivate, - .ndo_set_mac_address = prism2_set_mac_address, - .ndo_set_rx_mode = hostap_set_multicast_list, - .ndo_tx_timeout = prism2_tx_timeout, - .ndo_validate_addr = eth_validate_addr, -}; - -static const struct net_device_ops hostap_master_ops = { - .ndo_start_xmit = hostap_master_start_xmit, - - .ndo_open = prism2_open, - .ndo_stop = prism2_close, - .ndo_siocdevprivate = hostap_siocdevprivate, - .ndo_set_mac_address = prism2_set_mac_address, - .ndo_set_rx_mode = hostap_set_multicast_list, - .ndo_tx_timeout = prism2_tx_timeout, - .ndo_validate_addr = eth_validate_addr, -}; - -void hostap_setup_dev(struct net_device *dev, local_info_t *local, - int type) -{ - struct hostap_interface *iface; - - iface = netdev_priv(dev); - ether_setup(dev); - dev->min_mtu = PRISM2_MIN_MTU; - dev->max_mtu = PRISM2_MAX_MTU; - dev->priv_flags &= ~IFF_TX_SKB_SHARING; - - /* kernel callbacks */ - if (iface) { - /* Currently, we point to the proper spy_data only on - * the main_dev. This could be fixed. Jean II */ - iface->wireless_data.spy_data = &iface->spy_data; - dev->wireless_data = &iface->wireless_data; - } - dev->wireless_handlers = &hostap_iw_handler_def; - dev->watchdog_timeo = TX_TIMEOUT; - - switch(type) { - case HOSTAP_INTERFACE_AP: - dev->priv_flags |= IFF_NO_QUEUE; /* use main radio device queue */ - dev->netdev_ops = &hostap_mgmt_netdev_ops; - dev->type = ARPHRD_IEEE80211; - dev->header_ops = &hostap_80211_ops; - break; - case HOSTAP_INTERFACE_MASTER: - dev->netdev_ops = &hostap_master_ops; - break; - default: - dev->priv_flags |= IFF_NO_QUEUE; /* use main radio device queue */ - dev->netdev_ops = &hostap_netdev_ops; - } - - dev->mtu = local->mtu; - - - dev->ethtool_ops = &prism2_ethtool_ops; - -} - -static int hostap_enable_hostapd(local_info_t *local, int rtnl_locked) -{ - struct net_device *dev = local->dev; - - if (local->apdev) - return -EEXIST; - - printk(KERN_DEBUG "%s: enabling hostapd mode\n", dev->name); - - local->apdev = hostap_add_interface(local, HOSTAP_INTERFACE_AP, - rtnl_locked, local->ddev->name, - "ap"); - if (local->apdev == NULL) - return -ENOMEM; - - return 0; -} - - -static int hostap_disable_hostapd(local_info_t *local, int rtnl_locked) -{ - struct net_device *dev = local->dev; - - printk(KERN_DEBUG "%s: disabling hostapd mode\n", dev->name); - - hostap_remove_interface(local->apdev, rtnl_locked, 1); - local->apdev = NULL; - - return 0; -} - - -static int hostap_enable_hostapd_sta(local_info_t *local, int rtnl_locked) -{ - struct net_device *dev = local->dev; - - if (local->stadev) - return -EEXIST; - - printk(KERN_DEBUG "%s: enabling hostapd STA mode\n", dev->name); - - local->stadev = hostap_add_interface(local, HOSTAP_INTERFACE_STA, - rtnl_locked, local->ddev->name, - "sta"); - if (local->stadev == NULL) - return -ENOMEM; - - return 0; -} - - -static int hostap_disable_hostapd_sta(local_info_t *local, int rtnl_locked) -{ - struct net_device *dev = local->dev; - - printk(KERN_DEBUG "%s: disabling hostapd mode\n", dev->name); - - hostap_remove_interface(local->stadev, rtnl_locked, 1); - local->stadev = NULL; - - return 0; -} - - -int hostap_set_hostapd(local_info_t *local, int val, int rtnl_locked) -{ - int ret; - - if (val < 0 || val > 1) - return -EINVAL; - - if (local->hostapd == val) - return 0; - - if (val) { - ret = hostap_enable_hostapd(local, rtnl_locked); - if (ret == 0) - local->hostapd = 1; - } else { - local->hostapd = 0; - ret = hostap_disable_hostapd(local, rtnl_locked); - if (ret != 0) - local->hostapd = 1; - } - - return ret; -} - - -int hostap_set_hostapd_sta(local_info_t *local, int val, int rtnl_locked) -{ - int ret; - - if (val < 0 || val > 1) - return -EINVAL; - - if (local->hostapd_sta == val) - return 0; - - if (val) { - ret = hostap_enable_hostapd_sta(local, rtnl_locked); - if (ret == 0) - local->hostapd_sta = 1; - } else { - local->hostapd_sta = 0; - ret = hostap_disable_hostapd_sta(local, rtnl_locked); - if (ret != 0) - local->hostapd_sta = 1; - } - - - return ret; -} - - -int prism2_update_comms_qual(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - int ret = 0; - struct hfa384x_comms_quality sq; - - iface = netdev_priv(dev); - local = iface->local; - if (!local->sta_fw_ver) - ret = -1; - else if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1)) { - if (local->func->get_rid(local->dev, - HFA384X_RID_DBMCOMMSQUALITY, - &sq, sizeof(sq), 1) >= 0) { - local->comms_qual = (s16) le16_to_cpu(sq.comm_qual); - local->avg_signal = (s16) le16_to_cpu(sq.signal_level); - local->avg_noise = (s16) le16_to_cpu(sq.noise_level); - local->last_comms_qual_update = jiffies; - } else - ret = -1; - } else { - if (local->func->get_rid(local->dev, HFA384X_RID_COMMSQUALITY, - &sq, sizeof(sq), 1) >= 0) { - local->comms_qual = le16_to_cpu(sq.comm_qual); - local->avg_signal = HFA384X_LEVEL_TO_dBm( - le16_to_cpu(sq.signal_level)); - local->avg_noise = HFA384X_LEVEL_TO_dBm( - le16_to_cpu(sq.noise_level)); - local->last_comms_qual_update = jiffies; - } else - ret = -1; - } - - return ret; -} - - -int prism2_sta_send_mgmt(local_info_t *local, u8 *dst, u16 stype, - u8 *body, size_t bodylen) -{ - struct sk_buff *skb; - struct hostap_ieee80211_mgmt *mgmt; - struct hostap_skb_tx_data *meta; - struct net_device *dev = local->dev; - - skb = dev_alloc_skb(IEEE80211_MGMT_HDR_LEN + bodylen); - if (skb == NULL) - return -ENOMEM; - - mgmt = skb_put_zero(skb, IEEE80211_MGMT_HDR_LEN); - mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); - memcpy(mgmt->da, dst, ETH_ALEN); - memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); - memcpy(mgmt->bssid, dst, ETH_ALEN); - if (body) - skb_put_data(skb, body, bodylen); - - meta = (struct hostap_skb_tx_data *) skb->cb; - memset(meta, 0, sizeof(*meta)); - meta->magic = HOSTAP_SKB_TX_DATA_MAGIC; - meta->iface = netdev_priv(dev); - - skb->dev = dev; - skb_reset_mac_header(skb); - skb_reset_network_header(skb); - dev_queue_xmit(skb); - - return 0; -} - - -int prism2_sta_deauth(local_info_t *local, u16 reason) -{ - union iwreq_data wrqu; - int ret; - __le16 val = cpu_to_le16(reason); - - if (local->iw_mode != IW_MODE_INFRA || - is_zero_ether_addr(local->bssid) || - ether_addr_equal(local->bssid, "\x44\x44\x44\x44\x44\x44")) - return 0; - - ret = prism2_sta_send_mgmt(local, local->bssid, IEEE80211_STYPE_DEAUTH, - (u8 *) &val, 2); - eth_zero_addr(wrqu.ap_addr.sa_data); - wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL); - return ret; -} - - -struct proc_dir_entry *hostap_proc; - -static int __init hostap_init(void) -{ - if (init_net.proc_net != NULL) { - hostap_proc = proc_mkdir("hostap", init_net.proc_net); - if (!hostap_proc) - printk(KERN_WARNING "Failed to mkdir " - "/proc/net/hostap\n"); - } else - hostap_proc = NULL; - - return 0; -} - - -static void __exit hostap_exit(void) -{ - if (hostap_proc != NULL) { - hostap_proc = NULL; - remove_proc_entry("hostap", init_net.proc_net); - } -} - - -EXPORT_SYMBOL(hostap_set_word); -EXPORT_SYMBOL(hostap_set_string); -EXPORT_SYMBOL(hostap_get_porttype); -EXPORT_SYMBOL(hostap_set_encryption); -EXPORT_SYMBOL(hostap_set_antsel); -EXPORT_SYMBOL(hostap_set_roaming); -EXPORT_SYMBOL(hostap_set_auth_algs); -EXPORT_SYMBOL(hostap_dump_rx_header); -EXPORT_SYMBOL(hostap_dump_tx_header); -EXPORT_SYMBOL(hostap_80211_get_hdrlen); -EXPORT_SYMBOL(hostap_setup_dev); -EXPORT_SYMBOL(hostap_set_multicast_list_queue); -EXPORT_SYMBOL(hostap_set_hostapd); -EXPORT_SYMBOL(hostap_set_hostapd_sta); -EXPORT_SYMBOL(hostap_add_interface); -EXPORT_SYMBOL(hostap_remove_interface); -EXPORT_SYMBOL(prism2_update_comms_qual); - -module_init(hostap_init); -module_exit(hostap_exit); diff --git a/drivers/net/wireless/intersil/hostap/hostap_pci.c b/drivers/net/wireless/intersil/hostap/hostap_pci.c deleted file mode 100644 index 52d77506effd2..0000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_pci.c +++ /dev/null @@ -1,445 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -#define PRISM2_PCI - -/* Host AP driver's support for Intersil Prism2.5 PCI cards is based on - * driver patches from Reyk Floeter and - * Andy Warner */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "hostap_wlan.h" - - -static char *dev_info = "hostap_pci"; - - -MODULE_AUTHOR("Jouni Malinen"); -MODULE_DESCRIPTION("Support for Intersil Prism2.5-based 802.11 wireless LAN " - "PCI cards."); -MODULE_LICENSE("GPL"); - - -/* struct local_info::hw_priv */ -struct hostap_pci_priv { - void __iomem *mem_start; -}; - - -/* FIX: do we need mb/wmb/rmb with memory operations? */ - - -static const struct pci_device_id prism2_pci_id_table[] = { - /* Intersil Prism3 ISL3872 11Mb/s WLAN Controller */ - { 0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID }, - /* Intersil Prism2.5 ISL3874 11Mb/s WLAN Controller */ - { 0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID }, - /* Samsung MagicLAN SWL-2210P */ - { 0x167d, 0xa000, PCI_ANY_ID, PCI_ANY_ID }, - { 0 } -}; - - -#ifdef PRISM2_IO_DEBUG - -static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v) -{ - struct hostap_interface *iface; - struct hostap_pci_priv *hw_priv; - local_info_t *local; - unsigned long flags; - - iface = netdev_priv(dev); - local = iface->local; - hw_priv = local->hw_priv; - - spin_lock_irqsave(&local->lock, flags); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v); - writeb(v, hw_priv->mem_start + a); - spin_unlock_irqrestore(&local->lock, flags); -} - -static inline u8 hfa384x_inb_debug(struct net_device *dev, int a) -{ - struct hostap_interface *iface; - struct hostap_pci_priv *hw_priv; - local_info_t *local; - unsigned long flags; - u8 v; - - iface = netdev_priv(dev); - local = iface->local; - hw_priv = local->hw_priv; - - spin_lock_irqsave(&local->lock, flags); - v = readb(hw_priv->mem_start + a); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v); - spin_unlock_irqrestore(&local->lock, flags); - return v; -} - -static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v) -{ - struct hostap_interface *iface; - struct hostap_pci_priv *hw_priv; - local_info_t *local; - unsigned long flags; - - iface = netdev_priv(dev); - local = iface->local; - hw_priv = local->hw_priv; - - spin_lock_irqsave(&local->lock, flags); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v); - writew(v, hw_priv->mem_start + a); - spin_unlock_irqrestore(&local->lock, flags); -} - -static inline u16 hfa384x_inw_debug(struct net_device *dev, int a) -{ - struct hostap_interface *iface; - struct hostap_pci_priv *hw_priv; - local_info_t *local; - unsigned long flags; - u16 v; - - iface = netdev_priv(dev); - local = iface->local; - hw_priv = local->hw_priv; - - spin_lock_irqsave(&local->lock, flags); - v = readw(hw_priv->mem_start + a); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v); - spin_unlock_irqrestore(&local->lock, flags); - return v; -} - -#define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v)) -#define HFA384X_INB(a) hfa384x_inb_debug(dev, (a)) -#define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v)) -#define HFA384X_INW(a) hfa384x_inw_debug(dev, (a)) -#define HFA384X_OUTW_DATA(v,a) hfa384x_outw_debug(dev, (a), le16_to_cpu((v))) -#define HFA384X_INW_DATA(a) cpu_to_le16(hfa384x_inw_debug(dev, (a))) - -#else /* PRISM2_IO_DEBUG */ - -static inline void hfa384x_outb(struct net_device *dev, int a, u8 v) -{ - struct hostap_interface *iface; - struct hostap_pci_priv *hw_priv; - iface = netdev_priv(dev); - hw_priv = iface->local->hw_priv; - writeb(v, hw_priv->mem_start + a); -} - -static inline u8 hfa384x_inb(struct net_device *dev, int a) -{ - struct hostap_interface *iface; - struct hostap_pci_priv *hw_priv; - iface = netdev_priv(dev); - hw_priv = iface->local->hw_priv; - return readb(hw_priv->mem_start + a); -} - -static inline void hfa384x_outw(struct net_device *dev, int a, u16 v) -{ - struct hostap_interface *iface; - struct hostap_pci_priv *hw_priv; - iface = netdev_priv(dev); - hw_priv = iface->local->hw_priv; - writew(v, hw_priv->mem_start + a); -} - -static inline u16 hfa384x_inw(struct net_device *dev, int a) -{ - struct hostap_interface *iface; - struct hostap_pci_priv *hw_priv; - iface = netdev_priv(dev); - hw_priv = iface->local->hw_priv; - return readw(hw_priv->mem_start + a); -} - -#define HFA384X_OUTB(v,a) hfa384x_outb(dev, (a), (v)) -#define HFA384X_INB(a) hfa384x_inb(dev, (a)) -#define HFA384X_OUTW(v,a) hfa384x_outw(dev, (a), (v)) -#define HFA384X_INW(a) hfa384x_inw(dev, (a)) -#define HFA384X_OUTW_DATA(v,a) hfa384x_outw(dev, (a), le16_to_cpu((v))) -#define HFA384X_INW_DATA(a) cpu_to_le16(hfa384x_inw(dev, (a))) - -#endif /* PRISM2_IO_DEBUG */ - - -static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf, - int len) -{ - u16 d_off; - __le16 *pos; - - d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; - pos = (__le16 *) buf; - - for ( ; len > 1; len -= 2) - *pos++ = HFA384X_INW_DATA(d_off); - - if (len & 1) - *((char *) pos) = HFA384X_INB(d_off); - - return 0; -} - - -static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len) -{ - u16 d_off; - __le16 *pos; - - d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; - pos = (__le16 *) buf; - - for ( ; len > 1; len -= 2) - HFA384X_OUTW_DATA(*pos++, d_off); - - if (len & 1) - HFA384X_OUTB(*((char *) pos), d_off); - - return 0; -} - - -/* FIX: This might change at some point.. */ -#include "hostap_hw.c" - -static void prism2_pci_cor_sreset(local_info_t *local) -{ - struct net_device *dev = local->dev; - u16 reg; - - reg = HFA384X_INB(HFA384X_PCICOR_OFF); - printk(KERN_DEBUG "%s: Original COR value: 0x%0x\n", dev->name, reg); - - /* linux-wlan-ng uses extremely long hold and settle times for - * COR sreset. A comment in the driver code mentions that the long - * delays appear to be necessary. However, at least IBM 22P6901 seems - * to work fine with shorter delays. - * - * Longer delays can be configured by uncommenting following line: */ -/* #define PRISM2_PCI_USE_LONG_DELAYS */ - -#ifdef PRISM2_PCI_USE_LONG_DELAYS - int i; - - HFA384X_OUTW(reg | 0x0080, HFA384X_PCICOR_OFF); - mdelay(250); - - HFA384X_OUTW(reg & ~0x0080, HFA384X_PCICOR_OFF); - mdelay(500); - - /* Wait for f/w to complete initialization (CMD:BUSY == 0) */ - i = 2000000 / 10; - while ((HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) && --i) - udelay(10); - -#else /* PRISM2_PCI_USE_LONG_DELAYS */ - - HFA384X_OUTW(reg | 0x0080, HFA384X_PCICOR_OFF); - mdelay(2); - HFA384X_OUTW(reg & ~0x0080, HFA384X_PCICOR_OFF); - mdelay(2); - -#endif /* PRISM2_PCI_USE_LONG_DELAYS */ - - if (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) { - printk(KERN_DEBUG "%s: COR sreset timeout\n", dev->name); - } -} - - -static void prism2_pci_genesis_reset(local_info_t *local, int hcr) -{ - struct net_device *dev = local->dev; - - HFA384X_OUTW(0x00C5, HFA384X_PCICOR_OFF); - mdelay(10); - HFA384X_OUTW(hcr, HFA384X_PCIHCR_OFF); - mdelay(10); - HFA384X_OUTW(0x0045, HFA384X_PCICOR_OFF); - mdelay(10); -} - - -static struct prism2_helper_functions prism2_pci_funcs = -{ - .card_present = NULL, - .cor_sreset = prism2_pci_cor_sreset, - .genesis_reset = prism2_pci_genesis_reset, - .hw_type = HOSTAP_HW_PCI, -}; - - -static int prism2_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - unsigned long phymem; - void __iomem *mem = NULL; - local_info_t *local = NULL; - struct net_device *dev = NULL; - static int cards_found /* = 0 */; - int irq_registered = 0; - struct hostap_interface *iface; - struct hostap_pci_priv *hw_priv; - - hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL); - if (hw_priv == NULL) - return -ENOMEM; - - if (pci_enable_device(pdev)) - goto err_out_free; - - phymem = pci_resource_start(pdev, 0); - - if (!request_mem_region(phymem, pci_resource_len(pdev, 0), "Prism2")) { - printk(KERN_ERR "prism2: Cannot reserve PCI memory region\n"); - goto err_out_disable; - } - - mem = pci_ioremap_bar(pdev, 0); - if (mem == NULL) { - printk(KERN_ERR "prism2: Cannot remap PCI memory region\n") ; - goto fail; - } - - dev = prism2_init_local_data(&prism2_pci_funcs, cards_found, - &pdev->dev); - if (dev == NULL) - goto fail; - iface = netdev_priv(dev); - local = iface->local; - local->hw_priv = hw_priv; - cards_found++; - - dev->irq = pdev->irq; - hw_priv->mem_start = mem; - dev->base_addr = (unsigned long) mem; - - prism2_pci_cor_sreset(local); - - pci_set_drvdata(pdev, dev); - - if (request_irq(dev->irq, prism2_interrupt, IRQF_SHARED, dev->name, - dev)) { - printk(KERN_WARNING "%s: request_irq failed\n", dev->name); - goto fail; - } else - irq_registered = 1; - - if (!local->pri_only && prism2_hw_config(dev, 1)) { - printk(KERN_DEBUG "%s: hardware initialization failed\n", - dev_info); - goto fail; - } - - printk(KERN_INFO "%s: Intersil Prism2.5 PCI: " - "mem=0x%lx, irq=%d\n", dev->name, phymem, dev->irq); - - return hostap_hw_ready(dev); - - fail: - if (irq_registered && dev) - free_irq(dev->irq, dev); - - if (mem) - iounmap(mem); - - release_mem_region(phymem, pci_resource_len(pdev, 0)); - - err_out_disable: - pci_disable_device(pdev); - prism2_free_local_data(dev); - - err_out_free: - kfree(hw_priv); - - return -ENODEV; -} - - -static void prism2_pci_remove(struct pci_dev *pdev) -{ - struct net_device *dev; - struct hostap_interface *iface; - void __iomem *mem_start; - struct hostap_pci_priv *hw_priv; - - dev = pci_get_drvdata(pdev); - iface = netdev_priv(dev); - hw_priv = iface->local->hw_priv; - - /* Reset the hardware, and ensure interrupts are disabled. */ - prism2_pci_cor_sreset(iface->local); - hfa384x_disable_interrupts(dev); - - if (dev->irq) - free_irq(dev->irq, dev); - - mem_start = hw_priv->mem_start; - prism2_free_local_data(dev); - kfree(hw_priv); - - iounmap(mem_start); - - release_mem_region(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); - pci_disable_device(pdev); -} - -static int __maybe_unused prism2_pci_suspend(struct device *dev_d) -{ - struct net_device *dev = dev_get_drvdata(dev_d); - - if (netif_running(dev)) { - netif_stop_queue(dev); - netif_device_detach(dev); - } - prism2_suspend(dev); - - return 0; -} - -static int __maybe_unused prism2_pci_resume(struct device *dev_d) -{ - struct net_device *dev = dev_get_drvdata(dev_d); - - prism2_hw_config(dev, 0); - if (netif_running(dev)) { - netif_device_attach(dev); - netif_start_queue(dev); - } - - return 0; -} - -MODULE_DEVICE_TABLE(pci, prism2_pci_id_table); - -static SIMPLE_DEV_PM_OPS(prism2_pci_pm_ops, - prism2_pci_suspend, - prism2_pci_resume); - -static struct pci_driver prism2_pci_driver = { - .name = "hostap_pci", - .id_table = prism2_pci_id_table, - .probe = prism2_pci_probe, - .remove = prism2_pci_remove, - .driver.pm = &prism2_pci_pm_ops, -}; - -module_pci_driver(prism2_pci_driver); diff --git a/drivers/net/wireless/intersil/hostap/hostap_plx.c b/drivers/net/wireless/intersil/hostap/hostap_plx.c deleted file mode 100644 index 58247290fcbc4..0000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_plx.c +++ /dev/null @@ -1,617 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -#define PRISM2_PLX - -/* Host AP driver's support for PC Cards on PCI adapters using PLX9052 is - * based on: - * - Host AP driver patch from james@madingley.org - * - linux-wlan-ng driver, Copyright (C) AbsoluteValue Systems, Inc. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "hostap_wlan.h" - - -static char *dev_info = "hostap_plx"; - - -MODULE_AUTHOR("Jouni Malinen"); -MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN " - "cards (PLX)."); -MODULE_LICENSE("GPL"); - - -static int ignore_cis; -module_param(ignore_cis, int, 0444); -MODULE_PARM_DESC(ignore_cis, "Do not verify manfid information in CIS"); - - -/* struct local_info::hw_priv */ -struct hostap_plx_priv { - void __iomem *attr_mem; - unsigned int cor_offset; -}; - - -#define PLX_MIN_ATTR_LEN 512 /* at least 2 x 256 is needed for CIS */ -#define COR_SRESET 0x80 -#define COR_LEVLREQ 0x40 -#define COR_ENABLE_FUNC 0x01 -/* PCI Configuration Registers */ -#define PLX_PCIIPR 0x3d /* PCI Interrupt Pin */ -/* Local Configuration Registers */ -#define PLX_INTCSR 0x4c /* Interrupt Control/Status Register */ -#define PLX_INTCSR_PCI_INTEN BIT(6) /* PCI Interrupt Enable */ -#define PLX_CNTRL 0x50 -#define PLX_CNTRL_SERIAL_EEPROM_PRESENT BIT(28) - - -#define PLXDEV(vendor,dev,str) { vendor, dev, PCI_ANY_ID, PCI_ANY_ID } - -static const struct pci_device_id prism2_plx_id_table[] = { - PLXDEV(0x10b7, 0x7770, "3Com AirConnect PCI 777A"), - PLXDEV(0x111a, 0x1023, "Siemens SpeedStream SS1023"), - PLXDEV(0x126c, 0x8030, "Nortel emobility"), - PLXDEV(0x1562, 0x0001, "Symbol LA-4123"), - PLXDEV(0x1385, 0x4100, "Netgear MA301"), - PLXDEV(0x15e8, 0x0130, "National Datacomm NCP130 (PLX9052)"), - PLXDEV(0x15e8, 0x0131, "National Datacomm NCP130 (TMD7160)"), - PLXDEV(0x1638, 0x1100, "Eumitcom WL11000"), - PLXDEV(0x16ab, 0x1100, "Global Sun Tech GL24110P"), - PLXDEV(0x16ab, 0x1101, "Global Sun Tech GL24110P (?)"), - PLXDEV(0x16ab, 0x1102, "Linksys WPC11 with WDT11"), - PLXDEV(0x16ab, 0x1103, "Longshine 8031"), - PLXDEV(0x16ec, 0x3685, "US Robotics USR2415"), - PLXDEV(0xec80, 0xec00, "Belkin F5D6000"), - { 0 } -}; - - -/* Array of known Prism2/2.5 PC Card manufactured ids. If your card's manfid - * is not listed here, you will need to add it here to get the driver - * initialized. */ -static struct prism2_plx_manfid { - u16 manfid1, manfid2; -} prism2_plx_known_manfids[] = { - { 0x000b, 0x7110 } /* D-Link DWL-650 Rev. P1 */, - { 0x000b, 0x7300 } /* Philips 802.11b WLAN PCMCIA */, - { 0x0101, 0x0777 } /* 3Com AirConnect PCI 777A */, - { 0x0126, 0x8000 } /* Proxim RangeLAN */, - { 0x0138, 0x0002 } /* Compaq WL100 */, - { 0x0156, 0x0002 } /* Intersil Prism II Ref. Design (and others) */, - { 0x026f, 0x030b } /* Buffalo WLI-CF-S11G */, - { 0x0274, 0x1612 } /* Linksys WPC11 Ver 2.5 */, - { 0x0274, 0x1613 } /* Linksys WPC11 Ver 3 */, - { 0x028a, 0x0002 } /* D-Link DRC-650 */, - { 0x0250, 0x0002 } /* Samsung SWL2000-N */, - { 0xc250, 0x0002 } /* EMTAC A2424i */, - { 0xd601, 0x0002 } /* Z-Com XI300 */, - { 0xd601, 0x0005 } /* Zcomax XI-325H 200mW */, - { 0, 0} -}; - - -#ifdef PRISM2_IO_DEBUG - -static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - - iface = netdev_priv(dev); - local = iface->local; - - spin_lock_irqsave(&local->lock, flags); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v); - outb(v, dev->base_addr + a); - spin_unlock_irqrestore(&local->lock, flags); -} - -static inline u8 hfa384x_inb_debug(struct net_device *dev, int a) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - u8 v; - - iface = netdev_priv(dev); - local = iface->local; - - spin_lock_irqsave(&local->lock, flags); - v = inb(dev->base_addr + a); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v); - spin_unlock_irqrestore(&local->lock, flags); - return v; -} - -static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - - iface = netdev_priv(dev); - local = iface->local; - - spin_lock_irqsave(&local->lock, flags); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v); - outw(v, dev->base_addr + a); - spin_unlock_irqrestore(&local->lock, flags); -} - -static inline u16 hfa384x_inw_debug(struct net_device *dev, int a) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - u16 v; - - iface = netdev_priv(dev); - local = iface->local; - - spin_lock_irqsave(&local->lock, flags); - v = inw(dev->base_addr + a); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v); - spin_unlock_irqrestore(&local->lock, flags); - return v; -} - -static inline void hfa384x_outsw_debug(struct net_device *dev, int a, - u8 *buf, int wc) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - - iface = netdev_priv(dev); - local = iface->local; - - spin_lock_irqsave(&local->lock, flags); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc); - outsw(dev->base_addr + a, buf, wc); - spin_unlock_irqrestore(&local->lock, flags); -} - -static inline void hfa384x_insw_debug(struct net_device *dev, int a, - u8 *buf, int wc) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - - iface = netdev_priv(dev); - local = iface->local; - - spin_lock_irqsave(&local->lock, flags); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc); - insw(dev->base_addr + a, buf, wc); - spin_unlock_irqrestore(&local->lock, flags); -} - -#define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v)) -#define HFA384X_INB(a) hfa384x_inb_debug(dev, (a)) -#define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v)) -#define HFA384X_INW(a) hfa384x_inw_debug(dev, (a)) -#define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc)) -#define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc)) - -#else /* PRISM2_IO_DEBUG */ - -#define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a)) -#define HFA384X_INB(a) inb(dev->base_addr + (a)) -#define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a)) -#define HFA384X_INW(a) inw(dev->base_addr + (a)) -#define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc) -#define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc) - -#endif /* PRISM2_IO_DEBUG */ - - -static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf, - int len) -{ - u16 d_off; - u16 *pos; - - d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; - pos = (u16 *) buf; - - if (len / 2) - HFA384X_INSW(d_off, buf, len / 2); - pos += len / 2; - - if (len & 1) - *((char *) pos) = HFA384X_INB(d_off); - - return 0; -} - - -static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len) -{ - u16 d_off; - u16 *pos; - - d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; - pos = (u16 *) buf; - - if (len / 2) - HFA384X_OUTSW(d_off, buf, len / 2); - pos += len / 2; - - if (len & 1) - HFA384X_OUTB(*((char *) pos), d_off); - - return 0; -} - - -/* FIX: This might change at some point.. */ -#include "hostap_hw.c" - - -static void prism2_plx_cor_sreset(local_info_t *local) -{ - unsigned char corsave; - struct hostap_plx_priv *hw_priv = local->hw_priv; - - printk(KERN_DEBUG "%s: Doing reset via direct COR access.\n", - dev_info); - - /* Set sreset bit of COR and clear it after hold time */ - - if (hw_priv->attr_mem == NULL) { - /* TMD7160 - COR at card's first I/O addr */ - corsave = inb(hw_priv->cor_offset); - outb(corsave | COR_SRESET, hw_priv->cor_offset); - mdelay(2); - outb(corsave & ~COR_SRESET, hw_priv->cor_offset); - mdelay(2); - } else { - /* PLX9052 */ - corsave = readb(hw_priv->attr_mem + hw_priv->cor_offset); - writeb(corsave | COR_SRESET, - hw_priv->attr_mem + hw_priv->cor_offset); - mdelay(2); - writeb(corsave & ~COR_SRESET, - hw_priv->attr_mem + hw_priv->cor_offset); - mdelay(2); - } -} - - -static void prism2_plx_genesis_reset(local_info_t *local, int hcr) -{ - unsigned char corsave; - struct hostap_plx_priv *hw_priv = local->hw_priv; - - if (hw_priv->attr_mem == NULL) { - /* TMD7160 - COR at card's first I/O addr */ - corsave = inb(hw_priv->cor_offset); - outb(corsave | COR_SRESET, hw_priv->cor_offset); - mdelay(10); - outb(hcr, hw_priv->cor_offset + 2); - mdelay(10); - outb(corsave & ~COR_SRESET, hw_priv->cor_offset); - mdelay(10); - } else { - /* PLX9052 */ - corsave = readb(hw_priv->attr_mem + hw_priv->cor_offset); - writeb(corsave | COR_SRESET, - hw_priv->attr_mem + hw_priv->cor_offset); - mdelay(10); - writeb(hcr, hw_priv->attr_mem + hw_priv->cor_offset + 2); - mdelay(10); - writeb(corsave & ~COR_SRESET, - hw_priv->attr_mem + hw_priv->cor_offset); - mdelay(10); - } -} - - -static struct prism2_helper_functions prism2_plx_funcs = -{ - .card_present = NULL, - .cor_sreset = prism2_plx_cor_sreset, - .genesis_reset = prism2_plx_genesis_reset, - .hw_type = HOSTAP_HW_PLX, -}; - - -static int prism2_plx_check_cis(void __iomem *attr_mem, int attr_len, - unsigned int *cor_offset, - unsigned int *cor_index) -{ -#define CISTPL_CONFIG 0x1A -#define CISTPL_MANFID 0x20 -#define CISTPL_END 0xFF -#define CIS_MAX_LEN 256 - u8 *cis; - int i, pos; - unsigned int rmsz, rasz, manfid1, manfid2; - struct prism2_plx_manfid *manfid; - - cis = kmalloc(CIS_MAX_LEN, GFP_KERNEL); - if (cis == NULL) - return -ENOMEM; - - /* read CIS; it is in even offsets in the beginning of attr_mem */ - for (i = 0; i < CIS_MAX_LEN; i++) - cis[i] = readb(attr_mem + 2 * i); - printk(KERN_DEBUG "%s: CIS: %6ph ...\n", dev_info, cis); - - /* set reasonable defaults for Prism2 cards just in case CIS parsing - * fails */ - *cor_offset = 0x3e0; - *cor_index = 0x01; - manfid1 = manfid2 = 0; - - pos = 0; - while (pos < CIS_MAX_LEN - 1 && cis[pos] != CISTPL_END) { - if (pos + 2 + cis[pos + 1] > CIS_MAX_LEN) - goto cis_error; - - switch (cis[pos]) { - case CISTPL_CONFIG: - if (cis[pos + 1] < 2) - goto cis_error; - rmsz = (cis[pos + 2] & 0x3c) >> 2; - rasz = cis[pos + 2] & 0x03; - if (4 + rasz + rmsz > cis[pos + 1]) - goto cis_error; - *cor_index = cis[pos + 3] & 0x3F; - *cor_offset = 0; - for (i = 0; i <= rasz; i++) - *cor_offset += cis[pos + 4 + i] << (8 * i); - printk(KERN_DEBUG "%s: cor_index=0x%x " - "cor_offset=0x%x\n", dev_info, - *cor_index, *cor_offset); - if (*cor_offset > attr_len) { - printk(KERN_ERR "%s: COR offset not within " - "attr_mem\n", dev_info); - kfree(cis); - return -1; - } - break; - - case CISTPL_MANFID: - if (cis[pos + 1] < 4) - goto cis_error; - manfid1 = cis[pos + 2] + (cis[pos + 3] << 8); - manfid2 = cis[pos + 4] + (cis[pos + 5] << 8); - printk(KERN_DEBUG "%s: manfid=0x%04x, 0x%04x\n", - dev_info, manfid1, manfid2); - break; - } - - pos += cis[pos + 1] + 2; - } - - if (pos >= CIS_MAX_LEN || cis[pos] != CISTPL_END) - goto cis_error; - - for (manfid = prism2_plx_known_manfids; manfid->manfid1 != 0; manfid++) - if (manfid1 == manfid->manfid1 && manfid2 == manfid->manfid2) { - kfree(cis); - return 0; - } - - printk(KERN_INFO "%s: unknown manfid 0x%04x, 0x%04x - assuming this is" - " not supported card\n", dev_info, manfid1, manfid2); - goto fail; - - cis_error: - printk(KERN_WARNING "%s: invalid CIS data\n", dev_info); - - fail: - kfree(cis); - if (ignore_cis) { - printk(KERN_INFO "%s: ignore_cis parameter set - ignoring " - "errors during CIS verification\n", dev_info); - return 0; - } - return -1; -} - - -static int prism2_plx_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - unsigned int pccard_ioaddr, plx_ioaddr; - unsigned long pccard_attr_mem; - unsigned int pccard_attr_len; - void __iomem *attr_mem = NULL; - unsigned int cor_offset = 0, cor_index = 0; - u32 reg; - local_info_t *local = NULL; - struct net_device *dev = NULL; - struct hostap_interface *iface; - static int cards_found /* = 0 */; - int irq_registered = 0; - int tmd7160; - struct hostap_plx_priv *hw_priv; - - hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL); - if (hw_priv == NULL) - return -ENOMEM; - - if (pci_enable_device(pdev)) - goto err_out_free; - - /* National Datacomm NCP130 based on TMD7160, not PLX9052. */ - tmd7160 = (pdev->vendor == 0x15e8) && (pdev->device == 0x0131); - - plx_ioaddr = pci_resource_start(pdev, 1); - pccard_ioaddr = pci_resource_start(pdev, tmd7160 ? 2 : 3); - - if (tmd7160) { - /* TMD7160 */ - attr_mem = NULL; /* no access to PC Card attribute memory */ - - printk(KERN_INFO "TMD7160 PCI/PCMCIA adapter: io=0x%x, " - "irq=%d, pccard_io=0x%x\n", - plx_ioaddr, pdev->irq, pccard_ioaddr); - - cor_offset = plx_ioaddr; - cor_index = 0x04; - - outb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, plx_ioaddr); - mdelay(1); - reg = inb(plx_ioaddr); - if (reg != (cor_index | COR_LEVLREQ | COR_ENABLE_FUNC)) { - printk(KERN_ERR "%s: Error setting COR (expected=" - "0x%02x, was=0x%02x)\n", dev_info, - cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, reg); - goto fail; - } - } else { - /* PLX9052 */ - pccard_attr_mem = pci_resource_start(pdev, 2); - pccard_attr_len = pci_resource_len(pdev, 2); - if (pccard_attr_len < PLX_MIN_ATTR_LEN) - goto fail; - - - attr_mem = ioremap(pccard_attr_mem, pccard_attr_len); - if (attr_mem == NULL) { - printk(KERN_ERR "%s: cannot remap attr_mem\n", - dev_info); - goto fail; - } - - printk(KERN_INFO "PLX9052 PCI/PCMCIA adapter: " - "mem=0x%lx, plx_io=0x%x, irq=%d, pccard_io=0x%x\n", - pccard_attr_mem, plx_ioaddr, pdev->irq, pccard_ioaddr); - - if (prism2_plx_check_cis(attr_mem, pccard_attr_len, - &cor_offset, &cor_index)) { - printk(KERN_INFO "Unknown PC Card CIS - not a " - "Prism2/2.5 card?\n"); - goto fail; - } - - printk(KERN_DEBUG "Prism2/2.5 PC Card detected in PLX9052 " - "adapter\n"); - - /* Write COR to enable PC Card */ - writeb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, - attr_mem + cor_offset); - - /* Enable PCI interrupts if they are not already enabled */ - reg = inl(plx_ioaddr + PLX_INTCSR); - printk(KERN_DEBUG "PLX_INTCSR=0x%x\n", reg); - if (!(reg & PLX_INTCSR_PCI_INTEN)) { - outl(reg | PLX_INTCSR_PCI_INTEN, - plx_ioaddr + PLX_INTCSR); - if (!(inl(plx_ioaddr + PLX_INTCSR) & - PLX_INTCSR_PCI_INTEN)) { - printk(KERN_WARNING "%s: Could not enable " - "Local Interrupts\n", dev_info); - goto fail; - } - } - - reg = inl(plx_ioaddr + PLX_CNTRL); - printk(KERN_DEBUG "PLX_CNTRL=0x%x (Serial EEPROM " - "present=%d)\n", - reg, (reg & PLX_CNTRL_SERIAL_EEPROM_PRESENT) != 0); - /* should set PLX_PCIIPR to 0x01 (INTA#) if Serial EEPROM is - * not present; but are there really such cards in use(?) */ - } - - dev = prism2_init_local_data(&prism2_plx_funcs, cards_found, - &pdev->dev); - if (dev == NULL) - goto fail; - iface = netdev_priv(dev); - local = iface->local; - local->hw_priv = hw_priv; - cards_found++; - - dev->irq = pdev->irq; - dev->base_addr = pccard_ioaddr; - hw_priv->attr_mem = attr_mem; - hw_priv->cor_offset = cor_offset; - - pci_set_drvdata(pdev, dev); - - if (request_irq(dev->irq, prism2_interrupt, IRQF_SHARED, dev->name, - dev)) { - printk(KERN_WARNING "%s: request_irq failed\n", dev->name); - goto fail; - } else - irq_registered = 1; - - if (prism2_hw_config(dev, 1)) { - printk(KERN_DEBUG "%s: hardware initialization failed\n", - dev_info); - goto fail; - } - - return hostap_hw_ready(dev); - - fail: - if (irq_registered && dev) - free_irq(dev->irq, dev); - - if (attr_mem) - iounmap(attr_mem); - - pci_disable_device(pdev); - prism2_free_local_data(dev); - - err_out_free: - kfree(hw_priv); - - return -ENODEV; -} - - -static void prism2_plx_remove(struct pci_dev *pdev) -{ - struct net_device *dev; - struct hostap_interface *iface; - struct hostap_plx_priv *hw_priv; - - dev = pci_get_drvdata(pdev); - iface = netdev_priv(dev); - hw_priv = iface->local->hw_priv; - - /* Reset the hardware, and ensure interrupts are disabled. */ - prism2_plx_cor_sreset(iface->local); - hfa384x_disable_interrupts(dev); - - if (hw_priv->attr_mem) - iounmap(hw_priv->attr_mem); - if (dev->irq) - free_irq(dev->irq, dev); - - prism2_free_local_data(dev); - kfree(hw_priv); - pci_disable_device(pdev); -} - - -MODULE_DEVICE_TABLE(pci, prism2_plx_id_table); - -static struct pci_driver prism2_plx_driver = { - .name = "hostap_plx", - .id_table = prism2_plx_id_table, - .probe = prism2_plx_probe, - .remove = prism2_plx_remove, -}; - -module_pci_driver(prism2_plx_driver); diff --git a/drivers/net/wireless/intersil/hostap/hostap_proc.c b/drivers/net/wireless/intersil/hostap/hostap_proc.c deleted file mode 100644 index 61f68786056f4..0000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_proc.c +++ /dev/null @@ -1,411 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* /proc routines for Host AP driver */ - -#include -#include -#include -#include - -#include "hostap_wlan.h" -#include "hostap.h" - -#define PROC_LIMIT (PAGE_SIZE - 80) - -#if !defined(PRISM2_NO_PROCFS_DEBUG) && defined(CONFIG_PROC_FS) -static int prism2_debug_proc_show(struct seq_file *m, void *v) -{ - local_info_t *local = m->private; - int i; - - seq_printf(m, "next_txfid=%d next_alloc=%d\n", - local->next_txfid, local->next_alloc); - for (i = 0; i < PRISM2_TXFID_COUNT; i++) - seq_printf(m, "FID: tx=%04X intransmit=%04X\n", - local->txfid[i], local->intransmitfid[i]); - seq_printf(m, "FW TX rate control: %d\n", local->fw_tx_rate_control); - seq_printf(m, "beacon_int=%d\n", local->beacon_int); - seq_printf(m, "dtim_period=%d\n", local->dtim_period); - seq_printf(m, "wds_max_connections=%d\n", local->wds_max_connections); - seq_printf(m, "dev_enabled=%d\n", local->dev_enabled); - seq_printf(m, "sw_tick_stuck=%d\n", local->sw_tick_stuck); - for (i = 0; i < WEP_KEYS; i++) { - if (local->crypt_info.crypt[i] && - local->crypt_info.crypt[i]->ops) { - seq_printf(m, "crypt[%d]=%s\n", i, - local->crypt_info.crypt[i]->ops->name); - } - } - seq_printf(m, "pri_only=%d\n", local->pri_only); - seq_printf(m, "pci=%d\n", local->func->hw_type == HOSTAP_HW_PCI); - seq_printf(m, "sram_type=%d\n", local->sram_type); - seq_printf(m, "no_pri=%d\n", local->no_pri); - - return 0; -} -#endif - -#ifdef CONFIG_PROC_FS -static int prism2_stats_proc_show(struct seq_file *m, void *v) -{ - local_info_t *local = m->private; - struct comm_tallies_sums *sums = &local->comm_tallies; - - seq_printf(m, "TxUnicastFrames=%u\n", sums->tx_unicast_frames); - seq_printf(m, "TxMulticastframes=%u\n", sums->tx_multicast_frames); - seq_printf(m, "TxFragments=%u\n", sums->tx_fragments); - seq_printf(m, "TxUnicastOctets=%u\n", sums->tx_unicast_octets); - seq_printf(m, "TxMulticastOctets=%u\n", sums->tx_multicast_octets); - seq_printf(m, "TxDeferredTransmissions=%u\n", - sums->tx_deferred_transmissions); - seq_printf(m, "TxSingleRetryFrames=%u\n", sums->tx_single_retry_frames); - seq_printf(m, "TxMultipleRetryFrames=%u\n", - sums->tx_multiple_retry_frames); - seq_printf(m, "TxRetryLimitExceeded=%u\n", - sums->tx_retry_limit_exceeded); - seq_printf(m, "TxDiscards=%u\n", sums->tx_discards); - seq_printf(m, "RxUnicastFrames=%u\n", sums->rx_unicast_frames); - seq_printf(m, "RxMulticastFrames=%u\n", sums->rx_multicast_frames); - seq_printf(m, "RxFragments=%u\n", sums->rx_fragments); - seq_printf(m, "RxUnicastOctets=%u\n", sums->rx_unicast_octets); - seq_printf(m, "RxMulticastOctets=%u\n", sums->rx_multicast_octets); - seq_printf(m, "RxFCSErrors=%u\n", sums->rx_fcs_errors); - seq_printf(m, "RxDiscardsNoBuffer=%u\n", sums->rx_discards_no_buffer); - seq_printf(m, "TxDiscardsWrongSA=%u\n", sums->tx_discards_wrong_sa); - seq_printf(m, "RxDiscardsWEPUndecryptable=%u\n", - sums->rx_discards_wep_undecryptable); - seq_printf(m, "RxMessageInMsgFragments=%u\n", - sums->rx_message_in_msg_fragments); - seq_printf(m, "RxMessageInBadMsgFragments=%u\n", - sums->rx_message_in_bad_msg_fragments); - /* FIX: this may grow too long for one page(?) */ - - return 0; -} -#endif - -static int prism2_wds_proc_show(struct seq_file *m, void *v) -{ - struct list_head *ptr = v; - struct hostap_interface *iface; - - iface = list_entry(ptr, struct hostap_interface, list); - if (iface->type == HOSTAP_INTERFACE_WDS) - seq_printf(m, "%s\t%pM\n", - iface->dev->name, iface->u.wds.remote_addr); - return 0; -} - -static void *prism2_wds_proc_start(struct seq_file *m, loff_t *_pos) -{ - local_info_t *local = pde_data(file_inode(m->file)); - read_lock_bh(&local->iface_lock); - return seq_list_start(&local->hostap_interfaces, *_pos); -} - -static void *prism2_wds_proc_next(struct seq_file *m, void *v, loff_t *_pos) -{ - local_info_t *local = pde_data(file_inode(m->file)); - return seq_list_next(v, &local->hostap_interfaces, _pos); -} - -static void prism2_wds_proc_stop(struct seq_file *m, void *v) -{ - local_info_t *local = pde_data(file_inode(m->file)); - read_unlock_bh(&local->iface_lock); -} - -static const struct seq_operations prism2_wds_proc_seqops = { - .start = prism2_wds_proc_start, - .next = prism2_wds_proc_next, - .stop = prism2_wds_proc_stop, - .show = prism2_wds_proc_show, -}; - -static int prism2_bss_list_proc_show(struct seq_file *m, void *v) -{ - local_info_t *local = pde_data(file_inode(m->file)); - struct list_head *ptr = v; - struct hostap_bss_info *bss; - - if (ptr == &local->bss_list) { - seq_printf(m, "#BSSID\tlast_update\tcount\tcapab_info\tSSID(txt)\t" - "SSID(hex)\tWPA IE\n"); - return 0; - } - - bss = list_entry(ptr, struct hostap_bss_info, list); - seq_printf(m, "%pM\t%lu\t%u\t0x%x\t", - bss->bssid, bss->last_update, - bss->count, bss->capab_info); - - seq_printf(m, "%*pE", (int)bss->ssid_len, bss->ssid); - - seq_putc(m, '\t'); - seq_printf(m, "%*phN", (int)bss->ssid_len, bss->ssid); - seq_putc(m, '\t'); - seq_printf(m, "%*phN", (int)bss->wpa_ie_len, bss->wpa_ie); - seq_putc(m, '\n'); - return 0; -} - -static void *prism2_bss_list_proc_start(struct seq_file *m, loff_t *_pos) - __acquires(&local->lock) -{ - local_info_t *local = pde_data(file_inode(m->file)); - spin_lock_bh(&local->lock); - return seq_list_start_head(&local->bss_list, *_pos); -} - -static void *prism2_bss_list_proc_next(struct seq_file *m, void *v, loff_t *_pos) -{ - local_info_t *local = pde_data(file_inode(m->file)); - return seq_list_next(v, &local->bss_list, _pos); -} - -static void prism2_bss_list_proc_stop(struct seq_file *m, void *v) - __releases(&local->lock) -{ - local_info_t *local = pde_data(file_inode(m->file)); - spin_unlock_bh(&local->lock); -} - -static const struct seq_operations prism2_bss_list_proc_seqops = { - .start = prism2_bss_list_proc_start, - .next = prism2_bss_list_proc_next, - .stop = prism2_bss_list_proc_stop, - .show = prism2_bss_list_proc_show, -}; - -#ifdef CONFIG_PROC_FS -static int prism2_crypt_proc_show(struct seq_file *m, void *v) -{ - local_info_t *local = m->private; - int i; - - seq_printf(m, "tx_keyidx=%d\n", local->crypt_info.tx_keyidx); - for (i = 0; i < WEP_KEYS; i++) { - if (local->crypt_info.crypt[i] && - local->crypt_info.crypt[i]->ops && - local->crypt_info.crypt[i]->ops->print_stats) { - local->crypt_info.crypt[i]->ops->print_stats( - m, local->crypt_info.crypt[i]->priv); - } - } - return 0; -} -#endif - -static ssize_t prism2_pda_proc_read(struct file *file, char __user *buf, - size_t count, loff_t *_pos) -{ - local_info_t *local = pde_data(file_inode(file)); - size_t off; - - if (local->pda == NULL || *_pos >= PRISM2_PDA_SIZE) - return 0; - - off = *_pos; - if (count > PRISM2_PDA_SIZE - off) - count = PRISM2_PDA_SIZE - off; - if (copy_to_user(buf, local->pda + off, count) != 0) - return -EFAULT; - *_pos += count; - return count; -} - -static const struct proc_ops prism2_pda_proc_ops = { - .proc_read = prism2_pda_proc_read, - .proc_lseek = generic_file_llseek, -}; - - -static ssize_t prism2_aux_dump_proc_no_read(struct file *file, char __user *buf, - size_t bufsize, loff_t *_pos) -{ - return 0; -} - -static const struct proc_ops prism2_aux_dump_proc_ops = { - .proc_read = prism2_aux_dump_proc_no_read, - .proc_lseek = default_llseek, -}; - - -#ifdef PRISM2_IO_DEBUG -static int prism2_io_debug_proc_read(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - local_info_t *local = (local_info_t *) data; - int head = local->io_debug_head; - int start_bytes, left, copy; - - if (off + count > PRISM2_IO_DEBUG_SIZE * 4) { - *eof = 1; - if (off >= PRISM2_IO_DEBUG_SIZE * 4) - return 0; - count = PRISM2_IO_DEBUG_SIZE * 4 - off; - } - - start_bytes = (PRISM2_IO_DEBUG_SIZE - head) * 4; - left = count; - - if (off < start_bytes) { - copy = start_bytes - off; - if (copy > count) - copy = count; - memcpy(page, ((u8 *) &local->io_debug[head]) + off, copy); - left -= copy; - if (left > 0) - memcpy(&page[copy], local->io_debug, left); - } else { - memcpy(page, ((u8 *) local->io_debug) + (off - start_bytes), - left); - } - - *start = page; - - return count; -} -#endif /* PRISM2_IO_DEBUG */ - - -#ifndef PRISM2_NO_STATION_MODES -static int prism2_scan_results_proc_show(struct seq_file *m, void *v) -{ - local_info_t *local = pde_data(file_inode(m->file)); - unsigned long entry; - int i, len; - struct hfa384x_hostscan_result *scanres; - u8 *p; - - if (v == SEQ_START_TOKEN) { - seq_printf(m, - "CHID ANL SL BcnInt Capab Rate BSSID ATIM SupRates SSID\n"); - return 0; - } - - entry = (unsigned long)v - 2; - scanres = &local->last_scan_results[entry]; - - seq_printf(m, "%d %d %d %d 0x%02x %d %pM %d ", - le16_to_cpu(scanres->chid), - (s16) le16_to_cpu(scanres->anl), - (s16) le16_to_cpu(scanres->sl), - le16_to_cpu(scanres->beacon_interval), - le16_to_cpu(scanres->capability), - le16_to_cpu(scanres->rate), - scanres->bssid, - le16_to_cpu(scanres->atim)); - - p = scanres->sup_rates; - for (i = 0; i < sizeof(scanres->sup_rates); i++) { - if (p[i] == 0) - break; - seq_printf(m, "<%02x>", p[i]); - } - seq_putc(m, ' '); - - p = scanres->ssid; - len = le16_to_cpu(scanres->ssid_len); - if (len > 32) - len = 32; - for (i = 0; i < len; i++) { - unsigned char c = p[i]; - if (c >= 32 && c < 127) - seq_putc(m, c); - else - seq_printf(m, "<%02x>", c); - } - seq_putc(m, '\n'); - return 0; -} - -static void *prism2_scan_results_proc_start(struct seq_file *m, loff_t *_pos) -{ - local_info_t *local = pde_data(file_inode(m->file)); - spin_lock_bh(&local->lock); - - /* We have a header (pos 0) + N results to show (pos 1...N) */ - if (*_pos > local->last_scan_results_count) - return NULL; - return (void *)(unsigned long)(*_pos + 1); /* 0 would be EOF */ -} - -static void *prism2_scan_results_proc_next(struct seq_file *m, void *v, loff_t *_pos) -{ - local_info_t *local = pde_data(file_inode(m->file)); - - ++*_pos; - if (*_pos > local->last_scan_results_count) - return NULL; - return (void *)(unsigned long)(*_pos + 1); /* 0 would be EOF */ -} - -static void prism2_scan_results_proc_stop(struct seq_file *m, void *v) -{ - local_info_t *local = pde_data(file_inode(m->file)); - spin_unlock_bh(&local->lock); -} - -static const struct seq_operations prism2_scan_results_proc_seqops = { - .start = prism2_scan_results_proc_start, - .next = prism2_scan_results_proc_next, - .stop = prism2_scan_results_proc_stop, - .show = prism2_scan_results_proc_show, -}; -#endif /* PRISM2_NO_STATION_MODES */ - - -void hostap_init_proc(local_info_t *local) -{ - local->proc = NULL; - - if (hostap_proc == NULL) { - printk(KERN_WARNING "%s: hostap proc directory not created\n", - local->dev->name); - return; - } - - local->proc = proc_mkdir(local->ddev->name, hostap_proc); - if (local->proc == NULL) { - printk(KERN_INFO "/proc/net/hostap/%s creation failed\n", - local->ddev->name); - return; - } - -#ifndef PRISM2_NO_PROCFS_DEBUG - proc_create_single_data("debug", 0, local->proc, - prism2_debug_proc_show, local); -#endif /* PRISM2_NO_PROCFS_DEBUG */ - proc_create_single_data("stats", 0, local->proc, prism2_stats_proc_show, - local); - proc_create_seq_data("wds", 0, local->proc, - &prism2_wds_proc_seqops, local); - proc_create_data("pda", 0, local->proc, - &prism2_pda_proc_ops, local); - proc_create_data("aux_dump", 0, local->proc, - local->func->read_aux_proc_ops ?: &prism2_aux_dump_proc_ops, - local); - proc_create_seq_data("bss_list", 0, local->proc, - &prism2_bss_list_proc_seqops, local); - proc_create_single_data("crypt", 0, local->proc, prism2_crypt_proc_show, - local); -#ifdef PRISM2_IO_DEBUG - proc_create_single_data("io_debug", 0, local->proc, - prism2_debug_proc_show, local); -#endif /* PRISM2_IO_DEBUG */ -#ifndef PRISM2_NO_STATION_MODES - proc_create_seq_data("scan_results", 0, local->proc, - &prism2_scan_results_proc_seqops, local); -#endif /* PRISM2_NO_STATION_MODES */ -} - - -void hostap_remove_proc(local_info_t *local) -{ - proc_remove(local->proc); -} - - -EXPORT_SYMBOL(hostap_init_proc); -EXPORT_SYMBOL(hostap_remove_proc); diff --git a/drivers/net/wireless/intersil/hostap/hostap_wlan.h b/drivers/net/wireless/intersil/hostap/hostap_wlan.h deleted file mode 100644 index f71c0545c0be6..0000000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_wlan.h +++ /dev/null @@ -1,1051 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef HOSTAP_WLAN_H -#define HOSTAP_WLAN_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "hostap_config.h" -#include "hostap_common.h" - -#define MAX_PARM_DEVICES 8 -#define PARM_MIN_MAX "1-" __MODULE_STRING(MAX_PARM_DEVICES) -#define DEF_INTS -1, -1, -1, -1, -1, -1, -1 -#define GET_INT_PARM(var,idx) var[var[idx] < 0 ? 0 : idx] - - -/* Specific skb->protocol value that indicates that the packet already contains - * txdesc header. - * FIX: This might need own value that would be allocated especially for Prism2 - * txdesc; ETH_P_CONTROL is commented as "Card specific control frames". - * However, these skb's should have only minimal path in the kernel side since - * prism2_send_mgmt() sends these with dev_queue_xmit() to prism2_tx(). */ -#define ETH_P_HOSTAP ETH_P_CONTROL - -/* ARPHRD_IEEE80211_PRISM uses a bloated version of Prism2 RX frame header - * (from linux-wlan-ng) */ -struct linux_wlan_ng_val { - u32 did; - u16 status, len; - u32 data; -} __packed; - -struct linux_wlan_ng_prism_hdr { - u32 msgcode, msglen; - char devname[16]; - struct linux_wlan_ng_val hosttime, mactime, channel, rssi, sq, signal, - noise, rate, istx, frmlen; -} __packed; - -struct linux_wlan_ng_cap_hdr { - __be32 version; - __be32 length; - __be64 mactime; - __be64 hosttime; - __be32 phytype; - __be32 channel; - __be32 datarate; - __be32 antenna; - __be32 priority; - __be32 ssi_type; - __be32 ssi_signal; - __be32 ssi_noise; - __be32 preamble; - __be32 encoding; -} __packed; - -struct hostap_radiotap_rx { - struct ieee80211_radiotap_header hdr; - __le64 tsft; - u8 rate; - u8 padding; - __le16 chan_freq; - __le16 chan_flags; - s8 dbm_antsignal; - s8 dbm_antnoise; -} __packed; - -#define LWNG_CAP_DID_BASE (4 | (1 << 6)) /* section 4, group 1 */ -#define LWNG_CAPHDR_VERSION 0x80211001 - -struct hfa384x_rx_frame { - /* HFA384X RX frame descriptor */ - __le16 status; /* HFA384X_RX_STATUS_ flags */ - __le32 time; /* timestamp, 1 microsecond resolution */ - u8 silence; /* 27 .. 154; seems to be 0 */ - u8 signal; /* 27 .. 154 */ - u8 rate; /* 10, 20, 55, or 110 */ - u8 rxflow; - __le32 reserved; - - /* 802.11 */ - __le16 frame_control; - __le16 duration_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 addr3[ETH_ALEN]; - __le16 seq_ctrl; - u8 addr4[ETH_ALEN]; - __le16 data_len; - - /* 802.3 */ - u8 dst_addr[ETH_ALEN]; - u8 src_addr[ETH_ALEN]; - __be16 len; - - /* followed by frame data; max 2304 bytes */ -} __packed; - - -struct hfa384x_tx_frame { - /* HFA384X TX frame descriptor */ - __le16 status; /* HFA384X_TX_STATUS_ flags */ - __le16 reserved1; - __le16 reserved2; - __le32 sw_support; - u8 retry_count; /* not yet implemented */ - u8 tx_rate; /* Host AP only; 0 = firmware, or 10, 20, 55, 110 */ - __le16 tx_control; /* HFA384X_TX_CTRL_ flags */ - - /* 802.11 */ - struct_group(header, - __le16 frame_control; /* parts not used */ - __le16 duration_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; /* filled by firmware */ - u8 addr3[ETH_ALEN]; - __le16 seq_ctrl; /* filled by firmware */ - ); - u8 addr4[ETH_ALEN]; - __le16 data_len; - - /* 802.3 */ - u8 dst_addr[ETH_ALEN]; - u8 src_addr[ETH_ALEN]; - __be16 len; - - /* followed by frame data; max 2304 bytes */ -} __packed; - - -struct hfa384x_rid_hdr -{ - __le16 len; - __le16 rid; -} __packed; - - -/* Macro for converting signal levels (range 27 .. 154) to wireless ext - * dBm value with some accuracy */ -#define HFA384X_LEVEL_TO_dBm(v) 0x100 + (v) * 100 / 255 - 100 - -#define HFA384X_LEVEL_TO_dBm_sign(v) (v) * 100 / 255 - 100 - -struct hfa384x_scan_request { - __le16 channel_list; - __le16 txrate; /* HFA384X_RATES_* */ -} __packed; - -struct hfa384x_hostscan_request { - __le16 channel_list; - __le16 txrate; - __le16 target_ssid_len; - u8 target_ssid[32]; -} __packed; - -struct hfa384x_join_request { - u8 bssid[ETH_ALEN]; - __le16 channel; -} __packed; - -struct hfa384x_info_frame { - __le16 len; - __le16 type; -} __packed; - -struct hfa384x_comm_tallies { - __le16 tx_unicast_frames; - __le16 tx_multicast_frames; - __le16 tx_fragments; - __le16 tx_unicast_octets; - __le16 tx_multicast_octets; - __le16 tx_deferred_transmissions; - __le16 tx_single_retry_frames; - __le16 tx_multiple_retry_frames; - __le16 tx_retry_limit_exceeded; - __le16 tx_discards; - __le16 rx_unicast_frames; - __le16 rx_multicast_frames; - __le16 rx_fragments; - __le16 rx_unicast_octets; - __le16 rx_multicast_octets; - __le16 rx_fcs_errors; - __le16 rx_discards_no_buffer; - __le16 tx_discards_wrong_sa; - __le16 rx_discards_wep_undecryptable; - __le16 rx_message_in_msg_fragments; - __le16 rx_message_in_bad_msg_fragments; -} __packed; - -struct hfa384x_comm_tallies32 { - __le32 tx_unicast_frames; - __le32 tx_multicast_frames; - __le32 tx_fragments; - __le32 tx_unicast_octets; - __le32 tx_multicast_octets; - __le32 tx_deferred_transmissions; - __le32 tx_single_retry_frames; - __le32 tx_multiple_retry_frames; - __le32 tx_retry_limit_exceeded; - __le32 tx_discards; - __le32 rx_unicast_frames; - __le32 rx_multicast_frames; - __le32 rx_fragments; - __le32 rx_unicast_octets; - __le32 rx_multicast_octets; - __le32 rx_fcs_errors; - __le32 rx_discards_no_buffer; - __le32 tx_discards_wrong_sa; - __le32 rx_discards_wep_undecryptable; - __le32 rx_message_in_msg_fragments; - __le32 rx_message_in_bad_msg_fragments; -} __packed; - -struct hfa384x_scan_result_hdr { - __le16 reserved; - __le16 scan_reason; -#define HFA384X_SCAN_IN_PROGRESS 0 /* no results available yet */ -#define HFA384X_SCAN_HOST_INITIATED 1 -#define HFA384X_SCAN_FIRMWARE_INITIATED 2 -#define HFA384X_SCAN_INQUIRY_FROM_HOST 3 -} __packed; - -#define HFA384X_SCAN_MAX_RESULTS 32 - -struct hfa384x_scan_result { - __le16 chid; - __le16 anl; - __le16 sl; - u8 bssid[ETH_ALEN]; - __le16 beacon_interval; - __le16 capability; - __le16 ssid_len; - u8 ssid[32]; - u8 sup_rates[10]; - __le16 rate; -} __packed; - -struct hfa384x_hostscan_result { - __le16 chid; - __le16 anl; - __le16 sl; - u8 bssid[ETH_ALEN]; - __le16 beacon_interval; - __le16 capability; - __le16 ssid_len; - u8 ssid[32]; - u8 sup_rates[10]; - __le16 rate; - __le16 atim; -} __packed; - -struct comm_tallies_sums { - unsigned int tx_unicast_frames; - unsigned int tx_multicast_frames; - unsigned int tx_fragments; - unsigned int tx_unicast_octets; - unsigned int tx_multicast_octets; - unsigned int tx_deferred_transmissions; - unsigned int tx_single_retry_frames; - unsigned int tx_multiple_retry_frames; - unsigned int tx_retry_limit_exceeded; - unsigned int tx_discards; - unsigned int rx_unicast_frames; - unsigned int rx_multicast_frames; - unsigned int rx_fragments; - unsigned int rx_unicast_octets; - unsigned int rx_multicast_octets; - unsigned int rx_fcs_errors; - unsigned int rx_discards_no_buffer; - unsigned int tx_discards_wrong_sa; - unsigned int rx_discards_wep_undecryptable; - unsigned int rx_message_in_msg_fragments; - unsigned int rx_message_in_bad_msg_fragments; -}; - - -struct hfa384x_regs { - u16 cmd; - u16 evstat; - u16 offset0; - u16 offset1; - u16 swsupport0; -}; - - -#if defined(PRISM2_PCCARD) || defined(PRISM2_PLX) -/* I/O ports for HFA384X Controller access */ -#define HFA384X_CMD_OFF 0x00 -#define HFA384X_PARAM0_OFF 0x02 -#define HFA384X_PARAM1_OFF 0x04 -#define HFA384X_PARAM2_OFF 0x06 -#define HFA384X_STATUS_OFF 0x08 -#define HFA384X_RESP0_OFF 0x0A -#define HFA384X_RESP1_OFF 0x0C -#define HFA384X_RESP2_OFF 0x0E -#define HFA384X_INFOFID_OFF 0x10 -#define HFA384X_CONTROL_OFF 0x14 -#define HFA384X_SELECT0_OFF 0x18 -#define HFA384X_SELECT1_OFF 0x1A -#define HFA384X_OFFSET0_OFF 0x1C -#define HFA384X_OFFSET1_OFF 0x1E -#define HFA384X_RXFID_OFF 0x20 -#define HFA384X_ALLOCFID_OFF 0x22 -#define HFA384X_TXCOMPLFID_OFF 0x24 -#define HFA384X_SWSUPPORT0_OFF 0x28 -#define HFA384X_SWSUPPORT1_OFF 0x2A -#define HFA384X_SWSUPPORT2_OFF 0x2C -#define HFA384X_EVSTAT_OFF 0x30 -#define HFA384X_INTEN_OFF 0x32 -#define HFA384X_EVACK_OFF 0x34 -#define HFA384X_DATA0_OFF 0x36 -#define HFA384X_DATA1_OFF 0x38 -#define HFA384X_AUXPAGE_OFF 0x3A -#define HFA384X_AUXOFFSET_OFF 0x3C -#define HFA384X_AUXDATA_OFF 0x3E -#endif /* PRISM2_PCCARD || PRISM2_PLX */ - -#ifdef PRISM2_PCI -/* Memory addresses for ISL3874 controller access */ -#define HFA384X_CMD_OFF 0x00 -#define HFA384X_PARAM0_OFF 0x04 -#define HFA384X_PARAM1_OFF 0x08 -#define HFA384X_PARAM2_OFF 0x0C -#define HFA384X_STATUS_OFF 0x10 -#define HFA384X_RESP0_OFF 0x14 -#define HFA384X_RESP1_OFF 0x18 -#define HFA384X_RESP2_OFF 0x1C -#define HFA384X_INFOFID_OFF 0x20 -#define HFA384X_CONTROL_OFF 0x28 -#define HFA384X_SELECT0_OFF 0x30 -#define HFA384X_SELECT1_OFF 0x34 -#define HFA384X_OFFSET0_OFF 0x38 -#define HFA384X_OFFSET1_OFF 0x3C -#define HFA384X_RXFID_OFF 0x40 -#define HFA384X_ALLOCFID_OFF 0x44 -#define HFA384X_TXCOMPLFID_OFF 0x48 -#define HFA384X_PCICOR_OFF 0x4C -#define HFA384X_SWSUPPORT0_OFF 0x50 -#define HFA384X_SWSUPPORT1_OFF 0x54 -#define HFA384X_SWSUPPORT2_OFF 0x58 -#define HFA384X_PCIHCR_OFF 0x5C -#define HFA384X_EVSTAT_OFF 0x60 -#define HFA384X_INTEN_OFF 0x64 -#define HFA384X_EVACK_OFF 0x68 -#define HFA384X_DATA0_OFF 0x6C -#define HFA384X_DATA1_OFF 0x70 -#define HFA384X_AUXPAGE_OFF 0x74 -#define HFA384X_AUXOFFSET_OFF 0x78 -#define HFA384X_AUXDATA_OFF 0x7C -#define HFA384X_PCI_M0_ADDRH_OFF 0x80 -#define HFA384X_PCI_M0_ADDRL_OFF 0x84 -#define HFA384X_PCI_M0_LEN_OFF 0x88 -#define HFA384X_PCI_M0_CTL_OFF 0x8C -#define HFA384X_PCI_STATUS_OFF 0x98 -#define HFA384X_PCI_M1_ADDRH_OFF 0xA0 -#define HFA384X_PCI_M1_ADDRL_OFF 0xA4 -#define HFA384X_PCI_M1_LEN_OFF 0xA8 -#define HFA384X_PCI_M1_CTL_OFF 0xAC - -/* PCI bus master control bits (these are undocumented; based on guessing and - * experimenting..) */ -#define HFA384X_PCI_CTL_FROM_BAP (BIT(5) | BIT(1) | BIT(0)) -#define HFA384X_PCI_CTL_TO_BAP (BIT(5) | BIT(0)) - -#endif /* PRISM2_PCI */ - - -/* Command codes for CMD reg. */ -#define HFA384X_CMDCODE_INIT 0x00 -#define HFA384X_CMDCODE_ENABLE 0x01 -#define HFA384X_CMDCODE_DISABLE 0x02 -#define HFA384X_CMDCODE_ALLOC 0x0A -#define HFA384X_CMDCODE_TRANSMIT 0x0B -#define HFA384X_CMDCODE_INQUIRE 0x11 -#define HFA384X_CMDCODE_ACCESS 0x21 -#define HFA384X_CMDCODE_ACCESS_WRITE (0x21 | BIT(8)) -#define HFA384X_CMDCODE_DOWNLOAD 0x22 -#define HFA384X_CMDCODE_READMIF 0x30 -#define HFA384X_CMDCODE_WRITEMIF 0x31 -#define HFA384X_CMDCODE_TEST 0x38 - -#define HFA384X_CMDCODE_MASK 0x3F - -/* Test mode operations */ -#define HFA384X_TEST_CHANGE_CHANNEL 0x08 -#define HFA384X_TEST_MONITOR 0x0B -#define HFA384X_TEST_STOP 0x0F -#define HFA384X_TEST_CFG_BITS 0x15 -#define HFA384X_TEST_CFG_BIT_ALC BIT(3) - -#define HFA384X_CMD_BUSY BIT(15) - -#define HFA384X_CMD_TX_RECLAIM BIT(8) - -#define HFA384X_OFFSET_ERR BIT(14) -#define HFA384X_OFFSET_BUSY BIT(15) - - -/* ProgMode for download command */ -#define HFA384X_PROGMODE_DISABLE 0 -#define HFA384X_PROGMODE_ENABLE_VOLATILE 1 -#define HFA384X_PROGMODE_ENABLE_NON_VOLATILE 2 -#define HFA384X_PROGMODE_PROGRAM_NON_VOLATILE 3 - -#define HFA384X_AUX_MAGIC0 0xfe01 -#define HFA384X_AUX_MAGIC1 0xdc23 -#define HFA384X_AUX_MAGIC2 0xba45 - -#define HFA384X_AUX_PORT_DISABLED 0 -#define HFA384X_AUX_PORT_DISABLE BIT(14) -#define HFA384X_AUX_PORT_ENABLE BIT(15) -#define HFA384X_AUX_PORT_ENABLED (BIT(14) | BIT(15)) -#define HFA384X_AUX_PORT_MASK (BIT(14) | BIT(15)) - -#define PRISM2_PDA_SIZE 1024 - - -/* Events; EvStat, Interrupt mask (IntEn), and acknowledge bits (EvAck) */ -#define HFA384X_EV_TICK BIT(15) -#define HFA384X_EV_WTERR BIT(14) -#define HFA384X_EV_INFDROP BIT(13) -#ifdef PRISM2_PCI -#define HFA384X_EV_PCI_M1 BIT(9) -#define HFA384X_EV_PCI_M0 BIT(8) -#endif /* PRISM2_PCI */ -#define HFA384X_EV_INFO BIT(7) -#define HFA384X_EV_DTIM BIT(5) -#define HFA384X_EV_CMD BIT(4) -#define HFA384X_EV_ALLOC BIT(3) -#define HFA384X_EV_TXEXC BIT(2) -#define HFA384X_EV_TX BIT(1) -#define HFA384X_EV_RX BIT(0) - - -/* HFA384X Information frames */ -#define HFA384X_INFO_HANDOVERADDR 0xF000 /* AP f/w ? */ -#define HFA384X_INFO_HANDOVERDEAUTHADDR 0xF001 /* AP f/w 1.3.7 */ -#define HFA384X_INFO_COMMTALLIES 0xF100 -#define HFA384X_INFO_SCANRESULTS 0xF101 -#define HFA384X_INFO_CHANNELINFORESULTS 0xF102 /* AP f/w only */ -#define HFA384X_INFO_HOSTSCANRESULTS 0xF103 -#define HFA384X_INFO_LINKSTATUS 0xF200 -#define HFA384X_INFO_ASSOCSTATUS 0xF201 /* ? */ -#define HFA384X_INFO_AUTHREQ 0xF202 /* ? */ -#define HFA384X_INFO_PSUSERCNT 0xF203 /* ? */ -#define HFA384X_INFO_KEYIDCHANGED 0xF204 /* ? */ - -enum { HFA384X_LINKSTATUS_CONNECTED = 1, - HFA384X_LINKSTATUS_DISCONNECTED = 2, - HFA384X_LINKSTATUS_AP_CHANGE = 3, - HFA384X_LINKSTATUS_AP_OUT_OF_RANGE = 4, - HFA384X_LINKSTATUS_AP_IN_RANGE = 5, - HFA384X_LINKSTATUS_ASSOC_FAILED = 6 }; - -enum { HFA384X_PORTTYPE_BSS = 1, HFA384X_PORTTYPE_WDS = 2, - HFA384X_PORTTYPE_PSEUDO_IBSS = 3, HFA384X_PORTTYPE_IBSS = 0, - HFA384X_PORTTYPE_HOSTAP = 6 }; - -#define HFA384X_RATES_1MBPS BIT(0) -#define HFA384X_RATES_2MBPS BIT(1) -#define HFA384X_RATES_5MBPS BIT(2) -#define HFA384X_RATES_11MBPS BIT(3) - -#define HFA384X_ROAMING_FIRMWARE 1 -#define HFA384X_ROAMING_HOST 2 -#define HFA384X_ROAMING_DISABLED 3 - -#define HFA384X_WEPFLAGS_PRIVACYINVOKED BIT(0) -#define HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED BIT(1) -#define HFA384X_WEPFLAGS_HOSTENCRYPT BIT(4) -#define HFA384X_WEPFLAGS_HOSTDECRYPT BIT(7) - -#define HFA384X_RX_STATUS_MSGTYPE (BIT(15) | BIT(14) | BIT(13)) -#define HFA384X_RX_STATUS_PCF BIT(12) -#define HFA384X_RX_STATUS_MACPORT (BIT(10) | BIT(9) | BIT(8)) -#define HFA384X_RX_STATUS_UNDECR BIT(1) -#define HFA384X_RX_STATUS_FCSERR BIT(0) - -#define HFA384X_RX_STATUS_GET_MSGTYPE(s) \ -(((s) & HFA384X_RX_STATUS_MSGTYPE) >> 13) -#define HFA384X_RX_STATUS_GET_MACPORT(s) \ -(((s) & HFA384X_RX_STATUS_MACPORT) >> 8) - -enum { HFA384X_RX_MSGTYPE_NORMAL = 0, HFA384X_RX_MSGTYPE_RFC1042 = 1, - HFA384X_RX_MSGTYPE_BRIDGETUNNEL = 2, HFA384X_RX_MSGTYPE_MGMT = 4 }; - - -#define HFA384X_TX_CTRL_ALT_RTRY BIT(5) -#define HFA384X_TX_CTRL_802_11 BIT(3) -#define HFA384X_TX_CTRL_802_3 0 -#define HFA384X_TX_CTRL_TX_EX BIT(2) -#define HFA384X_TX_CTRL_TX_OK BIT(1) - -#define HFA384X_TX_STATUS_RETRYERR BIT(0) -#define HFA384X_TX_STATUS_AGEDERR BIT(1) -#define HFA384X_TX_STATUS_DISCON BIT(2) -#define HFA384X_TX_STATUS_FORMERR BIT(3) - -/* HFA3861/3863 (BBP) Control Registers */ -#define HFA386X_CR_TX_CONFIGURE 0x12 /* CR9 */ -#define HFA386X_CR_RX_CONFIGURE 0x14 /* CR10 */ -#define HFA386X_CR_A_D_TEST_MODES2 0x1A /* CR13 */ -#define HFA386X_CR_MANUAL_TX_POWER 0x3E /* CR31 */ -#define HFA386X_CR_MEASURED_TX_POWER 0x74 /* CR58 */ - - -#ifdef __KERNEL__ - -#define PRISM2_TXFID_COUNT 8 -#define PRISM2_DATA_MAXLEN 2304 -#define PRISM2_TXFID_LEN (PRISM2_DATA_MAXLEN + sizeof(struct hfa384x_tx_frame)) -#define PRISM2_TXFID_EMPTY 0xffff -#define PRISM2_TXFID_RESERVED 0xfffe -#define PRISM2_DUMMY_FID 0xffff -#define MAX_SSID_LEN 32 -#define MAX_NAME_LEN 32 /* this is assumed to be equal to MAX_SSID_LEN */ - -#define PRISM2_DUMP_RX_HDR BIT(0) -#define PRISM2_DUMP_TX_HDR BIT(1) -#define PRISM2_DUMP_TXEXC_HDR BIT(2) - -struct hostap_tx_callback_info { - u16 idx; - void (*func)(struct sk_buff *, int ok, void *); - void *data; - struct hostap_tx_callback_info *next; -}; - - -/* IEEE 802.11 requires that STA supports concurrent reception of at least - * three fragmented frames. This define can be increased to support more - * concurrent frames, but it should be noted that each entry can consume about - * 2 kB of RAM and increasing cache size will slow down frame reassembly. */ -#define PRISM2_FRAG_CACHE_LEN 4 - -struct prism2_frag_entry { - unsigned long first_frag_time; - unsigned int seq; - unsigned int last_frag; - struct sk_buff *skb; - u8 src_addr[ETH_ALEN]; - u8 dst_addr[ETH_ALEN]; -}; - - -struct hostap_cmd_queue { - struct list_head list; - wait_queue_head_t compl; - volatile enum { CMD_SLEEP, CMD_CALLBACK, CMD_COMPLETED } type; - void (*callback)(struct net_device *dev, long context, u16 resp0, - u16 res); - long context; - u16 cmd, param0, param1; - u16 resp0, res; - volatile int issued, issuing; - - refcount_t usecnt; - int del_req; -}; - -/* options for hw_shutdown */ -#define HOSTAP_HW_NO_DISABLE BIT(0) -#define HOSTAP_HW_ENABLE_CMDCOMPL BIT(1) - -typedef struct local_info local_info_t; - -struct prism2_helper_functions { - /* these functions are defined in hardware model specific files - * (hostap_{cs,plx,pci}.c */ - int (*card_present)(local_info_t *local); - void (*cor_sreset)(local_info_t *local); - void (*genesis_reset)(local_info_t *local, int hcr); - - /* the following functions are from hostap_hw.c, but they may have some - * hardware model specific code */ - - /* FIX: low-level commands like cmd might disappear at some point to - * make it easier to change them if needed (e.g., cmd would be replaced - * with write_mif/read_mif/testcmd/inquire); at least get_rid and - * set_rid might move to hostap_{cs,plx,pci}.c */ - int (*cmd)(struct net_device *dev, u16 cmd, u16 param0, u16 *param1, - u16 *resp0); - void (*read_regs)(struct net_device *dev, struct hfa384x_regs *regs); - int (*get_rid)(struct net_device *dev, u16 rid, void *buf, int len, - int exact_len); - int (*set_rid)(struct net_device *dev, u16 rid, void *buf, int len); - int (*hw_enable)(struct net_device *dev, int initial); - int (*hw_config)(struct net_device *dev, int initial); - void (*hw_reset)(struct net_device *dev); - void (*hw_shutdown)(struct net_device *dev, int no_disable); - int (*reset_port)(struct net_device *dev); - void (*schedule_reset)(local_info_t *local); - int (*download)(local_info_t *local, - struct prism2_download_param *param); - int (*tx)(struct sk_buff *skb, struct net_device *dev); - int (*set_tim)(struct net_device *dev, int aid, int set); - const struct proc_ops *read_aux_proc_ops; - - int need_tx_headroom; /* number of bytes of headroom needed before - * IEEE 802.11 header */ - enum { HOSTAP_HW_PCCARD, HOSTAP_HW_PLX, HOSTAP_HW_PCI } hw_type; -}; - - -struct prism2_download_data { - u32 dl_cmd; - u32 start_addr; - u32 num_areas; - struct prism2_download_data_area { - u32 addr; /* wlan card address */ - u32 len; - u8 *data; /* allocated data */ - } data[] __counted_by(num_areas); -}; - - -#define HOSTAP_MAX_BSS_COUNT 64 -#define MAX_WPA_IE_LEN 64 - -struct hostap_bss_info { - struct list_head list; - unsigned long last_update; - unsigned int count; - u8 bssid[ETH_ALEN]; - u16 capab_info; - u8 ssid[32]; - size_t ssid_len; - u8 wpa_ie[MAX_WPA_IE_LEN]; - size_t wpa_ie_len; - u8 rsn_ie[MAX_WPA_IE_LEN]; - size_t rsn_ie_len; - int chan; - int included; -}; - - -/* Per radio private Host AP data - shared by all net devices interfaces used - * by each radio (wlan#, wlan#ap, wlan#sta, WDS). - * ((struct hostap_interface *) netdev_priv(dev))->local points to this - * structure. */ -struct local_info { - struct module *hw_module; - int card_idx; - int dev_enabled; - int master_dev_auto_open; /* was master device opened automatically */ - int num_dev_open; /* number of open devices */ - struct net_device *dev; /* master radio device */ - struct net_device *ddev; /* main data device */ - struct list_head hostap_interfaces; /* Host AP interface list (contains - * struct hostap_interface entries) - */ - rwlock_t iface_lock; /* hostap_interfaces read lock; use write lock - * when removing entries from the list. - * TX and RX paths can use read lock. */ - spinlock_t cmdlock, baplock, lock, irq_init_lock; - struct mutex rid_bap_mtx; - u16 infofid; /* MAC buffer id for info frame */ - /* txfid, intransmitfid, next_txtid, and next_alloc are protected by - * txfidlock */ - spinlock_t txfidlock; - int txfid_len; /* length of allocated TX buffers */ - u16 txfid[PRISM2_TXFID_COUNT]; /* buffer IDs for TX frames */ - /* buffer IDs for intransmit frames or PRISM2_TXFID_EMPTY if - * corresponding txfid is free for next TX frame */ - u16 intransmitfid[PRISM2_TXFID_COUNT]; - int next_txfid; /* index to the next txfid to be checked for - * availability */ - int next_alloc; /* index to the next intransmitfid to be checked for - * allocation events */ - - /* bitfield for atomic bitops */ -#define HOSTAP_BITS_TRANSMIT 0 -#define HOSTAP_BITS_BAP_TASKLET 1 -#define HOSTAP_BITS_BAP_TASKLET2 2 - unsigned long bits; - - struct ap_data *ap; - - char essid[MAX_SSID_LEN + 1]; - char name[MAX_NAME_LEN + 1]; - int name_set; - u16 channel_mask; /* mask of allowed channels */ - u16 scan_channel_mask; /* mask of channels to be scanned */ - struct comm_tallies_sums comm_tallies; - struct proc_dir_entry *proc; - int iw_mode; /* operating mode (IW_MODE_*) */ - int pseudo_adhoc; /* 0: IW_MODE_ADHOC is real 802.11 compliant IBSS - * 1: IW_MODE_ADHOC is "pseudo IBSS" */ - char bssid[ETH_ALEN]; - int channel; - int beacon_int; - int dtim_period; - int mtu; - int frame_dump; /* dump RX/TX frame headers, PRISM2_DUMP_ flags */ - int fw_tx_rate_control; - u16 tx_rate_control; - u16 basic_rates; - int hw_resetting; - int hw_ready; - int hw_reset_tries; /* how many times reset has been tried */ - int hw_downloading; - int shutdown; - int pri_only; - int no_pri; /* no PRI f/w present */ - int sram_type; /* 8 = x8 SRAM, 16 = x16 SRAM, -1 = unknown */ - - enum { - PRISM2_TXPOWER_AUTO = 0, PRISM2_TXPOWER_OFF, - PRISM2_TXPOWER_FIXED, PRISM2_TXPOWER_UNKNOWN - } txpower_type; - int txpower; /* if txpower_type == PRISM2_TXPOWER_FIXED */ - - /* command queue for hfa384x_cmd(); protected with cmdlock */ - struct list_head cmd_queue; - /* max_len for cmd_queue; in addition, cmd_callback can use two - * additional entries to prevent sleeping commands from stopping - * transmits */ -#define HOSTAP_CMD_QUEUE_MAX_LEN 16 - int cmd_queue_len; /* number of entries in cmd_queue */ - - /* if card timeout is detected in interrupt context, reset_queue is - * used to schedule card reseting to be done in user context */ - struct work_struct reset_queue; - - /* For scheduling a change of the promiscuous mode RID */ - int is_promisc; - struct work_struct set_multicast_list_queue; - - struct work_struct set_tim_queue; - struct list_head set_tim_list; - spinlock_t set_tim_lock; - - int wds_max_connections; - int wds_connections; -#define HOSTAP_WDS_BROADCAST_RA BIT(0) -#define HOSTAP_WDS_AP_CLIENT BIT(1) -#define HOSTAP_WDS_STANDARD_FRAME BIT(2) - u32 wds_type; - u16 tx_control; /* flags to be used in TX description */ - int manual_retry_count; /* -1 = use f/w default; otherwise retry count - * to be used with all frames */ - - struct iw_statistics wstats; - unsigned long scan_timestamp; /* Time started to scan */ - enum { - PRISM2_MONITOR_80211 = 0, PRISM2_MONITOR_PRISM = 1, - PRISM2_MONITOR_CAPHDR = 2, PRISM2_MONITOR_RADIOTAP = 3 - } monitor_type; - int monitor_allow_fcserr; - - int hostapd; /* whether user space daemon, hostapd, is used for AP - * management */ - int hostapd_sta; /* whether hostapd is used with an extra STA interface - */ - struct net_device *apdev; - struct net_device_stats apdevstats; - - char assoc_ap_addr[ETH_ALEN]; - struct net_device *stadev; - struct net_device_stats stadevstats; - -#define WEP_KEYS 4 -#define WEP_KEY_LEN 13 - struct lib80211_crypt_info crypt_info; - - int open_wep; /* allow unencrypted frames */ - int host_encrypt; - int host_decrypt; - int privacy_invoked; /* force privacy invoked flag even if no keys are - * configured */ - int fw_encrypt_ok; /* whether firmware-based WEP encrypt is working - * in Host AP mode (STA f/w 1.4.9 or newer) */ - int bcrx_sta_key; /* use individual keys to override default keys even - * with RX of broad/multicast frames */ - - struct prism2_frag_entry frag_cache[PRISM2_FRAG_CACHE_LEN]; - unsigned int frag_next_idx; - - int ieee_802_1x; /* is IEEE 802.1X used */ - - int antsel_tx, antsel_rx; - int rts_threshold; /* dot11RTSThreshold */ - int fragm_threshold; /* dot11FragmentationThreshold */ - int auth_algs; /* PRISM2_AUTH_ flags */ - - int enh_sec; /* cnfEnhSecurity options (broadcast SSID hide/ignore) */ - int tallies32; /* 32-bit tallies in use */ - - struct prism2_helper_functions *func; - - u8 *pda; - int fw_ap; -#define PRISM2_FW_VER(major, minor, variant) \ -(((major) << 16) | ((minor) << 8) | variant) - u32 sta_fw_ver; - - /* Tasklets for handling hardware IRQ related operations outside hw IRQ - * handler */ - struct tasklet_struct bap_tasklet; - - struct tasklet_struct info_tasklet; - struct sk_buff_head info_list; /* info frames as skb's for - * info_tasklet */ - - struct hostap_tx_callback_info *tx_callback; /* registered TX callbacks - */ - - struct tasklet_struct rx_tasklet; - struct sk_buff_head rx_list; - - struct tasklet_struct sta_tx_exc_tasklet; - struct sk_buff_head sta_tx_exc_list; - - int host_roaming; - unsigned long last_join_time; /* time of last JoinRequest */ - struct hfa384x_hostscan_result *last_scan_results; - int last_scan_results_count; - enum { PRISM2_SCAN, PRISM2_HOSTSCAN } last_scan_type; - struct work_struct info_queue; - unsigned long pending_info; /* bit field of pending info_queue items */ -#define PRISM2_INFO_PENDING_LINKSTATUS 0 -#define PRISM2_INFO_PENDING_SCANRESULTS 1 - int prev_link_status; /* previous received LinkStatus info */ - int prev_linkstatus_connected; - u8 preferred_ap[ETH_ALEN]; /* use this AP if possible */ - -#ifdef PRISM2_CALLBACK - void *callback_data; /* Can be used in callbacks; e.g., allocate - * on enable event and free on disable event. - * Host AP driver code does not touch this. */ -#endif /* PRISM2_CALLBACK */ - - wait_queue_head_t hostscan_wq; - - /* Passive scan in Host AP mode */ - struct timer_list passive_scan_timer; - int passive_scan_interval; /* in seconds, 0 = disabled */ - int passive_scan_channel; - enum { PASSIVE_SCAN_WAIT, PASSIVE_SCAN_LISTEN } passive_scan_state; - - struct timer_list tick_timer; - unsigned long last_tick_timer; - unsigned int sw_tick_stuck; - - /* commsQuality / dBmCommsQuality data from periodic polling; only - * valid for Managed and Ad-hoc modes */ - unsigned long last_comms_qual_update; - int comms_qual; /* in some odd unit.. */ - int avg_signal; /* in dB (note: negative) */ - int avg_noise; /* in dB (note: negative) */ - struct work_struct comms_qual_update; - - /* RSSI to dBm adjustment (for RX descriptor fields) */ - int rssi_to_dBm; /* subtract from RSSI to get approximate dBm value */ - - /* BSS list / protected by local->lock */ - struct list_head bss_list; - int num_bss_info; - int wpa; /* WPA support enabled */ - int tkip_countermeasures; - int drop_unencrypted; - /* Generic IEEE 802.11 info element to be added to - * ProbeResp/Beacon/(Re)AssocReq */ - u8 *generic_elem; - size_t generic_elem_len; - -#ifdef PRISM2_DOWNLOAD_SUPPORT - /* Persistent volatile download data */ - struct prism2_download_data *dl_pri; - struct prism2_download_data *dl_sec; -#endif /* PRISM2_DOWNLOAD_SUPPORT */ - -#ifdef PRISM2_IO_DEBUG -#define PRISM2_IO_DEBUG_SIZE 10000 - u32 io_debug[PRISM2_IO_DEBUG_SIZE]; - int io_debug_head; - int io_debug_enabled; -#endif /* PRISM2_IO_DEBUG */ - - /* Pointer to hardware model specific (cs,pci,plx) private data. */ - void *hw_priv; -}; - - -/* Per interface private Host AP data - * Allocated for each net device that Host AP uses (wlan#, wlan#ap, wlan#sta, - * WDS) and netdev_priv(dev) points to this structure. */ -struct hostap_interface { - struct list_head list; /* list entry in Host AP interface list */ - struct net_device *dev; /* pointer to this device */ - struct local_info *local; /* pointer to shared private data */ - struct net_device_stats stats; - struct iw_spy_data spy_data; /* iwspy support */ - struct iw_public_data wireless_data; - - enum { - HOSTAP_INTERFACE_MASTER, - HOSTAP_INTERFACE_MAIN, - HOSTAP_INTERFACE_AP, - HOSTAP_INTERFACE_STA, - HOSTAP_INTERFACE_WDS, - } type; - - union { - struct hostap_interface_wds { - u8 remote_addr[ETH_ALEN]; - } wds; - } u; -}; - - -#define HOSTAP_SKB_TX_DATA_MAGIC 0xf08a36a2 - -/* - * TX meta data - stored in skb->cb buffer, so this must not be increased over - * the 48-byte limit. - * THE PADDING THIS STARTS WITH IS A HORRIBLE HACK THAT SHOULD NOT LIVE - * TO SEE THE DAY. - */ -struct hostap_skb_tx_data { - unsigned int __padding_for_default_qdiscs; - u32 magic; /* HOSTAP_SKB_TX_DATA_MAGIC */ - u8 rate; /* transmit rate */ -#define HOSTAP_TX_FLAGS_WDS BIT(0) -#define HOSTAP_TX_FLAGS_BUFFERED_FRAME BIT(1) -#define HOSTAP_TX_FLAGS_ADD_MOREDATA BIT(2) - u8 flags; /* HOSTAP_TX_FLAGS_* */ - u16 tx_cb_idx; - struct hostap_interface *iface; - unsigned long jiffies; /* queueing timestamp */ - unsigned short ethertype; -}; - - -#ifndef PRISM2_NO_DEBUG - -#define DEBUG_FID BIT(0) -#define DEBUG_PS BIT(1) -#define DEBUG_FLOW BIT(2) -#define DEBUG_AP BIT(3) -#define DEBUG_HW BIT(4) -#define DEBUG_EXTRA BIT(5) -#define DEBUG_EXTRA2 BIT(6) -#define DEBUG_PS2 BIT(7) -#define DEBUG_MASK (DEBUG_PS | DEBUG_AP | DEBUG_HW | DEBUG_EXTRA) -#define PDEBUG(n, args...) \ -do { if ((n) & DEBUG_MASK) printk(KERN_DEBUG args); } while (0) -#define PDEBUG2(n, args...) \ -do { if ((n) & DEBUG_MASK) printk(args); } while (0) - -#else /* PRISM2_NO_DEBUG */ - -#define PDEBUG(n, args...) -#define PDEBUG2(n, args...) - -#endif /* PRISM2_NO_DEBUG */ - -enum { BAP0 = 0, BAP1 = 1 }; - -#define PRISM2_IO_DEBUG_CMD_INB 0 -#define PRISM2_IO_DEBUG_CMD_INW 1 -#define PRISM2_IO_DEBUG_CMD_INSW 2 -#define PRISM2_IO_DEBUG_CMD_OUTB 3 -#define PRISM2_IO_DEBUG_CMD_OUTW 4 -#define PRISM2_IO_DEBUG_CMD_OUTSW 5 -#define PRISM2_IO_DEBUG_CMD_ERROR 6 -#define PRISM2_IO_DEBUG_CMD_INTERRUPT 7 - -#ifdef PRISM2_IO_DEBUG - -#define PRISM2_IO_DEBUG_ENTRY(cmd, reg, value) \ -(((cmd) << 24) | ((reg) << 16) | value) - -static inline void prism2_io_debug_add(struct net_device *dev, int cmd, - int reg, int value) -{ - struct hostap_interface *iface = netdev_priv(dev); - local_info_t *local = iface->local; - - if (!local->io_debug_enabled) - return; - - local->io_debug[local->io_debug_head] = jiffies & 0xffffffff; - if (++local->io_debug_head >= PRISM2_IO_DEBUG_SIZE) - local->io_debug_head = 0; - local->io_debug[local->io_debug_head] = - PRISM2_IO_DEBUG_ENTRY(cmd, reg, value); - if (++local->io_debug_head >= PRISM2_IO_DEBUG_SIZE) - local->io_debug_head = 0; -} - - -static inline void prism2_io_debug_error(struct net_device *dev, int err) -{ - struct hostap_interface *iface = netdev_priv(dev); - local_info_t *local = iface->local; - unsigned long flags; - - if (!local->io_debug_enabled) - return; - - spin_lock_irqsave(&local->lock, flags); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_ERROR, 0, err); - if (local->io_debug_enabled == 1) { - local->io_debug_enabled = 0; - printk(KERN_DEBUG "%s: I/O debug stopped\n", dev->name); - } - spin_unlock_irqrestore(&local->lock, flags); -} - -#else /* PRISM2_IO_DEBUG */ - -static inline void prism2_io_debug_add(struct net_device *dev, int cmd, - int reg, int value) -{ -} - -static inline void prism2_io_debug_error(struct net_device *dev, int err) -{ -} - -#endif /* PRISM2_IO_DEBUG */ - - -#ifdef PRISM2_CALLBACK -enum { - /* Called when card is enabled */ - PRISM2_CALLBACK_ENABLE, - - /* Called when card is disabled */ - PRISM2_CALLBACK_DISABLE, - - /* Called when RX/TX starts/ends */ - PRISM2_CALLBACK_RX_START, PRISM2_CALLBACK_RX_END, - PRISM2_CALLBACK_TX_START, PRISM2_CALLBACK_TX_END -}; -void prism2_callback(local_info_t *local, int event); -#else /* PRISM2_CALLBACK */ -#define prism2_callback(d, e) do { } while (0) -#endif /* PRISM2_CALLBACK */ - -#endif /* __KERNEL__ */ - -#endif /* HOSTAP_WLAN_H */ diff --git a/drivers/net/wireless/intersil/orinoco/Kconfig b/drivers/net/wireless/intersil/orinoco/Kconfig deleted file mode 100644 index f62730aa7be30..0000000000000 --- a/drivers/net/wireless/intersil/orinoco/Kconfig +++ /dev/null @@ -1,143 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config HERMES - tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)" - depends on (PPC_PMAC || PCI || PCMCIA) - depends on CFG80211 - select CFG80211_WEXT_EXPORT - select WIRELESS_EXT - select WEXT_SPY - select WEXT_PRIV - select FW_LOADER - select CRYPTO - select CRYPTO_MICHAEL_MIC - help - A driver for 802.11b wireless cards based on the "Hermes" or - Intersil HFA384x (Prism 2) MAC controller. This includes the vast - majority of the PCMCIA 802.11b cards (which are nearly all rebadges) - - except for the Cisco/Aironet cards. Cards supported include the - Apple Airport (not a PCMCIA card), WavelanIEEE/Orinoco, - Cabletron/EnteraSys Roamabout, ELSA AirLancer, MELCO Buffalo, Avaya, - IBM High Rate Wireless, Farralon Syyline, Samsung MagicLAN, Netgear - MA401, LinkSys WPC-11, D-Link DWL-650, 3Com AirConnect, Intel - IPW2011, and Symbol Spectrum24 High Rate amongst others. - - This option includes the guts of the driver, but in order to - actually use a card you will also need to enable support for PCMCIA - Hermes cards, PLX9052 based PCI adaptors or the Apple Airport below. - - You will also very likely also need the Wireless Tools in order to - configure your card and that /etc/pcmcia/wireless.opts works : - - -config HERMES_PRISM - bool "Support Prism 2/2.5 chipset" - depends on HERMES - help - - Say Y to enable support for Prism 2 and 2.5 chipsets. These - chipsets are better handled by the hostap driver. This driver - would not support WPA or firmware download for Prism chipset. - - If you are not sure, say N. - -config HERMES_CACHE_FW_ON_INIT - bool "Cache Hermes firmware on driver initialisation" - depends on HERMES - default y - help - Say Y to cache any firmware required by the Hermes drivers - on startup. The firmware will remain cached until the - driver is unloaded. The cache uses 64K of RAM. - - Otherwise load the firmware from userspace as required. In - this case the driver should be unloaded and restarted - whenever the firmware is changed. - - If you are not sure, say Y. - -config APPLE_AIRPORT - tristate "Apple Airport support (built-in)" - depends on PPC_PMAC && HERMES - help - Say Y here to support the Airport 802.11b wireless Ethernet hardware - built into the Macintosh iBook and other recent PowerPC-based - Macintosh machines. This is essentially a Lucent Orinoco card with - a non-standard interface. - - This driver does not support the Airport Extreme (802.11b/g). Use - the BCM43xx driver for Airport Extreme cards. - -config PLX_HERMES - tristate "Hermes in PLX9052 based PCI adaptor support (Netgear MA301 etc.)" - depends on PCI && HERMES - help - Enable support for PCMCIA cards supported by the "Hermes" (aka - orinoco) driver when used in PLX9052 based PCI adaptors. These - adaptors are not a full PCMCIA controller but act as a more limited - PCI <-> PCMCIA bridge. Several vendors sell such adaptors so that - 802.11b PCMCIA cards can be used in desktop machines. The Netgear - MA301 is such an adaptor. - -config TMD_HERMES - tristate "Hermes in TMD7160 based PCI adaptor support" - depends on PCI && HERMES - help - Enable support for PCMCIA cards supported by the "Hermes" (aka - orinoco) driver when used in TMD7160 based PCI adaptors. These - adaptors are not a full PCMCIA controller but act as a more limited - PCI <-> PCMCIA bridge. Several vendors sell such adaptors so that - 802.11b PCMCIA cards can be used in desktop machines. - -config NORTEL_HERMES - tristate "Nortel emobility PCI adaptor support" - depends on PCI && HERMES - help - Enable support for PCMCIA cards supported by the "Hermes" (aka - orinoco) driver when used in Nortel emobility PCI adaptors. These - adaptors are not full PCMCIA controllers, but act as a more limited - PCI <-> PCMCIA bridge. - -config PCI_HERMES - tristate "Prism 2.5 PCI 802.11b adaptor support" - depends on PCI && HERMES && HERMES_PRISM - help - Enable support for PCI and mini-PCI 802.11b wireless NICs based on - the Prism 2.5 chipset. These are true PCI cards, not the 802.11b - PCMCIA cards bundled with PCI<->PCMCIA adaptors which are also - common. Some of the built-in wireless adaptors in laptops are of - this variety. - -config PCMCIA_HERMES - tristate "Hermes PCMCIA card support" - depends on PCMCIA && HERMES && HAS_IOPORT_MAP - help - A driver for "Hermes" chipset based PCMCIA wireless adaptors, such - as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ - EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and - others). It should also be usable on various Prism II based cards - such as the Linksys, D-Link and Farallon Skyline. It should also - work on Symbol cards such as the 3Com AirConnect and Ericsson WLAN. - - You will very likely need the Wireless Tools in order to - configure your card and that /etc/pcmcia/wireless.opts works: - . - -config PCMCIA_SPECTRUM - tristate "Symbol Spectrum24 Trilogy PCMCIA card support" - depends on PCMCIA && HERMES && HAS_IOPORT_MAP - help - - This is a driver for 802.11b cards using RAM-loadable Symbol - firmware, such as Symbol Wireless Networker LA4100, CompactFlash - cards by Socket Communications and Intel PRO/Wireless 2011B. - - This driver requires firmware download on startup. Utilities - for downloading Symbol firmware are available at - - -config ORINOCO_USB - tristate "Agere Orinoco USB support" - depends on USB && HERMES - select FW_LOADER - help - This driver is for USB versions of the Agere Orinoco card. diff --git a/drivers/net/wireless/intersil/orinoco/Makefile b/drivers/net/wireless/intersil/orinoco/Makefile deleted file mode 100644 index 0c29c56c88d6d..0000000000000 --- a/drivers/net/wireless/intersil/orinoco/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for the orinoco wireless device drivers. -# -orinoco-objs := main.o fw.o hw.o mic.o scan.o wext.o hermes_dld.o hermes.o cfg.o - -obj-$(CONFIG_HERMES) += orinoco.o -obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o -obj-$(CONFIG_APPLE_AIRPORT) += airport.o -obj-$(CONFIG_PLX_HERMES) += orinoco_plx.o -obj-$(CONFIG_PCI_HERMES) += orinoco_pci.o -obj-$(CONFIG_TMD_HERMES) += orinoco_tmd.o -obj-$(CONFIG_NORTEL_HERMES) += orinoco_nortel.o -obj-$(CONFIG_PCMCIA_SPECTRUM) += spectrum_cs.o -obj-$(CONFIG_ORINOCO_USB) += orinoco_usb.o diff --git a/drivers/net/wireless/intersil/orinoco/airport.c b/drivers/net/wireless/intersil/orinoco/airport.c deleted file mode 100644 index 45ac00fdafa58..0000000000000 --- a/drivers/net/wireless/intersil/orinoco/airport.c +++ /dev/null @@ -1,268 +0,0 @@ -/* airport.c - * - * A driver for "Hermes" chipset based Apple Airport wireless - * card. - * - * Copyright notice & release notes in file main.c - * - * Note specific to airport stub: - * - * 0.05 : first version of the new split driver - * 0.06 : fix possible hang on powerup, add sleep support - */ - -#define DRIVER_NAME "airport" -#define PFX DRIVER_NAME ": " - -#include -#include -#include -#include -#include -#include - -#include "orinoco.h" - -#define AIRPORT_IO_LEN (0x1000) /* one page */ - -struct airport { - struct macio_dev *mdev; - void __iomem *vaddr; - unsigned int irq; - int irq_requested; - int ndev_registered; -}; - -static int -airport_suspend(struct macio_dev *mdev, pm_message_t state) -{ - struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev); - struct net_device *dev = priv->ndev; - struct airport *card = priv->card; - unsigned long flags; - int err; - - printk(KERN_DEBUG "%s: Airport entering sleep mode\n", dev->name); - - err = orinoco_lock(priv, &flags); - if (err) { - printk(KERN_ERR "%s: hw_unavailable on PBOOK_SLEEP_NOW\n", - dev->name); - return 0; - } - - orinoco_down(priv); - orinoco_unlock(priv, &flags); - - disable_irq(card->irq); - pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, - macio_get_of_node(mdev), 0, 0); - - return 0; -} - -static int -airport_resume(struct macio_dev *mdev) -{ - struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev); - struct net_device *dev = priv->ndev; - struct airport *card = priv->card; - unsigned long flags; - int err; - - printk(KERN_DEBUG "%s: Airport waking up\n", dev->name); - - pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, - macio_get_of_node(mdev), 0, 1); - msleep(200); - - enable_irq(card->irq); - - priv->hw.ops->lock_irqsave(&priv->lock, &flags); - err = orinoco_up(priv); - priv->hw.ops->unlock_irqrestore(&priv->lock, &flags); - - return err; -} - -static int -airport_detach(struct macio_dev *mdev) -{ - struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev); - struct airport *card = priv->card; - - if (card->ndev_registered) - orinoco_if_del(priv); - card->ndev_registered = 0; - - if (card->irq_requested) - free_irq(card->irq, priv); - card->irq_requested = 0; - - if (card->vaddr) - iounmap(card->vaddr); - card->vaddr = NULL; - - macio_release_resource(mdev, 0); - - pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, - macio_get_of_node(mdev), 0, 0); - ssleep(1); - - macio_set_drvdata(mdev, NULL); - free_orinocodev(priv); - - return 0; -} - -static int airport_hard_reset(struct orinoco_private *priv) -{ - /* It would be nice to power cycle the Airport for a real hard - * reset, but for some reason although it appears to - * re-initialize properly, it falls in a screaming heap - * shortly afterwards. */ -#if 0 - struct airport *card = priv->card; - - /* Vitally important. If we don't do this it seems we get an - * interrupt somewhere during the power cycle, since - * hw_unavailable is already set it doesn't get ACKed, we get - * into an interrupt loop and the PMU decides to turn us - * off. */ - disable_irq(card->irq); - - pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, - macio_get_of_node(card->mdev), 0, 0); - ssleep(1); - pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, - macio_get_of_node(card->mdev), 0, 1); - ssleep(1); - - enable_irq(card->irq); - ssleep(1); -#endif - - return 0; -} - -static int -airport_attach(struct macio_dev *mdev, const struct of_device_id *match) -{ - struct orinoco_private *priv; - struct airport *card; - unsigned long phys_addr; - struct hermes *hw; - - if (macio_resource_count(mdev) < 1 || macio_irq_count(mdev) < 1) { - printk(KERN_ERR PFX "Wrong interrupt/addresses in OF tree\n"); - return -ENODEV; - } - - /* Allocate space for private device-specific data */ - priv = alloc_orinocodev(sizeof(*card), &mdev->ofdev.dev, - airport_hard_reset, NULL); - if (!priv) { - printk(KERN_ERR PFX "Cannot allocate network device\n"); - return -ENODEV; - } - card = priv->card; - - hw = &priv->hw; - card->mdev = mdev; - - if (macio_request_resource(mdev, 0, DRIVER_NAME)) { - printk(KERN_ERR PFX "can't request IO resource !\n"); - free_orinocodev(priv); - return -EBUSY; - } - - macio_set_drvdata(mdev, priv); - - /* Setup interrupts & base address */ - card->irq = macio_irq(mdev, 0); - phys_addr = macio_resource_start(mdev, 0); /* Physical address */ - printk(KERN_DEBUG PFX "Physical address %lx\n", phys_addr); - card->vaddr = ioremap(phys_addr, AIRPORT_IO_LEN); - if (!card->vaddr) { - printk(KERN_ERR PFX "ioremap() failed\n"); - goto failed; - } - - hermes_struct_init(hw, card->vaddr, HERMES_16BIT_REGSPACING); - - /* Power up card */ - pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, - macio_get_of_node(mdev), 0, 1); - ssleep(1); - - /* Reset it before we get the interrupt */ - hw->ops->init(hw); - - if (request_irq(card->irq, orinoco_interrupt, 0, DRIVER_NAME, priv)) { - printk(KERN_ERR PFX "Couldn't get IRQ %d\n", card->irq); - goto failed; - } - card->irq_requested = 1; - - /* Initialise the main driver */ - if (orinoco_init(priv) != 0) { - printk(KERN_ERR PFX "orinoco_init() failed\n"); - goto failed; - } - - /* Register an interface with the stack */ - if (orinoco_if_add(priv, phys_addr, card->irq, NULL) != 0) { - printk(KERN_ERR PFX "orinoco_if_add() failed\n"); - goto failed; - } - card->ndev_registered = 1; - return 0; - failed: - airport_detach(mdev); - return -ENODEV; -} /* airport_attach */ - - -static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION - " (Benjamin Herrenschmidt )"; -MODULE_AUTHOR("Benjamin Herrenschmidt "); -MODULE_DESCRIPTION("Driver for the Apple Airport wireless card."); -MODULE_LICENSE("Dual MPL/GPL"); - -static const struct of_device_id airport_match[] = { - { - .name = "radio", - }, - {}, -}; - -MODULE_DEVICE_TABLE(of, airport_match); - -static struct macio_driver airport_driver = { - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - .of_match_table = airport_match, - }, - .probe = airport_attach, - .remove = airport_detach, - .suspend = airport_suspend, - .resume = airport_resume, -}; - -static int __init -init_airport(void) -{ - printk(KERN_DEBUG "%s\n", version); - - return macio_register_driver(&airport_driver); -} - -static void __exit -exit_airport(void) -{ - macio_unregister_driver(&airport_driver); -} - -module_init(init_airport); -module_exit(exit_airport); diff --git a/drivers/net/wireless/intersil/orinoco/cfg.c b/drivers/net/wireless/intersil/orinoco/cfg.c deleted file mode 100644 index b2d5ec8634b5d..0000000000000 --- a/drivers/net/wireless/intersil/orinoco/cfg.c +++ /dev/null @@ -1,291 +0,0 @@ -/* cfg80211 support - * - * See copyright notice in main.c - */ -#include -#include -#include "hw.h" -#include "main.h" -#include "orinoco.h" - -#include "cfg.h" - -/* Supported bitrates. Must agree with hw.c */ -static struct ieee80211_rate orinoco_rates[] = { - { .bitrate = 10 }, - { .bitrate = 20 }, - { .bitrate = 55 }, - { .bitrate = 110 }, -}; - -static const void * const orinoco_wiphy_privid = &orinoco_wiphy_privid; - -/* Called after orinoco_private is allocated. */ -void orinoco_wiphy_init(struct wiphy *wiphy) -{ - struct orinoco_private *priv = wiphy_priv(wiphy); - - wiphy->privid = orinoco_wiphy_privid; - - set_wiphy_dev(wiphy, priv->dev); -} - -/* Called after firmware is initialised */ -int orinoco_wiphy_register(struct wiphy *wiphy) -{ - struct orinoco_private *priv = wiphy_priv(wiphy); - int i, channels = 0; - - if (priv->firmware_type == FIRMWARE_TYPE_AGERE) - wiphy->max_scan_ssids = 1; - else - wiphy->max_scan_ssids = 0; - - wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); - - /* TODO: should we set if we only have demo ad-hoc? - * (priv->has_port3) - */ - if (priv->has_ibss) - wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC); - - if (!priv->broken_monitor || force_monitor) - wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); - - priv->band.bitrates = orinoco_rates; - priv->band.n_bitrates = ARRAY_SIZE(orinoco_rates); - - /* Only support channels allowed by the card EEPROM */ - for (i = 0; i < NUM_CHANNELS; i++) { - if (priv->channel_mask & (1 << i)) { - priv->channels[i].center_freq = - ieee80211_channel_to_frequency(i + 1, - NL80211_BAND_2GHZ); - channels++; - } - } - priv->band.channels = priv->channels; - priv->band.n_channels = channels; - - wiphy->bands[NL80211_BAND_2GHZ] = &priv->band; - wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; - - i = 0; - if (priv->has_wep) { - priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP40; - i++; - - if (priv->has_big_wep) { - priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP104; - i++; - } - } - if (priv->has_wpa) { - priv->cipher_suites[i] = WLAN_CIPHER_SUITE_TKIP; - i++; - } - wiphy->cipher_suites = priv->cipher_suites; - wiphy->n_cipher_suites = i; - - wiphy->rts_threshold = priv->rts_thresh; - if (!priv->has_mwo) - wiphy->frag_threshold = priv->frag_thresh + 1; - wiphy->retry_short = priv->short_retry_limit; - wiphy->retry_long = priv->long_retry_limit; - - return wiphy_register(wiphy); -} - -static int orinoco_change_vif(struct wiphy *wiphy, struct net_device *dev, - enum nl80211_iftype type, - struct vif_params *params) -{ - struct orinoco_private *priv = wiphy_priv(wiphy); - int err = 0; - unsigned long lock; - - if (orinoco_lock(priv, &lock) != 0) - return -EBUSY; - - switch (type) { - case NL80211_IFTYPE_ADHOC: - if (!priv->has_ibss && !priv->has_port3) - err = -EINVAL; - break; - - case NL80211_IFTYPE_STATION: - break; - - case NL80211_IFTYPE_MONITOR: - if (priv->broken_monitor && !force_monitor) { - wiphy_warn(wiphy, - "Monitor mode support is buggy in this firmware, not enabling\n"); - err = -EINVAL; - } - break; - - default: - err = -EINVAL; - } - - if (!err) { - priv->iw_mode = type; - set_port_type(priv); - err = orinoco_commit(priv); - } - - orinoco_unlock(priv, &lock); - - return err; -} - -static int orinoco_scan(struct wiphy *wiphy, - struct cfg80211_scan_request *request) -{ - struct orinoco_private *priv = wiphy_priv(wiphy); - int err; - - if (!request) - return -EINVAL; - - if (priv->scan_request && priv->scan_request != request) - return -EBUSY; - - priv->scan_request = request; - - err = orinoco_hw_trigger_scan(priv, request->ssids); - /* On error the we aren't processing the request */ - if (err) - priv->scan_request = NULL; - - return err; -} - -static int orinoco_set_monitor_channel(struct wiphy *wiphy, - struct cfg80211_chan_def *chandef) -{ - struct orinoco_private *priv = wiphy_priv(wiphy); - int err = 0; - unsigned long flags; - int channel; - - if (!chandef->chan) - return -EINVAL; - - if (cfg80211_get_chandef_type(chandef) != NL80211_CHAN_NO_HT) - return -EINVAL; - - if (chandef->chan->band != NL80211_BAND_2GHZ) - return -EINVAL; - - channel = ieee80211_frequency_to_channel(chandef->chan->center_freq); - - if ((channel < 1) || (channel > NUM_CHANNELS) || - !(priv->channel_mask & (1 << (channel - 1)))) - return -EINVAL; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - priv->channel = channel; - if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { - /* Fast channel change - no commit if successful */ - struct hermes *hw = &priv->hw; - err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST | - HERMES_TEST_SET_CHANNEL, - channel, NULL); - } - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_set_wiphy_params(struct wiphy *wiphy, u32 changed) -{ - struct orinoco_private *priv = wiphy_priv(wiphy); - int frag_value = -1; - int rts_value = -1; - int err = 0; - - if (changed & WIPHY_PARAM_RETRY_SHORT) { - /* Setting short retry not supported */ - err = -EINVAL; - } - - if (changed & WIPHY_PARAM_RETRY_LONG) { - /* Setting long retry not supported */ - err = -EINVAL; - } - - if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { - /* Set fragmentation */ - if (priv->has_mwo) { - if (wiphy->frag_threshold == -1) - frag_value = 0; - else { - printk(KERN_WARNING "%s: Fixed fragmentation " - "is not supported on this firmware. " - "Using MWO robust instead.\n", - priv->ndev->name); - frag_value = 1; - } - } else { - if (wiphy->frag_threshold == -1) - frag_value = 2346; - else if ((wiphy->frag_threshold < 257) || - (wiphy->frag_threshold > 2347)) - err = -EINVAL; - else - /* cfg80211 value is 257-2347 (odd only) - * orinoco rid has range 256-2346 (even only) */ - frag_value = wiphy->frag_threshold & ~0x1; - } - } - - if (changed & WIPHY_PARAM_RTS_THRESHOLD) { - /* Set RTS. - * - * Prism documentation suggests default of 2432, - * and a range of 0-3000. - * - * Current implementation uses 2347 as the default and - * the upper limit. - */ - - if (wiphy->rts_threshold == -1) - rts_value = 2347; - else if (wiphy->rts_threshold > 2347) - err = -EINVAL; - else - rts_value = wiphy->rts_threshold; - } - - if (!err) { - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - if (frag_value >= 0) { - if (priv->has_mwo) - priv->mwo_robust = frag_value; - else - priv->frag_thresh = frag_value; - } - if (rts_value >= 0) - priv->rts_thresh = rts_value; - - err = orinoco_commit(priv); - - orinoco_unlock(priv, &flags); - } - - return err; -} - -const struct cfg80211_ops orinoco_cfg_ops = { - .change_virtual_intf = orinoco_change_vif, - .set_monitor_channel = orinoco_set_monitor_channel, - .scan = orinoco_scan, - .set_wiphy_params = orinoco_set_wiphy_params, -}; diff --git a/drivers/net/wireless/intersil/orinoco/cfg.h b/drivers/net/wireless/intersil/orinoco/cfg.h deleted file mode 100644 index 3ddc96a06cd78..0000000000000 --- a/drivers/net/wireless/intersil/orinoco/cfg.h +++ /dev/null @@ -1,15 +0,0 @@ -/* cfg80211 support. - * - * See copyright notice in main.c - */ -#ifndef ORINOCO_CFG_H -#define ORINOCO_CFG_H - -#include - -extern const struct cfg80211_ops orinoco_cfg_ops; - -void orinoco_wiphy_init(struct wiphy *wiphy); -int orinoco_wiphy_register(struct wiphy *wiphy); - -#endif /* ORINOCO_CFG_H */ diff --git a/drivers/net/wireless/intersil/orinoco/fw.c b/drivers/net/wireless/intersil/orinoco/fw.c deleted file mode 100644 index 015af782881bf..0000000000000 --- a/drivers/net/wireless/intersil/orinoco/fw.c +++ /dev/null @@ -1,387 +0,0 @@ -/* Firmware file reading and download helpers - * - * See copyright notice in main.c - */ -#include -#include -#include -#include -#include - -#include "hermes.h" -#include "hermes_dld.h" -#include "orinoco.h" - -#include "fw.h" - -/* End markers (for Symbol firmware only) */ -#define TEXT_END 0x1A /* End of text header */ - -struct fw_info { - char *pri_fw; - char *sta_fw; - char *ap_fw; - u32 pda_addr; - u16 pda_size; -}; - -static const struct fw_info orinoco_fw[] = { - { NULL, "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 }, - { NULL, "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 }, - { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", NULL, 0x00003100, 512 } -}; -MODULE_FIRMWARE("agere_sta_fw.bin"); -MODULE_FIRMWARE("agere_ap_fw.bin"); -MODULE_FIRMWARE("prism_sta_fw.bin"); -MODULE_FIRMWARE("prism_ap_fw.bin"); -MODULE_FIRMWARE("symbol_sp24t_prim_fw"); -MODULE_FIRMWARE("symbol_sp24t_sec_fw"); - -/* Structure used to access fields in FW - * Make sure LE decoding macros are used - */ -struct orinoco_fw_header { - char hdr_vers[6]; /* ASCII string for header version */ - __le16 headersize; /* Total length of header */ - __le32 entry_point; /* NIC entry point */ - __le32 blocks; /* Number of blocks to program */ - __le32 block_offset; /* Offset of block data from eof header */ - __le32 pdr_offset; /* Offset to PDR data from eof header */ - __le32 pri_offset; /* Offset to primary plug data */ - __le32 compat_offset; /* Offset to compatibility data*/ - char signature[]; /* FW signature length headersize-20 */ -} __packed; - -/* Check the range of various header entries. Return a pointer to a - * description of the problem, or NULL if everything checks out. */ -static const char *validate_fw(const struct orinoco_fw_header *hdr, size_t len) -{ - u16 hdrsize; - - if (len < sizeof(*hdr)) - return "image too small"; - if (memcmp(hdr->hdr_vers, "HFW", 3) != 0) - return "format not recognised"; - - hdrsize = le16_to_cpu(hdr->headersize); - if (hdrsize > len) - return "bad headersize"; - if ((hdrsize + le32_to_cpu(hdr->block_offset)) > len) - return "bad block offset"; - if ((hdrsize + le32_to_cpu(hdr->pdr_offset)) > len) - return "bad PDR offset"; - if ((hdrsize + le32_to_cpu(hdr->pri_offset)) > len) - return "bad PRI offset"; - if ((hdrsize + le32_to_cpu(hdr->compat_offset)) > len) - return "bad compat offset"; - - /* TODO: consider adding a checksum or CRC to the firmware format */ - return NULL; -} - -#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP) -static inline const struct firmware * -orinoco_cached_fw_get(struct orinoco_private *priv, bool primary) -{ - if (primary) - return priv->cached_pri_fw; - else - return priv->cached_fw; -} -#else -#define orinoco_cached_fw_get(priv, primary) (NULL) -#endif - -/* Download either STA or AP firmware into the card. */ -static int -orinoco_dl_firmware(struct orinoco_private *priv, - const struct fw_info *fw, - int ap) -{ - /* Plug Data Area (PDA) */ - __le16 *pda; - - struct hermes *hw = &priv->hw; - const struct firmware *fw_entry; - const struct orinoco_fw_header *hdr; - const unsigned char *first_block; - const void *end; - const char *firmware; - const char *fw_err; - struct device *dev = priv->dev; - int err = 0; - - pda = kzalloc(fw->pda_size, GFP_KERNEL); - if (!pda) - return -ENOMEM; - - if (ap) - firmware = fw->ap_fw; - else - firmware = fw->sta_fw; - - dev_dbg(dev, "Attempting to download firmware %s\n", firmware); - - /* Read current plug data */ - err = hw->ops->read_pda(hw, pda, fw->pda_addr, fw->pda_size); - dev_dbg(dev, "Read PDA returned %d\n", err); - if (err) - goto free; - - if (!orinoco_cached_fw_get(priv, false)) { - err = request_firmware(&fw_entry, firmware, priv->dev); - - if (err) { - dev_err(dev, "Cannot find firmware %s\n", firmware); - err = -ENOENT; - goto free; - } - } else - fw_entry = orinoco_cached_fw_get(priv, false); - - hdr = (const struct orinoco_fw_header *) fw_entry->data; - - fw_err = validate_fw(hdr, fw_entry->size); - if (fw_err) { - dev_warn(dev, "Invalid firmware image detected (%s). " - "Aborting download\n", fw_err); - err = -EINVAL; - goto abort; - } - - /* Enable aux port to allow programming */ - err = hw->ops->program_init(hw, le32_to_cpu(hdr->entry_point)); - dev_dbg(dev, "Program init returned %d\n", err); - if (err != 0) - goto abort; - - /* Program data */ - first_block = (fw_entry->data + - le16_to_cpu(hdr->headersize) + - le32_to_cpu(hdr->block_offset)); - end = fw_entry->data + fw_entry->size; - - err = hermes_program(hw, first_block, end); - dev_dbg(dev, "Program returned %d\n", err); - if (err != 0) - goto abort; - - /* Update production data */ - first_block = (fw_entry->data + - le16_to_cpu(hdr->headersize) + - le32_to_cpu(hdr->pdr_offset)); - - err = hermes_apply_pda_with_defaults(hw, first_block, end, pda, - &pda[fw->pda_size / sizeof(*pda)]); - dev_dbg(dev, "Apply PDA returned %d\n", err); - if (err) - goto abort; - - /* Tell card we've finished */ - err = hw->ops->program_end(hw); - dev_dbg(dev, "Program end returned %d\n", err); - if (err != 0) - goto abort; - - /* Check if we're running */ - dev_dbg(dev, "hermes_present returned %d\n", hermes_present(hw)); - -abort: - /* If we requested the firmware, release it. */ - if (!orinoco_cached_fw_get(priv, false)) - release_firmware(fw_entry); - -free: - kfree(pda); - return err; -} - -/* - * Process a firmware image - stop the card, load the firmware, reset - * the card and make sure it responds. For the secondary firmware take - * care of the PDA - read it and then write it on top of the firmware. - */ -static int -symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw, - const unsigned char *image, const void *end, - int secondary) -{ - struct hermes *hw = &priv->hw; - int ret = 0; - const unsigned char *ptr; - const unsigned char *first_block; - - /* Plug Data Area (PDA) */ - __le16 *pda = NULL; - - /* Binary block begins after the 0x1A marker */ - ptr = image; - while (*ptr++ != TEXT_END); - first_block = ptr; - - /* Read the PDA from EEPROM */ - if (secondary) { - pda = kzalloc(fw->pda_size, GFP_KERNEL); - if (!pda) - return -ENOMEM; - - ret = hw->ops->read_pda(hw, pda, fw->pda_addr, fw->pda_size); - if (ret) - goto free; - } - - /* Stop the firmware, so that it can be safely rewritten */ - if (priv->stop_fw) { - ret = priv->stop_fw(priv, 1); - if (ret) - goto free; - } - - /* Program the adapter with new firmware */ - ret = hermes_program(hw, first_block, end); - if (ret) - goto free; - - /* Write the PDA to the adapter */ - if (secondary) { - size_t len = hermes_blocks_length(first_block, end); - ptr = first_block + len; - ret = hermes_apply_pda(hw, ptr, end, pda, - &pda[fw->pda_size / sizeof(*pda)]); - kfree(pda); - if (ret) - return ret; - } - - /* Run the firmware */ - if (priv->stop_fw) { - ret = priv->stop_fw(priv, 0); - if (ret) - return ret; - } - - /* Reset hermes chip and make sure it responds */ - ret = hw->ops->init(hw); - - /* hermes_reset() should return 0 with the secondary firmware */ - if (secondary && ret != 0) - return -ENODEV; - - /* And this should work with any firmware */ - if (!hermes_present(hw)) - return -ENODEV; - - return 0; - -free: - kfree(pda); - return ret; -} - - -/* - * Download the firmware into the card, this also does a PCMCIA soft - * reset on the card, to make sure it's in a sane state. - */ -static int -symbol_dl_firmware(struct orinoco_private *priv, - const struct fw_info *fw) -{ - struct device *dev = priv->dev; - int ret; - const struct firmware *fw_entry; - - if (!orinoco_cached_fw_get(priv, true)) { - if (request_firmware(&fw_entry, fw->pri_fw, priv->dev) != 0) { - dev_err(dev, "Cannot find firmware: %s\n", fw->pri_fw); - return -ENOENT; - } - } else - fw_entry = orinoco_cached_fw_get(priv, true); - - /* Load primary firmware */ - ret = symbol_dl_image(priv, fw, fw_entry->data, - fw_entry->data + fw_entry->size, 0); - - if (!orinoco_cached_fw_get(priv, true)) - release_firmware(fw_entry); - if (ret) { - dev_err(dev, "Primary firmware download failed\n"); - return ret; - } - - if (!orinoco_cached_fw_get(priv, false)) { - if (request_firmware(&fw_entry, fw->sta_fw, priv->dev) != 0) { - dev_err(dev, "Cannot find firmware: %s\n", fw->sta_fw); - return -ENOENT; - } - } else - fw_entry = orinoco_cached_fw_get(priv, false); - - /* Load secondary firmware */ - ret = symbol_dl_image(priv, fw, fw_entry->data, - fw_entry->data + fw_entry->size, 1); - if (!orinoco_cached_fw_get(priv, false)) - release_firmware(fw_entry); - if (ret) - dev_err(dev, "Secondary firmware download failed\n"); - - return ret; -} - -int orinoco_download(struct orinoco_private *priv) -{ - int err = 0; - /* Reload firmware */ - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: - /* case FIRMWARE_TYPE_INTERSIL: */ - err = orinoco_dl_firmware(priv, - &orinoco_fw[priv->firmware_type], 0); - break; - - case FIRMWARE_TYPE_SYMBOL: - err = symbol_dl_firmware(priv, - &orinoco_fw[priv->firmware_type]); - break; - case FIRMWARE_TYPE_INTERSIL: - break; - } - /* TODO: if we fail we probably need to reinitialise - * the driver */ - - return err; -} - -#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP) -void orinoco_cache_fw(struct orinoco_private *priv, int ap) -{ - const struct firmware *fw_entry = NULL; - const char *pri_fw; - const char *fw; - - pri_fw = orinoco_fw[priv->firmware_type].pri_fw; - if (ap) - fw = orinoco_fw[priv->firmware_type].ap_fw; - else - fw = orinoco_fw[priv->firmware_type].sta_fw; - - if (pri_fw) { - if (request_firmware(&fw_entry, pri_fw, priv->dev) == 0) - priv->cached_pri_fw = fw_entry; - } - - if (fw) { - if (request_firmware(&fw_entry, fw, priv->dev) == 0) - priv->cached_fw = fw_entry; - } -} - -void orinoco_uncache_fw(struct orinoco_private *priv) -{ - release_firmware(priv->cached_pri_fw); - release_firmware(priv->cached_fw); - priv->cached_pri_fw = NULL; - priv->cached_fw = NULL; -} -#endif diff --git a/drivers/net/wireless/intersil/orinoco/fw.h b/drivers/net/wireless/intersil/orinoco/fw.h deleted file mode 100644 index aca63e3c4b5b6..0000000000000 --- a/drivers/net/wireless/intersil/orinoco/fw.h +++ /dev/null @@ -1,21 +0,0 @@ -/* Firmware file reading and download helpers - * - * See copyright notice in main.c - */ -#ifndef _ORINOCO_FW_H_ -#define _ORINOCO_FW_H_ - -/* Forward declations */ -struct orinoco_private; - -int orinoco_download(struct orinoco_private *priv); - -#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP) -void orinoco_cache_fw(struct orinoco_private *priv, int ap); -void orinoco_uncache_fw(struct orinoco_private *priv); -#else -#define orinoco_cache_fw(priv, ap) do { } while (0) -#define orinoco_uncache_fw(priv) do { } while (0) -#endif - -#endif /* _ORINOCO_FW_H_ */ diff --git a/drivers/net/wireless/intersil/orinoco/hermes.c b/drivers/net/wireless/intersil/orinoco/hermes.c deleted file mode 100644 index 4888286727ff1..0000000000000 --- a/drivers/net/wireless/intersil/orinoco/hermes.c +++ /dev/null @@ -1,778 +0,0 @@ -/* hermes.c - * - * Driver core for the "Hermes" wireless MAC controller, as used in - * the Lucent Orinoco and Cabletron RoamAbout cards. It should also - * work on the hfa3841 and hfa3842 MAC controller chips used in the - * Prism II chipsets. - * - * This is not a complete driver, just low-level access routines for - * the MAC controller itself. - * - * Based on the prism2 driver from Absolute Value Systems' linux-wlan - * project, the Linux wvlan_cs driver, Lucent's HCF-Light - * (wvlan_hcf.c) library, and the NetBSD wireless driver (in no - * particular order). - * - * Copyright (C) 2000, David Gibson, Linuxcare Australia. - * (C) Copyright David Gibson, IBM Corp. 2001-2003. - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - */ - -#include -#include -#include -#include - -#include "hermes.h" - -/* These are maximum timeouts. Most often, card wil react much faster */ -#define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */ -#define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */ -#define CMD_COMPL_TIMEOUT (20000) /* in iterations of ~10us */ -#define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */ - -/* - * AUX port access. To unlock the AUX port write the access keys to the - * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL - * register. Then read it and make sure it's HERMES_AUX_ENABLED. - */ -#define HERMES_AUX_ENABLE 0x8000 /* Enable auxiliary port access */ -#define HERMES_AUX_DISABLE 0x4000 /* Disable to auxiliary port access */ -#define HERMES_AUX_ENABLED 0xC000 /* Auxiliary port is open */ -#define HERMES_AUX_DISABLED 0x0000 /* Auxiliary port is closed */ - -#define HERMES_AUX_PW0 0xFE01 -#define HERMES_AUX_PW1 0xDC23 -#define HERMES_AUX_PW2 0xBA45 - -/* HERMES_CMD_DOWNLD */ -#define HERMES_PROGRAM_DISABLE (0x0000 | HERMES_CMD_DOWNLD) -#define HERMES_PROGRAM_ENABLE_VOLATILE (0x0100 | HERMES_CMD_DOWNLD) -#define HERMES_PROGRAM_ENABLE_NON_VOLATILE (0x0200 | HERMES_CMD_DOWNLD) -#define HERMES_PROGRAM_NON_VOLATILE (0x0300 | HERMES_CMD_DOWNLD) - -/* - * Debugging helpers - */ - -#define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ %p: " , hw->iobase); \ - printk(stuff); } while (0) - -#undef HERMES_DEBUG -#ifdef HERMES_DEBUG - -#define DEBUG(lvl, stuff...) if ((lvl) <= HERMES_DEBUG) DMSG(stuff) - -#else /* ! HERMES_DEBUG */ - -#define DEBUG(lvl, stuff...) do { } while (0) - -#endif /* ! HERMES_DEBUG */ - -static const struct hermes_ops hermes_ops_local; - -/* - * Internal functions - */ - -/* Issue a command to the chip. Waiting for it to complete is the caller's - problem. - - Returns -EBUSY if the command register is busy, 0 on success. - - Callable from any context. -*/ -static int hermes_issue_cmd(struct hermes *hw, u16 cmd, u16 param0, - u16 param1, u16 param2) -{ - int k = CMD_BUSY_TIMEOUT; - u16 reg; - - /* First wait for the command register to unbusy */ - reg = hermes_read_regn(hw, CMD); - while ((reg & HERMES_CMD_BUSY) && k) { - k--; - udelay(1); - reg = hermes_read_regn(hw, CMD); - } - if (reg & HERMES_CMD_BUSY) - return -EBUSY; - - hermes_write_regn(hw, PARAM2, param2); - hermes_write_regn(hw, PARAM1, param1); - hermes_write_regn(hw, PARAM0, param0); - hermes_write_regn(hw, CMD, cmd); - - return 0; -} - -/* - * Function definitions - */ - -/* For doing cmds that wipe the magic constant in SWSUPPORT0 */ -static int hermes_doicmd_wait(struct hermes *hw, u16 cmd, - u16 parm0, u16 parm1, u16 parm2, - struct hermes_response *resp) -{ - int err = 0; - int k; - u16 status, reg; - - err = hermes_issue_cmd(hw, cmd, parm0, parm1, parm2); - if (err) - return err; - - reg = hermes_read_regn(hw, EVSTAT); - k = CMD_INIT_TIMEOUT; - while ((!(reg & HERMES_EV_CMD)) && k) { - k--; - udelay(10); - reg = hermes_read_regn(hw, EVSTAT); - } - - hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC); - - if (!hermes_present(hw)) { - DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n", - hw->iobase); - err = -ENODEV; - goto out; - } - - if (!(reg & HERMES_EV_CMD)) { - printk(KERN_ERR "hermes @ %p: " - "Timeout waiting for card to reset (reg=0x%04x)!\n", - hw->iobase, reg); - err = -ETIMEDOUT; - goto out; - } - - status = hermes_read_regn(hw, STATUS); - if (resp) { - resp->status = status; - resp->resp0 = hermes_read_regn(hw, RESP0); - resp->resp1 = hermes_read_regn(hw, RESP1); - resp->resp2 = hermes_read_regn(hw, RESP2); - } - - hermes_write_regn(hw, EVACK, HERMES_EV_CMD); - - if (status & HERMES_STATUS_RESULT) - err = -EIO; -out: - return err; -} - -void hermes_struct_init(struct hermes *hw, void __iomem *address, - int reg_spacing) -{ - hw->iobase = address; - hw->reg_spacing = reg_spacing; - hw->inten = 0x0; - hw->eeprom_pda = false; - hw->ops = &hermes_ops_local; -} -EXPORT_SYMBOL(hermes_struct_init); - -static int hermes_init(struct hermes *hw) -{ - u16 reg; - int err = 0; - int k; - - /* We don't want to be interrupted while resetting the chipset */ - hw->inten = 0x0; - hermes_write_regn(hw, INTEN, 0); - hermes_write_regn(hw, EVACK, 0xffff); - - /* Normally it's a "can't happen" for the command register to - be busy when we go to issue a command because we are - serializing all commands. However we want to have some - chance of resetting the card even if it gets into a stupid - state, so we actually wait to see if the command register - will unbusy itself here. */ - k = CMD_BUSY_TIMEOUT; - reg = hermes_read_regn(hw, CMD); - while (k && (reg & HERMES_CMD_BUSY)) { - if (reg == 0xffff) /* Special case - the card has probably been - removed, so don't wait for the timeout */ - return -ENODEV; - - k--; - udelay(1); - reg = hermes_read_regn(hw, CMD); - } - - /* No need to explicitly handle the timeout - if we've timed - out hermes_issue_cmd() will probably return -EBUSY below */ - - /* According to the documentation, EVSTAT may contain - obsolete event occurrence information. We have to acknowledge - it by writing EVACK. */ - reg = hermes_read_regn(hw, EVSTAT); - hermes_write_regn(hw, EVACK, reg); - - /* We don't use hermes_docmd_wait here, because the reset wipes - the magic constant in SWSUPPORT0 away, and it gets confused */ - err = hermes_doicmd_wait(hw, HERMES_CMD_INIT, 0, 0, 0, NULL); - - return err; -} - -/* Issue a command to the chip, and (busy!) wait for it to - * complete. - * - * Returns: - * < 0 on internal error - * 0 on success - * > 0 on error returned by the firmware - * - * Callable from any context, but locking is your problem. */ -static int hermes_docmd_wait(struct hermes *hw, u16 cmd, u16 parm0, - struct hermes_response *resp) -{ - int err; - int k; - u16 reg; - u16 status; - - err = hermes_issue_cmd(hw, cmd, parm0, 0, 0); - if (err) { - if (!hermes_present(hw)) { - if (net_ratelimit()) - printk(KERN_WARNING "hermes @ %p: " - "Card removed while issuing command " - "0x%04x.\n", hw->iobase, cmd); - err = -ENODEV; - } else - if (net_ratelimit()) - printk(KERN_ERR "hermes @ %p: " - "Error %d issuing command 0x%04x.\n", - hw->iobase, err, cmd); - goto out; - } - - reg = hermes_read_regn(hw, EVSTAT); - k = CMD_COMPL_TIMEOUT; - while ((!(reg & HERMES_EV_CMD)) && k) { - k--; - udelay(10); - reg = hermes_read_regn(hw, EVSTAT); - } - - if (!hermes_present(hw)) { - printk(KERN_WARNING "hermes @ %p: Card removed " - "while waiting for command 0x%04x completion.\n", - hw->iobase, cmd); - err = -ENODEV; - goto out; - } - - if (!(reg & HERMES_EV_CMD)) { - printk(KERN_ERR "hermes @ %p: Timeout waiting for " - "command 0x%04x completion.\n", hw->iobase, cmd); - err = -ETIMEDOUT; - goto out; - } - - status = hermes_read_regn(hw, STATUS); - if (resp) { - resp->status = status; - resp->resp0 = hermes_read_regn(hw, RESP0); - resp->resp1 = hermes_read_regn(hw, RESP1); - resp->resp2 = hermes_read_regn(hw, RESP2); - } - - hermes_write_regn(hw, EVACK, HERMES_EV_CMD); - - if (status & HERMES_STATUS_RESULT) - err = -EIO; - - out: - return err; -} - -static int hermes_allocate(struct hermes *hw, u16 size, u16 *fid) -{ - int err = 0; - int k; - u16 reg; - - if ((size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX)) - return -EINVAL; - - err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, NULL); - if (err) - return err; - - reg = hermes_read_regn(hw, EVSTAT); - k = ALLOC_COMPL_TIMEOUT; - while ((!(reg & HERMES_EV_ALLOC)) && k) { - k--; - udelay(10); - reg = hermes_read_regn(hw, EVSTAT); - } - - if (!hermes_present(hw)) { - printk(KERN_WARNING "hermes @ %p: " - "Card removed waiting for frame allocation.\n", - hw->iobase); - return -ENODEV; - } - - if (!(reg & HERMES_EV_ALLOC)) { - printk(KERN_ERR "hermes @ %p: " - "Timeout waiting for frame allocation\n", - hw->iobase); - return -ETIMEDOUT; - } - - *fid = hermes_read_regn(hw, ALLOCFID); - hermes_write_regn(hw, EVACK, HERMES_EV_ALLOC); - - return 0; -} - -/* Set up a BAP to read a particular chunk of data from card's internal buffer. - * - * Returns: - * < 0 on internal failure (errno) - * 0 on success - * > 0 on error - * from firmware - * - * Callable from any context */ -static int hermes_bap_seek(struct hermes *hw, int bap, u16 id, u16 offset) -{ - int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0; - int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0; - int k; - u16 reg; - - /* Paranoia.. */ - if ((offset > HERMES_BAP_OFFSET_MAX) || (offset % 2)) - return -EINVAL; - - k = HERMES_BAP_BUSY_TIMEOUT; - reg = hermes_read_reg(hw, oreg); - while ((reg & HERMES_OFFSET_BUSY) && k) { - k--; - udelay(1); - reg = hermes_read_reg(hw, oreg); - } - - if (reg & HERMES_OFFSET_BUSY) - return -ETIMEDOUT; - - /* Now we actually set up the transfer */ - hermes_write_reg(hw, sreg, id); - hermes_write_reg(hw, oreg, offset); - - /* Wait for the BAP to be ready */ - k = HERMES_BAP_BUSY_TIMEOUT; - reg = hermes_read_reg(hw, oreg); - while ((reg & (HERMES_OFFSET_BUSY | HERMES_OFFSET_ERR)) && k) { - k--; - udelay(1); - reg = hermes_read_reg(hw, oreg); - } - - if (reg != offset) { - printk(KERN_ERR "hermes @ %p: BAP%d offset %s: " - "reg=0x%x id=0x%x offset=0x%x\n", hw->iobase, bap, - (reg & HERMES_OFFSET_BUSY) ? "timeout" : "error", - reg, id, offset); - - if (reg & HERMES_OFFSET_BUSY) - return -ETIMEDOUT; - - return -EIO; /* error or wrong offset */ - } - - return 0; -} - -/* Read a block of data from the chip's buffer, via the - * BAP. Synchronization/serialization is the caller's problem. len - * must be even. - * - * Returns: - * < 0 on internal failure (errno) - * 0 on success - * > 0 on error from firmware - */ -static int hermes_bap_pread(struct hermes *hw, int bap, void *buf, int len, - u16 id, u16 offset) -{ - int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; - int err = 0; - - if ((len < 0) || (len % 2)) - return -EINVAL; - - err = hermes_bap_seek(hw, bap, id, offset); - if (err) - goto out; - - /* Actually do the transfer */ - hermes_read_words(hw, dreg, buf, len / 2); - - out: - return err; -} - -/* Write a block of data to the chip's buffer, via the - * BAP. Synchronization/serialization is the caller's problem. - * - * Returns: - * < 0 on internal failure (errno) - * 0 on success - * > 0 on error from firmware - */ -static int hermes_bap_pwrite(struct hermes *hw, int bap, const void *buf, - int len, u16 id, u16 offset) -{ - int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; - int err = 0; - - if (len < 0) - return -EINVAL; - - err = hermes_bap_seek(hw, bap, id, offset); - if (err) - goto out; - - /* Actually do the transfer */ - hermes_write_bytes(hw, dreg, buf, len); - - out: - return err; -} - -/* Read a Length-Type-Value record from the card. - * - * If length is NULL, we ignore the length read from the card, and - * read the entire buffer regardless. This is useful because some of - * the configuration records appear to have incorrect lengths in - * practice. - * - * Callable from user or bh context. */ -static int hermes_read_ltv(struct hermes *hw, int bap, u16 rid, - unsigned bufsize, u16 *length, void *buf) -{ - int err = 0; - int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; - u16 rlength, rtype; - unsigned nwords; - - if (bufsize % 2) - return -EINVAL; - - err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL); - if (err) - return err; - - err = hermes_bap_seek(hw, bap, rid, 0); - if (err) - return err; - - rlength = hermes_read_reg(hw, dreg); - - if (!rlength) - return -ENODATA; - - rtype = hermes_read_reg(hw, dreg); - - if (length) - *length = rlength; - - if (rtype != rid) - printk(KERN_WARNING "hermes @ %p: %s(): " - "rid (0x%04x) does not match type (0x%04x)\n", - hw->iobase, __func__, rid, rtype); - if (HERMES_RECLEN_TO_BYTES(rlength) > bufsize) - printk(KERN_WARNING "hermes @ %p: " - "Truncating LTV record from %d to %d bytes. " - "(rid=0x%04x, len=0x%04x)\n", hw->iobase, - HERMES_RECLEN_TO_BYTES(rlength), bufsize, rid, rlength); - - nwords = min((unsigned)rlength - 1, bufsize / 2); - hermes_read_words(hw, dreg, buf, nwords); - - return 0; -} - -static int hermes_write_ltv(struct hermes *hw, int bap, u16 rid, - u16 length, const void *value) -{ - int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; - int err = 0; - unsigned count; - - if (length == 0) - return -EINVAL; - - err = hermes_bap_seek(hw, bap, rid, 0); - if (err) - return err; - - hermes_write_reg(hw, dreg, length); - hermes_write_reg(hw, dreg, rid); - - count = length - 1; - - hermes_write_bytes(hw, dreg, value, count << 1); - - err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, - rid, NULL); - - return err; -} - -/*** Hermes AUX control ***/ - -static inline void -hermes_aux_setaddr(struct hermes *hw, u32 addr) -{ - hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7)); - hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F)); -} - -static inline int -hermes_aux_control(struct hermes *hw, int enabled) -{ - int desired_state = enabled ? HERMES_AUX_ENABLED : HERMES_AUX_DISABLED; - int action = enabled ? HERMES_AUX_ENABLE : HERMES_AUX_DISABLE; - int i; - - /* Already open? */ - if (hermes_read_reg(hw, HERMES_CONTROL) == desired_state) - return 0; - - hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0); - hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1); - hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2); - hermes_write_reg(hw, HERMES_CONTROL, action); - - for (i = 0; i < 20; i++) { - udelay(10); - if (hermes_read_reg(hw, HERMES_CONTROL) == - desired_state) - return 0; - } - - return -EBUSY; -} - -/*** Hermes programming ***/ - -/* About to start programming data (Hermes I) - * offset is the entry point - * - * Spectrum_cs' Symbol fw does not require this - * wl_lkm Agere fw does - * Don't know about intersil - */ -static int hermesi_program_init(struct hermes *hw, u32 offset) -{ - int err; - - /* Disable interrupts?*/ - /*hw->inten = 0x0;*/ - /*hermes_write_regn(hw, INTEN, 0);*/ - /*hermes_set_irqmask(hw, 0);*/ - - /* Acknowledge any outstanding command */ - hermes_write_regn(hw, EVACK, 0xFFFF); - - /* Using init_cmd_wait rather than cmd_wait */ - err = hw->ops->init_cmd_wait(hw, - 0x0100 | HERMES_CMD_INIT, - 0, 0, 0, NULL); - if (err) - return err; - - err = hw->ops->init_cmd_wait(hw, - 0x0000 | HERMES_CMD_INIT, - 0, 0, 0, NULL); - if (err) - return err; - - err = hermes_aux_control(hw, 1); - pr_debug("AUX enable returned %d\n", err); - - if (err) - return err; - - pr_debug("Enabling volatile, EP 0x%08x\n", offset); - err = hw->ops->init_cmd_wait(hw, - HERMES_PROGRAM_ENABLE_VOLATILE, - offset & 0xFFFFu, - offset >> 16, - 0, - NULL); - pr_debug("PROGRAM_ENABLE returned %d\n", err); - - return err; -} - -/* Done programming data (Hermes I) - * - * Spectrum_cs' Symbol fw does not require this - * wl_lkm Agere fw does - * Don't know about intersil - */ -static int hermesi_program_end(struct hermes *hw) -{ - struct hermes_response resp; - int rc = 0; - int err; - - rc = hw->ops->cmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp); - - pr_debug("PROGRAM_DISABLE returned %d, " - "r0 0x%04x, r1 0x%04x, r2 0x%04x\n", - rc, resp.resp0, resp.resp1, resp.resp2); - - if ((rc == 0) && - ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD)) - rc = -EIO; - - err = hermes_aux_control(hw, 0); - pr_debug("AUX disable returned %d\n", err); - - /* Acknowledge any outstanding command */ - hermes_write_regn(hw, EVACK, 0xFFFF); - - /* Reinitialise, ignoring return */ - (void) hw->ops->init_cmd_wait(hw, 0x0000 | HERMES_CMD_INIT, - 0, 0, 0, NULL); - - return rc ? rc : err; -} - -static int hermes_program_bytes(struct hermes *hw, const char *data, - u32 addr, u32 len) -{ - /* wl lkm splits the programming into chunks of 2000 bytes. - * This restriction appears to come from USB. The PCMCIA - * adapters can program the whole lot in one go */ - hermes_aux_setaddr(hw, addr); - hermes_write_bytes(hw, HERMES_AUXDATA, data, len); - return 0; -} - -/* Read PDA from the adapter */ -static int hermes_read_pda(struct hermes *hw, __le16 *pda, u32 pda_addr, - u16 pda_len) -{ - int ret; - u16 pda_size; - u16 data_len = pda_len; - __le16 *data = pda; - - if (hw->eeprom_pda) { - /* PDA of spectrum symbol is in eeprom */ - - /* Issue command to read EEPROM */ - ret = hw->ops->cmd_wait(hw, HERMES_CMD_READMIF, 0, NULL); - if (ret) - return ret; - } else { - /* wl_lkm does not include PDA size in the PDA area. - * We will pad the information into pda, so other routines - * don't have to be modified */ - pda[0] = cpu_to_le16(pda_len - 2); - /* Includes CFG_PROD_DATA but not itself */ - pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */ - data_len = pda_len - 4; - data = pda + 2; - } - - /* Open auxiliary port */ - ret = hermes_aux_control(hw, 1); - pr_debug("AUX enable returned %d\n", ret); - if (ret) - return ret; - - /* Read PDA */ - hermes_aux_setaddr(hw, pda_addr); - hermes_read_words(hw, HERMES_AUXDATA, data, data_len / 2); - - /* Close aux port */ - ret = hermes_aux_control(hw, 0); - pr_debug("AUX disable returned %d\n", ret); - - /* Check PDA length */ - pda_size = le16_to_cpu(pda[0]); - pr_debug("Actual PDA length %d, Max allowed %d\n", - pda_size, pda_len); - if (pda_size > pda_len) - return -EINVAL; - - return 0; -} - -static void hermes_lock_irqsave(spinlock_t *lock, - unsigned long *flags) __acquires(lock) -{ - spin_lock_irqsave(lock, *flags); -} - -static void hermes_unlock_irqrestore(spinlock_t *lock, - unsigned long *flags) __releases(lock) -{ - spin_unlock_irqrestore(lock, *flags); -} - -static void hermes_lock_irq(spinlock_t *lock) __acquires(lock) -{ - spin_lock_irq(lock); -} - -static void hermes_unlock_irq(spinlock_t *lock) __releases(lock) -{ - spin_unlock_irq(lock); -} - -/* Hermes operations for local buses */ -static const struct hermes_ops hermes_ops_local = { - .init = hermes_init, - .cmd_wait = hermes_docmd_wait, - .init_cmd_wait = hermes_doicmd_wait, - .allocate = hermes_allocate, - .read_ltv = hermes_read_ltv, - .read_ltv_pr = hermes_read_ltv, - .write_ltv = hermes_write_ltv, - .bap_pread = hermes_bap_pread, - .bap_pwrite = hermes_bap_pwrite, - .read_pda = hermes_read_pda, - .program_init = hermesi_program_init, - .program_end = hermesi_program_end, - .program = hermes_program_bytes, - .lock_irqsave = hermes_lock_irqsave, - .unlock_irqrestore = hermes_unlock_irqrestore, - .lock_irq = hermes_lock_irq, - .unlock_irq = hermes_unlock_irq, -}; diff --git a/drivers/net/wireless/intersil/orinoco/hermes.h b/drivers/net/wireless/intersil/orinoco/hermes.h deleted file mode 100644 index 3dc561a5cb7ae..0000000000000 --- a/drivers/net/wireless/intersil/orinoco/hermes.h +++ /dev/null @@ -1,534 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* hermes.h - * - * Driver core for the "Hermes" wireless MAC controller, as used in - * the Lucent Orinoco and Cabletron RoamAbout cards. It should also - * work on the hfa3841 and hfa3842 MAC controller chips used in the - * Prism I & II chipsets. - * - * This is not a complete driver, just low-level access routines for - * the MAC controller itself. - * - * Based on the prism2 driver from Absolute Value Systems' linux-wlan - * project, the Linux wvlan_cs driver, Lucent's HCF-Light - * (wvlan_hcf.c) library, and the NetBSD wireless driver. - * - * Copyright (C) 2000, David Gibson, Linuxcare Australia. - * (C) Copyright David Gibson, IBM Corp. 2001-2003. - * - * Portions taken from hfa384x.h. - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - */ - -#ifndef _HERMES_H -#define _HERMES_H - -/* Notes on locking: - * - * As a module of low level hardware access routines, there is no - * locking. Users of this module should ensure that they serialize - * access to the hermes structure, and to the hardware -*/ - -#include -#include - -/* - * Limits and constants - */ -#define HERMES_ALLOC_LEN_MIN (4) -#define HERMES_ALLOC_LEN_MAX (2400) -#define HERMES_LTV_LEN_MAX (34) -#define HERMES_BAP_DATALEN_MAX (4096) -#define HERMES_BAP_OFFSET_MAX (4096) -#define HERMES_PORTID_MAX (7) -#define HERMES_NUMPORTS_MAX (HERMES_PORTID_MAX + 1) -#define HERMES_PDR_LEN_MAX (260) /* in bytes, from EK */ -#define HERMES_PDA_RECS_MAX (200) /* a guess */ -#define HERMES_PDA_LEN_MAX (1024) /* in bytes, from EK */ -#define HERMES_SCANRESULT_MAX (35) -#define HERMES_CHINFORESULT_MAX (8) -#define HERMES_MAX_MULTICAST (16) -#define HERMES_MAGIC (0x7d1f) - -/* - * Hermes register offsets - */ -#define HERMES_CMD (0x00) -#define HERMES_PARAM0 (0x02) -#define HERMES_PARAM1 (0x04) -#define HERMES_PARAM2 (0x06) -#define HERMES_STATUS (0x08) -#define HERMES_RESP0 (0x0A) -#define HERMES_RESP1 (0x0C) -#define HERMES_RESP2 (0x0E) -#define HERMES_INFOFID (0x10) -#define HERMES_RXFID (0x20) -#define HERMES_ALLOCFID (0x22) -#define HERMES_TXCOMPLFID (0x24) -#define HERMES_SELECT0 (0x18) -#define HERMES_OFFSET0 (0x1C) -#define HERMES_DATA0 (0x36) -#define HERMES_SELECT1 (0x1A) -#define HERMES_OFFSET1 (0x1E) -#define HERMES_DATA1 (0x38) -#define HERMES_EVSTAT (0x30) -#define HERMES_INTEN (0x32) -#define HERMES_EVACK (0x34) -#define HERMES_CONTROL (0x14) -#define HERMES_SWSUPPORT0 (0x28) -#define HERMES_SWSUPPORT1 (0x2A) -#define HERMES_SWSUPPORT2 (0x2C) -#define HERMES_AUXPAGE (0x3A) -#define HERMES_AUXOFFSET (0x3C) -#define HERMES_AUXDATA (0x3E) - -/* - * CMD register bitmasks - */ -#define HERMES_CMD_BUSY (0x8000) -#define HERMES_CMD_AINFO (0x7f00) -#define HERMES_CMD_MACPORT (0x0700) -#define HERMES_CMD_RECL (0x0100) -#define HERMES_CMD_WRITE (0x0100) -#define HERMES_CMD_PROGMODE (0x0300) -#define HERMES_CMD_CMDCODE (0x003f) - -/* - * STATUS register bitmasks - */ -#define HERMES_STATUS_RESULT (0x7f00) -#define HERMES_STATUS_CMDCODE (0x003f) - -/* - * OFFSET register bitmasks - */ -#define HERMES_OFFSET_BUSY (0x8000) -#define HERMES_OFFSET_ERR (0x4000) -#define HERMES_OFFSET_DATAOFF (0x0ffe) - -/* - * Event register bitmasks (INTEN, EVSTAT, EVACK) - */ -#define HERMES_EV_TICK (0x8000) -#define HERMES_EV_WTERR (0x4000) -#define HERMES_EV_INFDROP (0x2000) -#define HERMES_EV_INFO (0x0080) -#define HERMES_EV_DTIM (0x0020) -#define HERMES_EV_CMD (0x0010) -#define HERMES_EV_ALLOC (0x0008) -#define HERMES_EV_TXEXC (0x0004) -#define HERMES_EV_TX (0x0002) -#define HERMES_EV_RX (0x0001) - -/* - * Command codes - */ -/*--- Controller Commands ----------------------------*/ -#define HERMES_CMD_INIT (0x0000) -#define HERMES_CMD_ENABLE (0x0001) -#define HERMES_CMD_DISABLE (0x0002) -#define HERMES_CMD_DIAG (0x0003) - -/*--- Buffer Mgmt Commands ---------------------------*/ -#define HERMES_CMD_ALLOC (0x000A) -#define HERMES_CMD_TX (0x000B) - -/*--- Regulate Commands ------------------------------*/ -#define HERMES_CMD_NOTIFY (0x0010) -#define HERMES_CMD_INQUIRE (0x0011) - -/*--- Configure Commands -----------------------------*/ -#define HERMES_CMD_ACCESS (0x0021) -#define HERMES_CMD_DOWNLD (0x0022) - -/*--- Serial I/O Commands ----------------------------*/ -#define HERMES_CMD_READMIF (0x0030) -#define HERMES_CMD_WRITEMIF (0x0031) - -/*--- Debugging Commands -----------------------------*/ -#define HERMES_CMD_TEST (0x0038) - - -/* Test command arguments */ -#define HERMES_TEST_SET_CHANNEL 0x0800 -#define HERMES_TEST_MONITOR 0x0b00 -#define HERMES_TEST_STOP 0x0f00 - -/* Authentication algorithms */ -#define HERMES_AUTH_OPEN 1 -#define HERMES_AUTH_SHARED_KEY 2 - -/* WEP settings */ -#define HERMES_WEP_PRIVACY_INVOKED 0x0001 -#define HERMES_WEP_EXCL_UNENCRYPTED 0x0002 -#define HERMES_WEP_HOST_ENCRYPT 0x0010 -#define HERMES_WEP_HOST_DECRYPT 0x0080 - -/* Symbol hostscan options */ -#define HERMES_HOSTSCAN_SYMBOL_5SEC 0x0001 -#define HERMES_HOSTSCAN_SYMBOL_ONCE 0x0002 -#define HERMES_HOSTSCAN_SYMBOL_PASSIVE 0x0040 -#define HERMES_HOSTSCAN_SYMBOL_BCAST 0x0080 - -/* - * Frame structures and constants - */ - -#define HERMES_DESCRIPTOR_OFFSET 0 -#define HERMES_802_11_OFFSET (14) -#define HERMES_802_3_OFFSET (14 + 32) -#define HERMES_802_2_OFFSET (14 + 32 + 14) -#define HERMES_TXCNTL2_OFFSET (HERMES_802_3_OFFSET - 2) - -#define HERMES_RXSTAT_ERR (0x0003) -#define HERMES_RXSTAT_BADCRC (0x0001) -#define HERMES_RXSTAT_UNDECRYPTABLE (0x0002) -#define HERMES_RXSTAT_MIC (0x0010) /* Frame contains MIC */ -#define HERMES_RXSTAT_MACPORT (0x0700) -#define HERMES_RXSTAT_PCF (0x1000) /* Frame was received in CF period */ -#define HERMES_RXSTAT_MIC_KEY_ID (0x1800) /* MIC key used */ -#define HERMES_RXSTAT_MSGTYPE (0xE000) -#define HERMES_RXSTAT_1042 (0x2000) /* RFC-1042 frame */ -#define HERMES_RXSTAT_TUNNEL (0x4000) /* bridge-tunnel encoded frame */ -#define HERMES_RXSTAT_WMP (0x6000) /* Wavelan-II Management Protocol frame */ - -/* Shift amount for key ID in RXSTAT and TXCTRL */ -#define HERMES_MIC_KEY_ID_SHIFT 11 - -struct hermes_tx_descriptor { - __le16 status; - __le16 reserved1; - __le16 reserved2; - __le32 sw_support; - u8 retry_count; - u8 tx_rate; - __le16 tx_control; -} __packed; - -#define HERMES_TXSTAT_RETRYERR (0x0001) -#define HERMES_TXSTAT_AGEDERR (0x0002) -#define HERMES_TXSTAT_DISCON (0x0004) -#define HERMES_TXSTAT_FORMERR (0x0008) - -#define HERMES_TXCTRL_TX_OK (0x0002) /* ?? interrupt on Tx complete */ -#define HERMES_TXCTRL_TX_EX (0x0004) /* ?? interrupt on Tx exception */ -#define HERMES_TXCTRL_802_11 (0x0008) /* We supply 802.11 header */ -#define HERMES_TXCTRL_MIC (0x0010) /* 802.3 + TKIP */ -#define HERMES_TXCTRL_MIC_KEY_ID (0x1800) /* MIC Key ID mask */ -#define HERMES_TXCTRL_ALT_RTRY (0x0020) - -/* Inquiry constants and data types */ - -#define HERMES_INQ_TALLIES (0xF100) -#define HERMES_INQ_SCAN (0xF101) -#define HERMES_INQ_CHANNELINFO (0xF102) -#define HERMES_INQ_HOSTSCAN (0xF103) -#define HERMES_INQ_HOSTSCAN_SYMBOL (0xF104) -#define HERMES_INQ_LINKSTATUS (0xF200) -#define HERMES_INQ_SEC_STAT_AGERE (0xF202) - -struct hermes_tallies_frame { - __le16 TxUnicastFrames; - __le16 TxMulticastFrames; - __le16 TxFragments; - __le16 TxUnicastOctets; - __le16 TxMulticastOctets; - __le16 TxDeferredTransmissions; - __le16 TxSingleRetryFrames; - __le16 TxMultipleRetryFrames; - __le16 TxRetryLimitExceeded; - __le16 TxDiscards; - __le16 RxUnicastFrames; - __le16 RxMulticastFrames; - __le16 RxFragments; - __le16 RxUnicastOctets; - __le16 RxMulticastOctets; - __le16 RxFCSErrors; - __le16 RxDiscards_NoBuffer; - __le16 TxDiscardsWrongSA; - __le16 RxWEPUndecryptable; - __le16 RxMsgInMsgFragments; - __le16 RxMsgInBadMsgFragments; - /* Those last are probably not available in very old firmwares */ - __le16 RxDiscards_WEPICVError; - __le16 RxDiscards_WEPExcluded; -} __packed; - -/* Grabbed from wlan-ng - Thanks Mark... - Jean II - * This is the result of a scan inquiry command */ -/* Structure describing info about an Access Point */ -struct prism2_scan_apinfo { - __le16 channel; /* Channel where the AP sits */ - __le16 noise; /* Noise level */ - __le16 level; /* Signal level */ - u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ - __le16 beacon_interv; /* Beacon interval */ - __le16 capabilities; /* Capabilities */ - __le16 essid_len; /* ESSID length */ - u8 essid[32]; /* ESSID of the network */ - u8 rates[10]; /* Bit rate supported */ - __le16 proberesp_rate; /* Data rate of the response frame */ - __le16 atim; /* ATIM window time, Kus (hostscan only) */ -} __packed; - -/* Same stuff for the Lucent/Agere card. - * Thanks to h1kari - Jean II */ -struct agere_scan_apinfo { - __le16 channel; /* Channel where the AP sits */ - __le16 noise; /* Noise level */ - __le16 level; /* Signal level */ - u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ - __le16 beacon_interv; /* Beacon interval */ - __le16 capabilities; /* Capabilities */ - /* bits: 0-ess, 1-ibss, 4-privacy [wep] */ - __le16 essid_len; /* ESSID length */ - u8 essid[32]; /* ESSID of the network */ -} __packed; - -/* Moustafa: Scan structure for Symbol cards */ -struct symbol_scan_apinfo { - u8 channel; /* Channel where the AP sits */ - u8 unknown1; /* 8 in 2.9x and 3.9x f/w, 0 otherwise */ - __le16 noise; /* Noise level */ - __le16 level; /* Signal level */ - u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ - __le16 beacon_interv; /* Beacon interval */ - __le16 capabilities; /* Capabilities */ - /* bits: 0-ess, 1-ibss, 4-privacy [wep] */ - __le16 essid_len; /* ESSID length */ - u8 essid[32]; /* ESSID of the network */ - __le16 rates[5]; /* Bit rate supported */ - __le16 basic_rates; /* Basic rates bitmask */ - u8 unknown2[6]; /* Always FF:FF:FF:FF:00:00 */ - u8 unknown3[8]; /* Always 0, appeared in f/w 3.91-68 */ -} __packed; - -union hermes_scan_info { - struct agere_scan_apinfo a; - struct prism2_scan_apinfo p; - struct symbol_scan_apinfo s; -}; - -/* Extended scan struct for HERMES_INQ_CHANNELINFO. - * wl_lkm calls this an ACS scan (Automatic Channel Select). - * Keep out of union hermes_scan_info because it is much bigger than - * the older scan structures. */ -struct agere_ext_scan_info { - __le16 reserved0; - - u8 noise; - u8 level; - u8 rx_flow; - u8 rate; - __le16 reserved1[2]; - - __le16 frame_control; - __le16 dur_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 bssid[ETH_ALEN]; - __le16 sequence; - u8 addr4[ETH_ALEN]; - - __le16 data_length; - - /* Next 3 fields do not get filled in. */ - u8 daddr[ETH_ALEN]; - u8 saddr[ETH_ALEN]; - __le16 len_type; - - __le64 timestamp; - __le16 beacon_interval; - __le16 capabilities; - u8 data[]; -} __packed; - -#define HERMES_LINKSTATUS_NOT_CONNECTED (0x0000) -#define HERMES_LINKSTATUS_CONNECTED (0x0001) -#define HERMES_LINKSTATUS_DISCONNECTED (0x0002) -#define HERMES_LINKSTATUS_AP_CHANGE (0x0003) -#define HERMES_LINKSTATUS_AP_OUT_OF_RANGE (0x0004) -#define HERMES_LINKSTATUS_AP_IN_RANGE (0x0005) -#define HERMES_LINKSTATUS_ASSOC_FAILED (0x0006) - -struct hermes_linkstatus { - __le16 linkstatus; /* Link status */ -} __packed; - -struct hermes_response { - u16 status, resp0, resp1, resp2; -}; - -/* "ID" structure - used for ESSID and station nickname */ -struct hermes_idstring { - __le16 len; - __le16 val[16]; -} __packed; - -struct hermes_multicast { - u8 addr[HERMES_MAX_MULTICAST][ETH_ALEN]; -} __packed; - -/* Timeouts */ -#define HERMES_BAP_BUSY_TIMEOUT (10000) /* In iterations of ~1us */ - -struct hermes; - -/* Functions to access hardware */ -struct hermes_ops { - int (*init)(struct hermes *hw); - int (*cmd_wait)(struct hermes *hw, u16 cmd, u16 parm0, - struct hermes_response *resp); - int (*init_cmd_wait)(struct hermes *hw, u16 cmd, - u16 parm0, u16 parm1, u16 parm2, - struct hermes_response *resp); - int (*allocate)(struct hermes *hw, u16 size, u16 *fid); - int (*read_ltv)(struct hermes *hw, int bap, u16 rid, unsigned buflen, - u16 *length, void *buf); - int (*read_ltv_pr)(struct hermes *hw, int bap, u16 rid, - unsigned buflen, u16 *length, void *buf); - int (*write_ltv)(struct hermes *hw, int bap, u16 rid, - u16 length, const void *value); - int (*bap_pread)(struct hermes *hw, int bap, void *buf, int len, - u16 id, u16 offset); - int (*bap_pwrite)(struct hermes *hw, int bap, const void *buf, - int len, u16 id, u16 offset); - int (*read_pda)(struct hermes *hw, __le16 *pda, - u32 pda_addr, u16 pda_len); - int (*program_init)(struct hermes *hw, u32 entry_point); - int (*program_end)(struct hermes *hw); - int (*program)(struct hermes *hw, const char *buf, - u32 addr, u32 len); - void (*lock_irqsave)(spinlock_t *lock, unsigned long *flags); - void (*unlock_irqrestore)(spinlock_t *lock, unsigned long *flags); - void (*lock_irq)(spinlock_t *lock); - void (*unlock_irq)(spinlock_t *lock); -}; - -/* Basic control structure */ -struct hermes { - void __iomem *iobase; - int reg_spacing; -#define HERMES_16BIT_REGSPACING 0 -#define HERMES_32BIT_REGSPACING 1 - u16 inten; /* Which interrupts should be enabled? */ - bool eeprom_pda; - const struct hermes_ops *ops; - void *priv; -}; - -/* Register access convenience macros */ -#define hermes_read_reg(hw, off) \ - (ioread16((hw)->iobase + ((off) << (hw)->reg_spacing))) -#define hermes_write_reg(hw, off, val) \ - (iowrite16((val), (hw)->iobase + ((off) << (hw)->reg_spacing))) -#define hermes_read_regn(hw, name) hermes_read_reg((hw), HERMES_##name) -#define hermes_write_regn(hw, name, val) \ - hermes_write_reg((hw), HERMES_##name, (val)) - -/* Function prototypes */ -void hermes_struct_init(struct hermes *hw, void __iomem *address, - int reg_spacing); - -/* Inline functions */ - -static inline int hermes_present(struct hermes *hw) -{ - return hermes_read_regn(hw, SWSUPPORT0) == HERMES_MAGIC; -} - -static inline void hermes_set_irqmask(struct hermes *hw, u16 events) -{ - hw->inten = events; - hermes_write_regn(hw, INTEN, events); -} - -static inline int hermes_enable_port(struct hermes *hw, int port) -{ - return hw->ops->cmd_wait(hw, HERMES_CMD_ENABLE | (port << 8), - 0, NULL); -} - -static inline int hermes_disable_port(struct hermes *hw, int port) -{ - return hw->ops->cmd_wait(hw, HERMES_CMD_DISABLE | (port << 8), - 0, NULL); -} - -/* Initiate an INQUIRE command (tallies or scan). The result will come as an - * information frame in __orinoco_ev_info() */ -static inline int hermes_inquire(struct hermes *hw, u16 rid) -{ - return hw->ops->cmd_wait(hw, HERMES_CMD_INQUIRE, rid, NULL); -} - -#define HERMES_BYTES_TO_RECLEN(n) ((((n) + 1) / 2) + 1) -#define HERMES_RECLEN_TO_BYTES(n) (((n) - 1) * 2) - -/* Note that for the next two, the count is in 16-bit words, not bytes */ -static inline void hermes_read_words(struct hermes *hw, int off, - void *buf, unsigned count) -{ - off = off << hw->reg_spacing; - ioread16_rep(hw->iobase + off, buf, count); -} - -static inline void hermes_write_bytes(struct hermes *hw, int off, - const char *buf, unsigned count) -{ - off = off << hw->reg_spacing; - iowrite16_rep(hw->iobase + off, buf, count >> 1); - if (unlikely(count & 1)) - iowrite8(buf[count - 1], hw->iobase + off); -} - -static inline void hermes_clear_words(struct hermes *hw, int off, - unsigned count) -{ - unsigned i; - - off = off << hw->reg_spacing; - - for (i = 0; i < count; i++) - iowrite16(0, hw->iobase + off); -} - -#define HERMES_READ_RECORD(hw, bap, rid, buf) \ - (hw->ops->read_ltv((hw), (bap), (rid), sizeof(*buf), NULL, (buf))) -#define HERMES_READ_RECORD_PR(hw, bap, rid, buf) \ - (hw->ops->read_ltv_pr((hw), (bap), (rid), sizeof(*buf), NULL, (buf))) -#define HERMES_WRITE_RECORD(hw, bap, rid, buf) \ - (hw->ops->write_ltv((hw), (bap), (rid), \ - HERMES_BYTES_TO_RECLEN(sizeof(*buf)), (buf))) - -static inline int hermes_read_wordrec(struct hermes *hw, int bap, u16 rid, - u16 *word) -{ - __le16 rec; - int err; - - err = HERMES_READ_RECORD(hw, bap, rid, &rec); - *word = le16_to_cpu(rec); - return err; -} - -static inline int hermes_read_wordrec_pr(struct hermes *hw, int bap, u16 rid, - u16 *word) -{ - __le16 rec; - int err; - - err = HERMES_READ_RECORD_PR(hw, bap, rid, &rec); - *word = le16_to_cpu(rec); - return err; -} - -static inline int hermes_write_wordrec(struct hermes *hw, int bap, u16 rid, - u16 word) -{ - __le16 rec = cpu_to_le16(word); - return HERMES_WRITE_RECORD(hw, bap, rid, &rec); -} - -#endif /* _HERMES_H */ diff --git a/drivers/net/wireless/intersil/orinoco/hermes_dld.c b/drivers/net/wireless/intersil/orinoco/hermes_dld.c deleted file mode 100644 index dbeadfcfefe26..0000000000000 --- a/drivers/net/wireless/intersil/orinoco/hermes_dld.c +++ /dev/null @@ -1,477 +0,0 @@ -/* - * Hermes download helper. - * - * This helper: - * - is capable of writing to the volatile area of the hermes device - * - is currently not capable of writing to non-volatile areas - * - provide helpers to identify and update plugin data - * - is not capable of interpreting a fw image directly. That is up to - * the main card driver. - * - deals with Hermes I devices. It can probably be modified to deal - * with Hermes II devices - * - * Copyright (C) 2007, David Kilroy - * - * Plug data code slightly modified from spectrum_cs driver - * Copyright (C) 2002-2005 Pavel Roskin - * Portions based on information in wl_lkm_718 Agere driver - * COPYRIGHT (C) 2001-2004 by Agere Systems Inc. All Rights Reserved - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - */ - -#include -#include -#include "hermes.h" -#include "hermes_dld.h" - -#define PFX "hermes_dld: " - -/* End markers used in dblocks */ -#define PDI_END 0x00000000 /* End of PDA */ -#define BLOCK_END 0xFFFFFFFF /* Last image block */ -#define TEXT_END 0x1A /* End of text header */ - -/* - * The following structures have little-endian fields denoted by - * the leading underscore. Don't access them directly - use inline - * functions defined below. - */ - -/* - * The binary image to be downloaded consists of series of data blocks. - * Each block has the following structure. - */ -struct dblock { - __le32 addr; /* adapter address where to write the block */ - __le16 len; /* length of the data only, in bytes */ - char data[]; /* data to be written */ -} __packed; - -/* - * Plug Data References are located in the image after the last data - * block. They refer to areas in the adapter memory where the plug data - * items with matching ID should be written. - */ -struct pdr { - __le32 id; /* record ID */ - __le32 addr; /* adapter address where to write the data */ - __le32 len; /* expected length of the data, in bytes */ - char next[]; /* next PDR starts here */ -} __packed; - -/* - * Plug Data Items are located in the EEPROM read from the adapter by - * primary firmware. They refer to the device-specific data that should - * be plugged into the secondary firmware. - */ -struct pdi { - __le16 len; /* length of ID and data, in words */ - __le16 id; /* record ID */ - char data[]; /* plug data */ -} __packed; - -/*** FW data block access functions ***/ - -static inline u32 -dblock_addr(const struct dblock *blk) -{ - return le32_to_cpu(blk->addr); -} - -static inline u32 -dblock_len(const struct dblock *blk) -{ - return le16_to_cpu(blk->len); -} - -/*** PDR Access functions ***/ - -static inline u32 -pdr_id(const struct pdr *pdr) -{ - return le32_to_cpu(pdr->id); -} - -static inline u32 -pdr_addr(const struct pdr *pdr) -{ - return le32_to_cpu(pdr->addr); -} - -static inline u32 -pdr_len(const struct pdr *pdr) -{ - return le32_to_cpu(pdr->len); -} - -/*** PDI Access functions ***/ - -static inline u32 -pdi_id(const struct pdi *pdi) -{ - return le16_to_cpu(pdi->id); -} - -/* Return length of the data only, in bytes */ -static inline u32 -pdi_len(const struct pdi *pdi) -{ - return 2 * (le16_to_cpu(pdi->len) - 1); -} - -/*** Plug Data Functions ***/ - -/* - * Scan PDR for the record with the specified RECORD_ID. - * If it's not found, return NULL. - */ -static const struct pdr * -hermes_find_pdr(const struct pdr *first_pdr, u32 record_id, const void *end) -{ - const struct pdr *pdr = first_pdr; - - end -= sizeof(struct pdr); - - while (((void *) pdr <= end) && - (pdr_id(pdr) != PDI_END)) { - /* - * PDR area is currently not terminated by PDI_END. - * It's followed by CRC records, which have the type - * field where PDR has length. The type can be 0 or 1. - */ - if (pdr_len(pdr) < 2) - return NULL; - - /* If the record ID matches, we are done */ - if (pdr_id(pdr) == record_id) - return pdr; - - pdr = (struct pdr *) pdr->next; - } - return NULL; -} - -/* Scan production data items for a particular entry */ -static const struct pdi * -hermes_find_pdi(const struct pdi *first_pdi, u32 record_id, const void *end) -{ - const struct pdi *pdi = first_pdi; - - end -= sizeof(struct pdi); - - while (((void *) pdi <= end) && - (pdi_id(pdi) != PDI_END)) { - - /* If the record ID matches, we are done */ - if (pdi_id(pdi) == record_id) - return pdi; - - pdi = (struct pdi *) &pdi->data[pdi_len(pdi)]; - } - return NULL; -} - -/* Process one Plug Data Item - find corresponding PDR and plug it */ -static int -hermes_plug_pdi(struct hermes *hw, const struct pdr *first_pdr, - const struct pdi *pdi, const void *pdr_end) -{ - const struct pdr *pdr; - - /* Find the PDR corresponding to this PDI */ - pdr = hermes_find_pdr(first_pdr, pdi_id(pdi), pdr_end); - - /* No match is found, safe to ignore */ - if (!pdr) - return 0; - - /* Lengths of the data in PDI and PDR must match */ - if (pdi_len(pdi) != pdr_len(pdr)) - return -EINVAL; - - /* do the actual plugging */ - hw->ops->program(hw, pdi->data, pdr_addr(pdr), pdi_len(pdi)); - - return 0; -} - -/* Parse PDA and write the records into the adapter - * - * Attempt to write every records that is in the specified pda - * which also has a valid production data record for the firmware. - */ -int hermes_apply_pda(struct hermes *hw, - const char *first_pdr, - const void *pdr_end, - const __le16 *pda, - const void *pda_end) -{ - int ret; - const struct pdi *pdi; - const struct pdr *pdr; - - pdr = (const struct pdr *) first_pdr; - pda_end -= sizeof(struct pdi); - - /* Go through every PDI and plug them into the adapter */ - pdi = (const struct pdi *) (pda + 2); - while (((void *) pdi <= pda_end) && - (pdi_id(pdi) != PDI_END)) { - ret = hermes_plug_pdi(hw, pdr, pdi, pdr_end); - if (ret) - return ret; - - /* Increment to the next PDI */ - pdi = (const struct pdi *) &pdi->data[pdi_len(pdi)]; - } - return 0; -} - -/* Identify the total number of bytes in all blocks - * including the header data. - */ -size_t -hermes_blocks_length(const char *first_block, const void *end) -{ - const struct dblock *blk = (const struct dblock *) first_block; - int total_len = 0; - int len; - - end -= sizeof(*blk); - - /* Skip all blocks to locate Plug Data References - * (Spectrum CS) */ - while (((void *) blk <= end) && - (dblock_addr(blk) != BLOCK_END)) { - len = dblock_len(blk); - total_len += sizeof(*blk) + len; - blk = (struct dblock *) &blk->data[len]; - } - - return total_len; -} - -/*** Hermes programming ***/ - -/* Program the data blocks */ -int hermes_program(struct hermes *hw, const char *first_block, const void *end) -{ - const struct dblock *blk; - u32 blkaddr; - u32 blklen; - int err = 0; - - blk = (const struct dblock *) first_block; - - if ((void *) blk > (end - sizeof(*blk))) - return -EIO; - - blkaddr = dblock_addr(blk); - blklen = dblock_len(blk); - - while ((blkaddr != BLOCK_END) && - (((void *) blk + blklen) <= end)) { - pr_debug(PFX "Programming block of length %d " - "to address 0x%08x\n", blklen, blkaddr); - - err = hw->ops->program(hw, blk->data, blkaddr, blklen); - if (err) - break; - - blk = (const struct dblock *) &blk->data[blklen]; - - if ((void *) blk > (end - sizeof(*blk))) - return -EIO; - - blkaddr = dblock_addr(blk); - blklen = dblock_len(blk); - } - return err; -} - -/*** Default plugging data for Hermes I ***/ -/* Values from wl_lkm_718/hcf/dhf.c */ - -#define DEFINE_DEFAULT_PDR(pid, length, data) \ -static const struct { \ - __le16 len; \ - __le16 id; \ - u8 val[length]; \ -} __packed default_pdr_data_##pid = { \ - cpu_to_le16((sizeof(default_pdr_data_##pid)/ \ - sizeof(__le16)) - 1), \ - cpu_to_le16(pid), \ - data \ -} - -#define DEFAULT_PDR(pid) default_pdr_data_##pid - -/* HWIF Compatibility */ -DEFINE_DEFAULT_PDR(0x0005, 10, "\x00\x00\x06\x00\x01\x00\x01\x00\x01\x00"); - -/* PPPPSign */ -DEFINE_DEFAULT_PDR(0x0108, 4, "\x00\x00\x00\x00"); - -/* PPPPProf */ -DEFINE_DEFAULT_PDR(0x0109, 10, "\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00"); - -/* Antenna diversity */ -DEFINE_DEFAULT_PDR(0x0150, 2, "\x00\x3F"); - -/* Modem VCO band Set-up */ -DEFINE_DEFAULT_PDR(0x0160, 28, - "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00"); - -/* Modem Rx Gain Table Values */ -DEFINE_DEFAULT_PDR(0x0161, 256, - "\x3F\x01\x3F\01\x3F\x01\x3F\x01" - "\x3F\x01\x3F\01\x3F\x01\x3F\x01" - "\x3F\x01\x3F\01\x3F\x01\x3F\x01" - "\x3F\x01\x3F\01\x3F\x01\x3F\x01" - "\x3F\x01\x3E\01\x3E\x01\x3D\x01" - "\x3D\x01\x3C\01\x3C\x01\x3B\x01" - "\x3B\x01\x3A\01\x3A\x01\x39\x01" - "\x39\x01\x38\01\x38\x01\x37\x01" - "\x37\x01\x36\01\x36\x01\x35\x01" - "\x35\x01\x34\01\x34\x01\x33\x01" - "\x33\x01\x32\x01\x32\x01\x31\x01" - "\x31\x01\x30\x01\x30\x01\x7B\x01" - "\x7B\x01\x7A\x01\x7A\x01\x79\x01" - "\x79\x01\x78\x01\x78\x01\x77\x01" - "\x77\x01\x76\x01\x76\x01\x75\x01" - "\x75\x01\x74\x01\x74\x01\x73\x01" - "\x73\x01\x72\x01\x72\x01\x71\x01" - "\x71\x01\x70\x01\x70\x01\x68\x01" - "\x68\x01\x67\x01\x67\x01\x66\x01" - "\x66\x01\x65\x01\x65\x01\x57\x01" - "\x57\x01\x56\x01\x56\x01\x55\x01" - "\x55\x01\x54\x01\x54\x01\x53\x01" - "\x53\x01\x52\x01\x52\x01\x51\x01" - "\x51\x01\x50\x01\x50\x01\x48\x01" - "\x48\x01\x47\x01\x47\x01\x46\x01" - "\x46\x01\x45\x01\x45\x01\x44\x01" - "\x44\x01\x43\x01\x43\x01\x42\x01" - "\x42\x01\x41\x01\x41\x01\x40\x01" - "\x40\x01\x40\x01\x40\x01\x40\x01" - "\x40\x01\x40\x01\x40\x01\x40\x01" - "\x40\x01\x40\x01\x40\x01\x40\x01" - "\x40\x01\x40\x01\x40\x01\x40\x01"); - -/* Write PDA according to certain rules. - * - * For every production data record, look for a previous setting in - * the pda, and use that. - * - * For certain records, use defaults if they are not found in pda. - */ -int hermes_apply_pda_with_defaults(struct hermes *hw, - const char *first_pdr, - const void *pdr_end, - const __le16 *pda, - const void *pda_end) -{ - const struct pdr *pdr = (const struct pdr *) first_pdr; - const struct pdi *first_pdi = (const struct pdi *) &pda[2]; - const struct pdi *pdi; - const struct pdi *default_pdi = NULL; - const struct pdi *outdoor_pdi; - int record_id; - - pdr_end -= sizeof(struct pdr); - - while (((void *) pdr <= pdr_end) && - (pdr_id(pdr) != PDI_END)) { - /* - * For spectrum_cs firmwares, - * PDR area is currently not terminated by PDI_END. - * It's followed by CRC records, which have the type - * field where PDR has length. The type can be 0 or 1. - */ - if (pdr_len(pdr) < 2) - break; - record_id = pdr_id(pdr); - - pdi = hermes_find_pdi(first_pdi, record_id, pda_end); - if (pdi) - pr_debug(PFX "Found record 0x%04x at %p\n", - record_id, pdi); - - switch (record_id) { - case 0x110: /* Modem REFDAC values */ - case 0x120: /* Modem VGDAC values */ - outdoor_pdi = hermes_find_pdi(first_pdi, record_id + 1, - pda_end); - default_pdi = NULL; - if (outdoor_pdi) { - pdi = outdoor_pdi; - pr_debug(PFX - "Using outdoor record 0x%04x at %p\n", - record_id + 1, pdi); - } - break; - case 0x5: /* HWIF Compatibility */ - default_pdi = (struct pdi *) &DEFAULT_PDR(0x0005); - break; - case 0x108: /* PPPPSign */ - default_pdi = (struct pdi *) &DEFAULT_PDR(0x0108); - break; - case 0x109: /* PPPPProf */ - default_pdi = (struct pdi *) &DEFAULT_PDR(0x0109); - break; - case 0x150: /* Antenna diversity */ - default_pdi = (struct pdi *) &DEFAULT_PDR(0x0150); - break; - case 0x160: /* Modem VCO band Set-up */ - default_pdi = (struct pdi *) &DEFAULT_PDR(0x0160); - break; - case 0x161: /* Modem Rx Gain Table Values */ - default_pdi = (struct pdi *) &DEFAULT_PDR(0x0161); - break; - default: - default_pdi = NULL; - break; - } - if (!pdi && default_pdi) { - /* Use default */ - pdi = default_pdi; - pr_debug(PFX "Using default record 0x%04x at %p\n", - record_id, pdi); - } - - if (pdi) { - /* Lengths of the data in PDI and PDR must match */ - if ((pdi_len(pdi) == pdr_len(pdr)) && - ((void *) pdi->data + pdi_len(pdi) < pda_end)) { - /* do the actual plugging */ - hw->ops->program(hw, pdi->data, pdr_addr(pdr), - pdi_len(pdi)); - } - } - - pdr++; - } - return 0; -} diff --git a/drivers/net/wireless/intersil/orinoco/hermes_dld.h b/drivers/net/wireless/intersil/orinoco/hermes_dld.h deleted file mode 100644 index b5377e232c636..0000000000000 --- a/drivers/net/wireless/intersil/orinoco/hermes_dld.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2007, David Kilroy - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - */ -#ifndef _HERMES_DLD_H -#define _HERMES_DLD_H - -#include "hermes.h" - -int hermesi_program_init(struct hermes *hw, u32 offset); -int hermesi_program_end(struct hermes *hw); -int hermes_program(struct hermes *hw, const char *first_block, const void *end); - -int hermes_read_pda(struct hermes *hw, - __le16 *pda, - u32 pda_addr, - u16 pda_len, - int use_eeprom); -int hermes_apply_pda(struct hermes *hw, - const char *first_pdr, - const void *pdr_end, - const __le16 *pda, - const void *pda_end); -int hermes_apply_pda_with_defaults(struct hermes *hw, - const char *first_pdr, - const void *pdr_end, - const __le16 *pda, - const void *pda_end); - -size_t hermes_blocks_length(const char *first_block, const void *end); - -#endif /* _HERMES_DLD_H */ diff --git a/drivers/net/wireless/intersil/orinoco/hermes_rid.h b/drivers/net/wireless/intersil/orinoco/hermes_rid.h deleted file mode 100644 index 42eb67dea1df2..0000000000000 --- a/drivers/net/wireless/intersil/orinoco/hermes_rid.h +++ /dev/null @@ -1,165 +0,0 @@ -#ifndef _HERMES_RID_H -#define _HERMES_RID_H - -/* - * Configuration RIDs - */ -#define HERMES_RID_CNFPORTTYPE 0xFC00 -#define HERMES_RID_CNFOWNMACADDR 0xFC01 -#define HERMES_RID_CNFDESIREDSSID 0xFC02 -#define HERMES_RID_CNFOWNCHANNEL 0xFC03 -#define HERMES_RID_CNFOWNSSID 0xFC04 -#define HERMES_RID_CNFOWNATIMWINDOW 0xFC05 -#define HERMES_RID_CNFSYSTEMSCALE 0xFC06 -#define HERMES_RID_CNFMAXDATALEN 0xFC07 -#define HERMES_RID_CNFWDSADDRESS 0xFC08 -#define HERMES_RID_CNFPMENABLED 0xFC09 -#define HERMES_RID_CNFPMEPS 0xFC0A -#define HERMES_RID_CNFMULTICASTRECEIVE 0xFC0B -#define HERMES_RID_CNFMAXSLEEPDURATION 0xFC0C -#define HERMES_RID_CNFPMHOLDOVERDURATION 0xFC0D -#define HERMES_RID_CNFOWNNAME 0xFC0E -#define HERMES_RID_CNFOWNDTIMPERIOD 0xFC10 -#define HERMES_RID_CNFWDSADDRESS1 0xFC11 -#define HERMES_RID_CNFWDSADDRESS2 0xFC12 -#define HERMES_RID_CNFWDSADDRESS3 0xFC13 -#define HERMES_RID_CNFWDSADDRESS4 0xFC14 -#define HERMES_RID_CNFWDSADDRESS5 0xFC15 -#define HERMES_RID_CNFWDSADDRESS6 0xFC16 -#define HERMES_RID_CNFMULTICASTPMBUFFERING 0xFC17 -#define HERMES_RID_CNFWEPENABLED_AGERE 0xFC20 -#define HERMES_RID_CNFAUTHENTICATION_AGERE 0xFC21 -#define HERMES_RID_CNFMANDATORYBSSID_SYMBOL 0xFC21 -#define HERMES_RID_CNFDROPUNENCRYPTED 0xFC22 -#define HERMES_RID_CNFWEPDEFAULTKEYID 0xFC23 -#define HERMES_RID_CNFDEFAULTKEY0 0xFC24 -#define HERMES_RID_CNFDEFAULTKEY1 0xFC25 -#define HERMES_RID_CNFMWOROBUST_AGERE 0xFC25 -#define HERMES_RID_CNFDEFAULTKEY2 0xFC26 -#define HERMES_RID_CNFDEFAULTKEY3 0xFC27 -#define HERMES_RID_CNFWEPFLAGS_INTERSIL 0xFC28 -#define HERMES_RID_CNFWEPKEYMAPPINGTABLE 0xFC29 -#define HERMES_RID_CNFAUTHENTICATION 0xFC2A -#define HERMES_RID_CNFMAXASSOCSTA 0xFC2B -#define HERMES_RID_CNFKEYLENGTH_SYMBOL 0xFC2B -#define HERMES_RID_CNFTXCONTROL 0xFC2C -#define HERMES_RID_CNFROAMINGMODE 0xFC2D -#define HERMES_RID_CNFHOSTAUTHENTICATION 0xFC2E -#define HERMES_RID_CNFRCVCRCERROR 0xFC30 -#define HERMES_RID_CNFMMLIFE 0xFC31 -#define HERMES_RID_CNFALTRETRYCOUNT 0xFC32 -#define HERMES_RID_CNFBEACONINT 0xFC33 -#define HERMES_RID_CNFAPPCFINFO 0xFC34 -#define HERMES_RID_CNFSTAPCFINFO 0xFC35 -#define HERMES_RID_CNFPRIORITYQUSAGE 0xFC37 -#define HERMES_RID_CNFTIMCTRL 0xFC40 -#define HERMES_RID_CNFTHIRTY2TALLY 0xFC42 -#define HERMES_RID_CNFENHSECURITY 0xFC43 -#define HERMES_RID_CNFGROUPADDRESSES 0xFC80 -#define HERMES_RID_CNFCREATEIBSS 0xFC81 -#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD 0xFC82 -#define HERMES_RID_CNFRTSTHRESHOLD 0xFC83 -#define HERMES_RID_CNFTXRATECONTROL 0xFC84 -#define HERMES_RID_CNFPROMISCUOUSMODE 0xFC85 -#define HERMES_RID_CNFBASICRATES_SYMBOL 0xFC8A -#define HERMES_RID_CNFPREAMBLE_SYMBOL 0xFC8C -#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD0 0xFC90 -#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD1 0xFC91 -#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD2 0xFC92 -#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD3 0xFC93 -#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD4 0xFC94 -#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD5 0xFC95 -#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD6 0xFC96 -#define HERMES_RID_CNFRTSTHRESHOLD0 0xFC97 -#define HERMES_RID_CNFRTSTHRESHOLD1 0xFC98 -#define HERMES_RID_CNFRTSTHRESHOLD2 0xFC99 -#define HERMES_RID_CNFRTSTHRESHOLD3 0xFC9A -#define HERMES_RID_CNFRTSTHRESHOLD4 0xFC9B -#define HERMES_RID_CNFRTSTHRESHOLD5 0xFC9C -#define HERMES_RID_CNFRTSTHRESHOLD6 0xFC9D -#define HERMES_RID_CNFHOSTSCAN_SYMBOL 0xFCAB -#define HERMES_RID_CNFSHORTPREAMBLE 0xFCB0 -#define HERMES_RID_CNFWEPKEYS_AGERE 0xFCB0 -#define HERMES_RID_CNFEXCLUDELONGPREAMBLE 0xFCB1 -#define HERMES_RID_CNFTXKEY_AGERE 0xFCB1 -#define HERMES_RID_CNFAUTHENTICATIONRSPTO 0xFCB2 -#define HERMES_RID_CNFSCANSSID_AGERE 0xFCB2 -#define HERMES_RID_CNFBASICRATES 0xFCB3 -#define HERMES_RID_CNFSUPPORTEDRATES 0xFCB4 -#define HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE 0xFCB4 -#define HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE 0xFCB5 -#define HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE 0xFCB6 -#define HERMES_RID_CNFADDMAPPEDTKIPKEY_AGERE 0xFCB7 -#define HERMES_RID_CNFREMMAPPEDTKIPKEY_AGERE 0xFCB8 -#define HERMES_RID_CNFSETWPACAPABILITIES_AGERE 0xFCB9 -#define HERMES_RID_CNFCACHEDPMKADDRESS 0xFCBA -#define HERMES_RID_CNFREMOVEPMKADDRESS 0xFCBB -#define HERMES_RID_CNFSCANCHANNELS2GHZ 0xFCC2 -#define HERMES_RID_CNFDISASSOCIATE 0xFCC8 -#define HERMES_RID_CNFTICKTIME 0xFCE0 -#define HERMES_RID_CNFSCANREQUEST 0xFCE1 -#define HERMES_RID_CNFJOINREQUEST 0xFCE2 -#define HERMES_RID_CNFAUTHENTICATESTATION 0xFCE3 -#define HERMES_RID_CNFCHANNELINFOREQUEST 0xFCE4 -#define HERMES_RID_CNFHOSTSCAN 0xFCE5 - -/* - * Information RIDs - */ -#define HERMES_RID_MAXLOADTIME 0xFD00 -#define HERMES_RID_DOWNLOADBUFFER 0xFD01 -#define HERMES_RID_PRIID 0xFD02 -#define HERMES_RID_PRISUPRANGE 0xFD03 -#define HERMES_RID_CFIACTRANGES 0xFD04 -#define HERMES_RID_NICSERNUM 0xFD0A -#define HERMES_RID_NICID 0xFD0B -#define HERMES_RID_MFISUPRANGE 0xFD0C -#define HERMES_RID_CFISUPRANGE 0xFD0D -#define HERMES_RID_CHANNELLIST 0xFD10 -#define HERMES_RID_REGULATORYDOMAINS 0xFD11 -#define HERMES_RID_TEMPTYPE 0xFD12 -#define HERMES_RID_CIS 0xFD13 -#define HERMES_RID_STAID 0xFD20 -#define HERMES_RID_STASUPRANGE 0xFD21 -#define HERMES_RID_MFIACTRANGES 0xFD22 -#define HERMES_RID_CFIACTRANGES2 0xFD23 -#define HERMES_RID_SECONDARYVERSION_SYMBOL 0xFD24 -#define HERMES_RID_PORTSTATUS 0xFD40 -#define HERMES_RID_CURRENTSSID 0xFD41 -#define HERMES_RID_CURRENTBSSID 0xFD42 -#define HERMES_RID_COMMSQUALITY 0xFD43 -#define HERMES_RID_CURRENTTXRATE 0xFD44 -#define HERMES_RID_CURRENTBEACONINTERVAL 0xFD45 -#define HERMES_RID_CURRENTSCALETHRESHOLDS 0xFD46 -#define HERMES_RID_PROTOCOLRSPTIME 0xFD47 -#define HERMES_RID_SHORTRETRYLIMIT 0xFD48 -#define HERMES_RID_LONGRETRYLIMIT 0xFD49 -#define HERMES_RID_MAXTRANSMITLIFETIME 0xFD4A -#define HERMES_RID_MAXRECEIVELIFETIME 0xFD4B -#define HERMES_RID_CFPOLLABLE 0xFD4C -#define HERMES_RID_AUTHENTICATIONALGORITHMS 0xFD4D -#define HERMES_RID_PRIVACYOPTIONIMPLEMENTED 0xFD4F -#define HERMES_RID_DBMCOMMSQUALITY_INTERSIL 0xFD51 -#define HERMES_RID_CURRENTTXRATE1 0xFD80 -#define HERMES_RID_CURRENTTXRATE2 0xFD81 -#define HERMES_RID_CURRENTTXRATE3 0xFD82 -#define HERMES_RID_CURRENTTXRATE4 0xFD83 -#define HERMES_RID_CURRENTTXRATE5 0xFD84 -#define HERMES_RID_CURRENTTXRATE6 0xFD85 -#define HERMES_RID_OWNMACADDR 0xFD86 -#define HERMES_RID_SCANRESULTSTABLE 0xFD88 -#define HERMES_RID_CURRENT_COUNTRY_INFO 0xFD89 -#define HERMES_RID_CURRENT_WPA_IE 0xFD8A -#define HERMES_RID_CURRENT_TKIP_IV 0xFD8B -#define HERMES_RID_CURRENT_ASSOC_REQ_INFO 0xFD8C -#define HERMES_RID_CURRENT_ASSOC_RESP_INFO 0xFD8D -#define HERMES_RID_TXQUEUEEMPTY 0xFD91 -#define HERMES_RID_PHYTYPE 0xFDC0 -#define HERMES_RID_CURRENTCHANNEL 0xFDC1 -#define HERMES_RID_CURRENTPOWERSTATE 0xFDC2 -#define HERMES_RID_CCAMODE 0xFDC3 -#define HERMES_RID_SUPPORTEDDATARATES 0xFDC6 -#define HERMES_RID_BUILDSEQ 0xFFFE -#define HERMES_RID_FWID 0xFFFF - -#endif diff --git a/drivers/net/wireless/intersil/orinoco/hw.c b/drivers/net/wireless/intersil/orinoco/hw.c deleted file mode 100644 index 4fcca08e50de2..0000000000000 --- a/drivers/net/wireless/intersil/orinoco/hw.c +++ /dev/null @@ -1,1362 +0,0 @@ -/* Encapsulate basic setting changes and retrieval on Hermes hardware - * - * See copyright notice in main.c - */ -#include -#include -#include -#include -#include -#include -#include "hermes.h" -#include "hermes_rid.h" -#include "orinoco.h" - -#include "hw.h" - -#define SYMBOL_MAX_VER_LEN (14) - -/* Symbol firmware has a bug allocating buffers larger than this */ -#define TX_NICBUF_SIZE_BUG 1585 - -/********************************************************************/ -/* Data tables */ -/********************************************************************/ - -/* This tables gives the actual meanings of the bitrate IDs returned - * by the firmware. */ -static const struct { - int bitrate; /* in 100s of kilobits */ - int automatic; - u16 agere_txratectrl; - u16 intersil_txratectrl; -} bitrate_table[] = { - {110, 1, 3, 15}, /* Entry 0 is the default */ - {10, 0, 1, 1}, - {10, 1, 1, 1}, - {20, 0, 2, 2}, - {20, 1, 6, 3}, - {55, 0, 4, 4}, - {55, 1, 7, 7}, - {110, 0, 5, 8}, -}; -#define BITRATE_TABLE_SIZE ARRAY_SIZE(bitrate_table) - -/* Firmware version encoding */ -struct comp_id { - u16 id, variant, major, minor; -} __packed; - -static inline enum fwtype determine_firmware_type(struct comp_id *nic_id) -{ - if (nic_id->id < 0x8000) - return FIRMWARE_TYPE_AGERE; - else if (nic_id->id == 0x8000 && nic_id->major == 0) - return FIRMWARE_TYPE_SYMBOL; - else - return FIRMWARE_TYPE_INTERSIL; -} - -/* Set priv->firmware type, determine firmware properties - * This function can be called before we have registerred with netdev, - * so all errors go out with dev_* rather than printk - * - * If non-NULL stores a firmware description in fw_name. - * If non-NULL stores a HW version in hw_ver - * - * These are output via generic cfg80211 ethtool support. - */ -int determine_fw_capabilities(struct orinoco_private *priv, - char *fw_name, size_t fw_name_len, - u32 *hw_ver) -{ - struct device *dev = priv->dev; - struct hermes *hw = &priv->hw; - int err; - struct comp_id nic_id, sta_id; - unsigned int firmver; - char tmp[SYMBOL_MAX_VER_LEN + 1] __attribute__((aligned(2))); - - /* Get the hardware version */ - err = HERMES_READ_RECORD_PR(hw, USER_BAP, HERMES_RID_NICID, &nic_id); - if (err) { - dev_err(dev, "Cannot read hardware identity: error %d\n", - err); - return err; - } - - le16_to_cpus(&nic_id.id); - le16_to_cpus(&nic_id.variant); - le16_to_cpus(&nic_id.major); - le16_to_cpus(&nic_id.minor); - dev_info(dev, "Hardware identity %04x:%04x:%04x:%04x\n", - nic_id.id, nic_id.variant, nic_id.major, nic_id.minor); - - if (hw_ver) - *hw_ver = (((nic_id.id & 0xff) << 24) | - ((nic_id.variant & 0xff) << 16) | - ((nic_id.major & 0xff) << 8) | - (nic_id.minor & 0xff)); - - priv->firmware_type = determine_firmware_type(&nic_id); - - /* Get the firmware version */ - err = HERMES_READ_RECORD_PR(hw, USER_BAP, HERMES_RID_STAID, &sta_id); - if (err) { - dev_err(dev, "Cannot read station identity: error %d\n", - err); - return err; - } - - le16_to_cpus(&sta_id.id); - le16_to_cpus(&sta_id.variant); - le16_to_cpus(&sta_id.major); - le16_to_cpus(&sta_id.minor); - dev_info(dev, "Station identity %04x:%04x:%04x:%04x\n", - sta_id.id, sta_id.variant, sta_id.major, sta_id.minor); - - switch (sta_id.id) { - case 0x15: - dev_err(dev, "Primary firmware is active\n"); - return -ENODEV; - case 0x14b: - dev_err(dev, "Tertiary firmware is active\n"); - return -ENODEV; - case 0x1f: /* Intersil, Agere, Symbol Spectrum24 */ - case 0x21: /* Symbol Spectrum24 Trilogy */ - break; - default: - dev_notice(dev, "Unknown station ID, please report\n"); - break; - } - - /* Default capabilities */ - priv->has_sensitivity = 1; - priv->has_mwo = 0; - priv->has_preamble = 0; - priv->has_port3 = 1; - priv->has_ibss = 1; - priv->has_wep = 0; - priv->has_big_wep = 0; - priv->has_alt_txcntl = 0; - priv->has_ext_scan = 0; - priv->has_wpa = 0; - priv->do_fw_download = 0; - - /* Determine capabilities from the firmware version */ - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: - /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout, - ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */ - if (fw_name) - snprintf(fw_name, fw_name_len, "Lucent/Agere %d.%02d", - sta_id.major, sta_id.minor); - - firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor; - - priv->has_ibss = (firmver >= 0x60006); - priv->has_wep = (firmver >= 0x40020); - priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell - Gold cards from the others? */ - priv->has_mwo = (firmver >= 0x60000); - priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */ - priv->ibss_port = 1; - priv->has_hostscan = (firmver >= 0x8000a); - priv->do_fw_download = 1; - priv->broken_monitor = (firmver >= 0x80000); - priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */ - priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */ - priv->has_wpa = (firmver >= 0x9002a); - /* Tested with Agere firmware : - * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II - * Tested CableTron firmware : 4.32 => Anton */ - break; - case FIRMWARE_TYPE_SYMBOL: - /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */ - /* Intel MAC : 00:02:B3:* */ - /* 3Com MAC : 00:50:DA:* */ - memset(tmp, 0, sizeof(tmp)); - /* Get the Symbol firmware version */ - err = hw->ops->read_ltv_pr(hw, USER_BAP, - HERMES_RID_SECONDARYVERSION_SYMBOL, - SYMBOL_MAX_VER_LEN, NULL, &tmp); - if (err) { - dev_warn(dev, "Error %d reading Symbol firmware info. " - "Wildly guessing capabilities...\n", err); - firmver = 0; - tmp[0] = '\0'; - } else { - /* The firmware revision is a string, the format is - * something like : "V2.20-01". - * Quick and dirty parsing... - Jean II - */ - firmver = ((tmp[1] - '0') << 16) - | ((tmp[3] - '0') << 12) - | ((tmp[4] - '0') << 8) - | ((tmp[6] - '0') << 4) - | (tmp[7] - '0'); - - tmp[SYMBOL_MAX_VER_LEN] = '\0'; - } - - if (fw_name) - snprintf(fw_name, fw_name_len, "Symbol %s", tmp); - - priv->has_ibss = (firmver >= 0x20000); - priv->has_wep = (firmver >= 0x15012); - priv->has_big_wep = (firmver >= 0x20000); - priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) || - (firmver >= 0x29000 && firmver < 0x30000) || - firmver >= 0x31000; - priv->has_preamble = (firmver >= 0x20000); - priv->ibss_port = 4; - - /* Symbol firmware is found on various cards, but - * there has been no attempt to check firmware - * download on non-spectrum_cs based cards. - * - * Given that the Agere firmware download works - * differently, we should avoid doing a firmware - * download with the Symbol algorithm on non-spectrum - * cards. - * - * For now we can identify a spectrum_cs based card - * because it has a firmware reset function. - */ - priv->do_fw_download = (priv->stop_fw != NULL); - - priv->broken_disableport = (firmver == 0x25013) || - (firmver >= 0x30000 && firmver <= 0x31000); - priv->has_hostscan = (firmver >= 0x31001) || - (firmver >= 0x29057 && firmver < 0x30000); - /* Tested with Intel firmware : 0x20015 => Jean II */ - /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */ - break; - case FIRMWARE_TYPE_INTERSIL: - /* D-Link, Linksys, Adtron, ZoomAir, and many others... - * Samsung, Compaq 100/200 and Proxim are slightly - * different and less well tested */ - /* D-Link MAC : 00:40:05:* */ - /* Addtron MAC : 00:90:D1:* */ - if (fw_name) - snprintf(fw_name, fw_name_len, "Intersil %d.%d.%d", - sta_id.major, sta_id.minor, sta_id.variant); - - firmver = ((unsigned long)sta_id.major << 16) | - ((unsigned long)sta_id.minor << 8) | sta_id.variant; - - priv->has_ibss = (firmver >= 0x000700); /* FIXME */ - priv->has_big_wep = priv->has_wep = (firmver >= 0x000800); - priv->has_pm = (firmver >= 0x000700); - priv->has_hostscan = (firmver >= 0x010301); - - if (firmver >= 0x000800) - priv->ibss_port = 0; - else { - dev_notice(dev, "Intersil firmware earlier than v0.8.x" - " - several features not supported\n"); - priv->ibss_port = 1; - } - break; - } - if (fw_name) - dev_info(dev, "Firmware determined as %s\n", fw_name); - -#ifndef CONFIG_HERMES_PRISM - if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL) { - dev_err(dev, "Support for Prism chipset is not enabled\n"); - return -ENODEV; - } -#endif - - return 0; -} - -/* Read settings from EEPROM into our private structure. - * MAC address gets dropped into callers buffer - * Can be called before netdev registration. - */ -int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr) -{ - struct device *dev = priv->dev; - struct hermes_idstring nickbuf; - struct hermes *hw = &priv->hw; - int len; - int err; - u16 reclen; - - /* Get the MAC address */ - err = hw->ops->read_ltv_pr(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, - ETH_ALEN, NULL, dev_addr); - if (err) { - dev_warn(dev, "Failed to read MAC address!\n"); - goto out; - } - - dev_dbg(dev, "MAC address %pM\n", dev_addr); - - /* Get the station name */ - err = hw->ops->read_ltv_pr(hw, USER_BAP, HERMES_RID_CNFOWNNAME, - sizeof(nickbuf), &reclen, &nickbuf); - if (err) { - dev_err(dev, "failed to read station name\n"); - goto out; - } - if (nickbuf.len) - len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len)); - else - len = min(IW_ESSID_MAX_SIZE, 2 * reclen); - memcpy(priv->nick, &nickbuf.val, len); - priv->nick[len] = '\0'; - - dev_dbg(dev, "Station name \"%s\"\n", priv->nick); - - /* Get allowed channels */ - err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_CHANNELLIST, - &priv->channel_mask); - if (err) { - dev_err(dev, "Failed to read channel list!\n"); - goto out; - } - - /* Get initial AP density */ - err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE, - &priv->ap_density); - if (err || priv->ap_density < 1 || priv->ap_density > 3) - priv->has_sensitivity = 0; - - /* Get initial RTS threshold */ - err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, - &priv->rts_thresh); - if (err) { - dev_err(dev, "Failed to read RTS threshold!\n"); - goto out; - } - - /* Get initial fragmentation settings */ - if (priv->has_mwo) - err = hermes_read_wordrec_pr(hw, USER_BAP, - HERMES_RID_CNFMWOROBUST_AGERE, - &priv->mwo_robust); - else - err = hermes_read_wordrec_pr(hw, USER_BAP, - HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, - &priv->frag_thresh); - if (err) { - dev_err(dev, "Failed to read fragmentation settings!\n"); - goto out; - } - - /* Power management setup */ - if (priv->has_pm) { - priv->pm_on = 0; - priv->pm_mcast = 1; - err = hermes_read_wordrec_pr(hw, USER_BAP, - HERMES_RID_CNFMAXSLEEPDURATION, - &priv->pm_period); - if (err) { - dev_err(dev, "Failed to read power management " - "period!\n"); - goto out; - } - err = hermes_read_wordrec_pr(hw, USER_BAP, - HERMES_RID_CNFPMHOLDOVERDURATION, - &priv->pm_timeout); - if (err) { - dev_err(dev, "Failed to read power management " - "timeout!\n"); - goto out; - } - } - - /* Preamble setup */ - if (priv->has_preamble) { - err = hermes_read_wordrec_pr(hw, USER_BAP, - HERMES_RID_CNFPREAMBLE_SYMBOL, - &priv->preamble); - if (err) { - dev_err(dev, "Failed to read preamble setup\n"); - goto out; - } - } - - /* Retry settings */ - err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_SHORTRETRYLIMIT, - &priv->short_retry_limit); - if (err) { - dev_err(dev, "Failed to read short retry limit\n"); - goto out; - } - - err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_LONGRETRYLIMIT, - &priv->long_retry_limit); - if (err) { - dev_err(dev, "Failed to read long retry limit\n"); - goto out; - } - - err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_MAXTRANSMITLIFETIME, - &priv->retry_lifetime); - if (err) { - dev_err(dev, "Failed to read max retry lifetime\n"); - goto out; - } - -out: - return err; -} - -/* Can be called before netdev registration */ -int orinoco_hw_allocate_fid(struct orinoco_private *priv) -{ - struct device *dev = priv->dev; - struct hermes *hw = &priv->hw; - int err; - - err = hw->ops->allocate(hw, priv->nicbuf_size, &priv->txfid); - if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) { - /* Try workaround for old Symbol firmware bug */ - priv->nicbuf_size = TX_NICBUF_SIZE_BUG; - err = hw->ops->allocate(hw, priv->nicbuf_size, &priv->txfid); - - dev_warn(dev, "Firmware ALLOC bug detected " - "(old Symbol firmware?). Work around %s\n", - err ? "failed!" : "ok."); - } - - return err; -} - -int orinoco_get_bitratemode(int bitrate, int automatic) -{ - int ratemode = -1; - int i; - - if ((bitrate != 10) && (bitrate != 20) && - (bitrate != 55) && (bitrate != 110)) - return ratemode; - - for (i = 0; i < BITRATE_TABLE_SIZE; i++) { - if ((bitrate_table[i].bitrate == bitrate) && - (bitrate_table[i].automatic == automatic)) { - ratemode = i; - break; - } - } - return ratemode; -} - -void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic) -{ - BUG_ON((ratemode < 0) || (ratemode >= BITRATE_TABLE_SIZE)); - - *bitrate = bitrate_table[ratemode].bitrate * 100000; - *automatic = bitrate_table[ratemode].automatic; -} - -int orinoco_hw_program_rids(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - struct wireless_dev *wdev = netdev_priv(dev); - struct hermes *hw = &priv->hw; - int err; - struct hermes_idstring idbuf; - - /* Set the MAC address */ - err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, - HERMES_BYTES_TO_RECLEN(ETH_ALEN), - dev->dev_addr); - if (err) { - printk(KERN_ERR "%s: Error %d setting MAC address\n", - dev->name, err); - return err; - } - - /* Set up the link mode */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE, - priv->port_type); - if (err) { - printk(KERN_ERR "%s: Error %d setting port type\n", - dev->name, err); - return err; - } - /* Set the channel/frequency */ - if (priv->channel != 0 && priv->iw_mode != NL80211_IFTYPE_STATION) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFOWNCHANNEL, - priv->channel); - if (err) { - printk(KERN_ERR "%s: Error %d setting channel %d\n", - dev->name, err, priv->channel); - return err; - } - } - - if (priv->has_ibss) { - u16 createibss; - - if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) { - printk(KERN_WARNING "%s: This firmware requires an " - "ESSID in IBSS-Ad-Hoc mode.\n", dev->name); - /* With wvlan_cs, in this case, we would crash. - * hopefully, this driver will behave better... - * Jean II */ - createibss = 0; - } else { - createibss = priv->createibss; - } - - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFCREATEIBSS, - createibss); - if (err) { - printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n", - dev->name, err); - return err; - } - } - - /* Set the desired BSSID */ - err = __orinoco_hw_set_wap(priv); - if (err) { - printk(KERN_ERR "%s: Error %d setting AP address\n", - dev->name, err); - return err; - } - - /* Set the desired ESSID */ - idbuf.len = cpu_to_le16(strlen(priv->desired_essid)); - memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val)); - /* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */ - err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID, - HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid) + 2), - &idbuf); - if (err) { - printk(KERN_ERR "%s: Error %d setting OWNSSID\n", - dev->name, err); - return err; - } - err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID, - HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid) + 2), - &idbuf); - if (err) { - printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n", - dev->name, err); - return err; - } - - /* Set the station name */ - idbuf.len = cpu_to_le16(strlen(priv->nick)); - memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val)); - err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, - HERMES_BYTES_TO_RECLEN(strlen(priv->nick) + 2), - &idbuf); - if (err) { - printk(KERN_ERR "%s: Error %d setting nickname\n", - dev->name, err); - return err; - } - - /* Set AP density */ - if (priv->has_sensitivity) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFSYSTEMSCALE, - priv->ap_density); - if (err) { - printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. " - "Disabling sensitivity control\n", - dev->name, err); - - priv->has_sensitivity = 0; - } - } - - /* Set RTS threshold */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, - priv->rts_thresh); - if (err) { - printk(KERN_ERR "%s: Error %d setting RTS threshold\n", - dev->name, err); - return err; - } - - /* Set fragmentation threshold or MWO robustness */ - if (priv->has_mwo) - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFMWOROBUST_AGERE, - priv->mwo_robust); - else - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, - priv->frag_thresh); - if (err) { - printk(KERN_ERR "%s: Error %d setting fragmentation\n", - dev->name, err); - return err; - } - - /* Set bitrate */ - err = __orinoco_hw_set_bitrate(priv); - if (err) { - printk(KERN_ERR "%s: Error %d setting bitrate\n", - dev->name, err); - return err; - } - - /* Set power management */ - if (priv->has_pm) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFPMENABLED, - priv->pm_on); - if (err) { - printk(KERN_ERR "%s: Error %d setting up PM\n", - dev->name, err); - return err; - } - - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFMULTICASTRECEIVE, - priv->pm_mcast); - if (err) { - printk(KERN_ERR "%s: Error %d setting up PM\n", - dev->name, err); - return err; - } - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFMAXSLEEPDURATION, - priv->pm_period); - if (err) { - printk(KERN_ERR "%s: Error %d setting up PM\n", - dev->name, err); - return err; - } - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFPMHOLDOVERDURATION, - priv->pm_timeout); - if (err) { - printk(KERN_ERR "%s: Error %d setting up PM\n", - dev->name, err); - return err; - } - } - - /* Set preamble - only for Symbol so far... */ - if (priv->has_preamble) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFPREAMBLE_SYMBOL, - priv->preamble); - if (err) { - printk(KERN_ERR "%s: Error %d setting preamble\n", - dev->name, err); - return err; - } - } - - /* Set up encryption */ - if (priv->has_wep || priv->has_wpa) { - err = __orinoco_hw_setup_enc(priv); - if (err) { - printk(KERN_ERR "%s: Error %d activating encryption\n", - dev->name, err); - return err; - } - } - - if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { - /* Enable monitor mode */ - dev->type = ARPHRD_IEEE80211; - err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST | - HERMES_TEST_MONITOR, 0, NULL); - } else { - /* Disable monitor mode */ - dev->type = ARPHRD_ETHER; - err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST | - HERMES_TEST_STOP, 0, NULL); - } - if (err) - return err; - - /* Reset promiscuity / multicast*/ - priv->promiscuous = 0; - priv->mc_count = 0; - - /* Record mode change */ - wdev->iftype = priv->iw_mode; - - return 0; -} - -/* Get tsc from the firmware */ -int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc) -{ - struct hermes *hw = &priv->hw; - int err = 0; - u8 tsc_arr[4][ORINOCO_SEQ_LEN]; - - if ((key < 0) || (key >= 4)) - return -EINVAL; - - err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_TKIP_IV, - sizeof(tsc_arr), NULL, &tsc_arr); - if (!err) - memcpy(tsc, &tsc_arr[key][0], sizeof(tsc_arr[0])); - - return err; -} - -int __orinoco_hw_set_bitrate(struct orinoco_private *priv) -{ - struct hermes *hw = &priv->hw; - int ratemode = priv->bitratemode; - int err = 0; - - if (ratemode >= BITRATE_TABLE_SIZE) { - printk(KERN_ERR "%s: BUG: Invalid bitrate mode %d\n", - priv->ndev->name, ratemode); - return -EINVAL; - } - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFTXRATECONTROL, - bitrate_table[ratemode].agere_txratectrl); - break; - case FIRMWARE_TYPE_INTERSIL: - case FIRMWARE_TYPE_SYMBOL: - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFTXRATECONTROL, - bitrate_table[ratemode].intersil_txratectrl); - break; - default: - BUG(); - } - - return err; -} - -int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate) -{ - struct hermes *hw = &priv->hw; - int i; - int err = 0; - u16 val; - - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CURRENTTXRATE, &val); - if (err) - return err; - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: /* Lucent style rate */ - /* Note : in Lucent firmware, the return value of - * HERMES_RID_CURRENTTXRATE is the bitrate in Mb/s, - * and therefore is totally different from the - * encoding of HERMES_RID_CNFTXRATECONTROL. - * Don't forget that 6Mb/s is really 5.5Mb/s */ - if (val == 6) - *bitrate = 5500000; - else - *bitrate = val * 1000000; - break; - case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */ - case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */ - for (i = 0; i < BITRATE_TABLE_SIZE; i++) - if (bitrate_table[i].intersil_txratectrl == val) { - *bitrate = bitrate_table[i].bitrate * 100000; - break; - } - - if (i >= BITRATE_TABLE_SIZE) { - printk(KERN_INFO "%s: Unable to determine current bitrate (0x%04hx)\n", - priv->ndev->name, val); - err = -EIO; - } - - break; - default: - BUG(); - } - - return err; -} - -/* Set fixed AP address */ -int __orinoco_hw_set_wap(struct orinoco_private *priv) -{ - int roaming_flag; - int err = 0; - struct hermes *hw = &priv->hw; - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: - /* not supported */ - break; - case FIRMWARE_TYPE_INTERSIL: - if (priv->bssid_fixed) - roaming_flag = 2; - else - roaming_flag = 1; - - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFROAMINGMODE, - roaming_flag); - break; - case FIRMWARE_TYPE_SYMBOL: - err = HERMES_WRITE_RECORD(hw, USER_BAP, - HERMES_RID_CNFMANDATORYBSSID_SYMBOL, - &priv->desired_bssid); - break; - } - return err; -} - -/* Change the WEP keys and/or the current keys. Can be called - * either from __orinoco_hw_setup_enc() or directly from - * orinoco_ioctl_setiwencode(). In the later case the association - * with the AP is not broken (if the firmware can handle it), - * which is needed for 802.1x implementations. */ -int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv) -{ - struct hermes *hw = &priv->hw; - int err = 0; - int i; - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: - { - struct orinoco_key keys[ORINOCO_MAX_KEYS]; - - memset(&keys, 0, sizeof(keys)); - for (i = 0; i < ORINOCO_MAX_KEYS; i++) { - int len = min(priv->keys[i].key_len, - ORINOCO_MAX_KEY_SIZE); - memcpy(&keys[i].data, priv->keys[i].key, len); - if (len > SMALL_KEY_SIZE) - keys[i].len = cpu_to_le16(LARGE_KEY_SIZE); - else if (len > 0) - keys[i].len = cpu_to_le16(SMALL_KEY_SIZE); - else - keys[i].len = cpu_to_le16(0); - } - - err = HERMES_WRITE_RECORD(hw, USER_BAP, - HERMES_RID_CNFWEPKEYS_AGERE, - &keys); - if (err) - return err; - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFTXKEY_AGERE, - priv->tx_key); - if (err) - return err; - break; - } - case FIRMWARE_TYPE_INTERSIL: - case FIRMWARE_TYPE_SYMBOL: - { - int keylen; - - /* Force uniform key length to work around - * firmware bugs */ - keylen = priv->keys[priv->tx_key].key_len; - - if (keylen > LARGE_KEY_SIZE) { - printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n", - priv->ndev->name, priv->tx_key, keylen); - return -E2BIG; - } else if (keylen > SMALL_KEY_SIZE) - keylen = LARGE_KEY_SIZE; - else if (keylen > 0) - keylen = SMALL_KEY_SIZE; - else - keylen = 0; - - /* Write all 4 keys */ - for (i = 0; i < ORINOCO_MAX_KEYS; i++) { - u8 key[LARGE_KEY_SIZE] = { 0 }; - - memcpy(key, priv->keys[i].key, - priv->keys[i].key_len); - - err = hw->ops->write_ltv(hw, USER_BAP, - HERMES_RID_CNFDEFAULTKEY0 + i, - HERMES_BYTES_TO_RECLEN(keylen), - key); - if (err) - return err; - } - - /* Write the index of the key used in transmission */ - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFWEPDEFAULTKEYID, - priv->tx_key); - if (err) - return err; - } - break; - } - - return 0; -} - -int __orinoco_hw_setup_enc(struct orinoco_private *priv) -{ - struct hermes *hw = &priv->hw; - int err = 0; - int master_wep_flag; - int auth_flag; - int enc_flag; - - /* Setup WEP keys */ - if (priv->encode_alg == ORINOCO_ALG_WEP) - __orinoco_hw_setup_wepkeys(priv); - - if (priv->wep_restrict) - auth_flag = HERMES_AUTH_SHARED_KEY; - else - auth_flag = HERMES_AUTH_OPEN; - - if (priv->wpa_enabled) - enc_flag = 2; - else if (priv->encode_alg == ORINOCO_ALG_WEP) - enc_flag = 1; - else - enc_flag = 0; - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: /* Agere style WEP */ - if (priv->encode_alg == ORINOCO_ALG_WEP) { - /* Enable the shared-key authentication. */ - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFAUTHENTICATION_AGERE, - auth_flag); - if (err) - return err; - } - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFWEPENABLED_AGERE, - enc_flag); - if (err) - return err; - - if (priv->has_wpa) { - /* Set WPA key management */ - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE, - priv->key_mgmt); - if (err) - return err; - } - - break; - - case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */ - case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ - if (priv->encode_alg == ORINOCO_ALG_WEP) { - if (priv->wep_restrict || - (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)) - master_wep_flag = HERMES_WEP_PRIVACY_INVOKED | - HERMES_WEP_EXCL_UNENCRYPTED; - else - master_wep_flag = HERMES_WEP_PRIVACY_INVOKED; - - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFAUTHENTICATION, - auth_flag); - if (err) - return err; - } else - master_wep_flag = 0; - - if (priv->iw_mode == NL80211_IFTYPE_MONITOR) - master_wep_flag |= HERMES_WEP_HOST_DECRYPT; - - /* Master WEP setting : on/off */ - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFWEPFLAGS_INTERSIL, - master_wep_flag); - if (err) - return err; - - break; - } - - return 0; -} - -/* key must be 32 bytes, including the tx and rx MIC keys. - * rsc must be NULL or up to 8 bytes - * tsc must be NULL or up to 8 bytes - */ -int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, - int set_tx, const u8 *key, size_t key_len, - const u8 *rsc, size_t rsc_len, - const u8 *tsc, size_t tsc_len) -{ - struct { - __le16 idx; - u8 rsc[ORINOCO_SEQ_LEN]; - struct { - u8 key[TKIP_KEYLEN]; - u8 tx_mic[MIC_KEYLEN]; - u8 rx_mic[MIC_KEYLEN]; - } tkip; - u8 tsc[ORINOCO_SEQ_LEN]; - } __packed buf; - struct hermes *hw = &priv->hw; - int ret; - int err; - int k; - u16 xmitting; - - key_idx &= 0x3; - - if (set_tx) - key_idx |= 0x8000; - - buf.idx = cpu_to_le16(key_idx); - if (key_len != sizeof(buf.tkip)) - return -EINVAL; - memcpy(&buf.tkip, key, sizeof(buf.tkip)); - - if (rsc_len > sizeof(buf.rsc)) - rsc_len = sizeof(buf.rsc); - - if (tsc_len > sizeof(buf.tsc)) - tsc_len = sizeof(buf.tsc); - - memset(buf.rsc, 0, sizeof(buf.rsc)); - memset(buf.tsc, 0, sizeof(buf.tsc)); - - if (rsc != NULL) - memcpy(buf.rsc, rsc, rsc_len); - - if (tsc != NULL) - memcpy(buf.tsc, tsc, tsc_len); - else - buf.tsc[4] = 0x10; - - /* Wait up to 100ms for tx queue to empty */ - for (k = 100; k > 0; k--) { - udelay(1000); - ret = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_TXQUEUEEMPTY, - &xmitting); - if (ret || !xmitting) - break; - } - - if (k == 0) - ret = -ETIMEDOUT; - - err = HERMES_WRITE_RECORD(hw, USER_BAP, - HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE, - &buf); - - return ret ? ret : err; -} - -int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx) -{ - struct hermes *hw = &priv->hw; - int err; - - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE, - key_idx); - if (err) - printk(KERN_WARNING "%s: Error %d clearing TKIP key %d\n", - priv->ndev->name, err, key_idx); - return err; -} - -int __orinoco_hw_set_multicast_list(struct orinoco_private *priv, - struct net_device *dev, - int mc_count, int promisc) -{ - struct hermes *hw = &priv->hw; - int err = 0; - - if (promisc != priv->promiscuous) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFPROMISCUOUSMODE, - promisc); - if (err) { - printk(KERN_ERR "%s: Error %d setting PROMISCUOUSMODE to 1.\n", - priv->ndev->name, err); - } else - priv->promiscuous = promisc; - } - - /* If we're not in promiscuous mode, then we need to set the - * group address if either we want to multicast, or if we were - * multicasting and want to stop */ - if (!promisc && (mc_count || priv->mc_count)) { - struct netdev_hw_addr *ha; - struct hermes_multicast mclist; - int i = 0; - - netdev_for_each_mc_addr(ha, dev) { - if (i == mc_count) - break; - memcpy(mclist.addr[i++], ha->addr, ETH_ALEN); - } - - err = hw->ops->write_ltv(hw, USER_BAP, - HERMES_RID_CNFGROUPADDRESSES, - HERMES_BYTES_TO_RECLEN(mc_count * ETH_ALEN), - &mclist); - if (err) - printk(KERN_ERR "%s: Error %d setting multicast list.\n", - priv->ndev->name, err); - else - priv->mc_count = mc_count; - } - return err; -} - -/* Return : < 0 -> error code ; >= 0 -> length */ -int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, - char buf[IW_ESSID_MAX_SIZE + 1]) -{ - struct hermes *hw = &priv->hw; - int err = 0; - struct hermes_idstring essidbuf; - char *p = (char *)(&essidbuf.val); - int len; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - if (strlen(priv->desired_essid) > 0) { - /* We read the desired SSID from the hardware rather - than from priv->desired_essid, just in case the - firmware is allowed to change it on us. I'm not - sure about this */ - /* My guess is that the OWNSSID should always be whatever - * we set to the card, whereas CURRENT_SSID is the one that - * may change... - Jean II */ - u16 rid; - - *active = 1; - - rid = (priv->port_type == 3) ? HERMES_RID_CNFOWNSSID : - HERMES_RID_CNFDESIREDSSID; - - err = hw->ops->read_ltv(hw, USER_BAP, rid, sizeof(essidbuf), - NULL, &essidbuf); - if (err) - goto fail_unlock; - } else { - *active = 0; - - err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID, - sizeof(essidbuf), NULL, &essidbuf); - if (err) - goto fail_unlock; - } - - len = le16_to_cpu(essidbuf.len); - BUG_ON(len > IW_ESSID_MAX_SIZE); - - memset(buf, 0, IW_ESSID_MAX_SIZE); - memcpy(buf, p, len); - err = len; - - fail_unlock: - orinoco_unlock(priv, &flags); - - return err; -} - -int orinoco_hw_get_freq(struct orinoco_private *priv) -{ - struct hermes *hw = &priv->hw; - int err = 0; - u16 channel; - int freq = 0; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL, - &channel); - if (err) - goto out; - - /* Intersil firmware 1.3.5 returns 0 when the interface is down */ - if (channel == 0) { - err = -EBUSY; - goto out; - } - - if ((channel < 1) || (channel > NUM_CHANNELS)) { - printk(KERN_WARNING "%s: Channel out of range (%d)!\n", - priv->ndev->name, channel); - err = -EBUSY; - goto out; - - } - freq = ieee80211_channel_to_frequency(channel, NL80211_BAND_2GHZ); - - out: - orinoco_unlock(priv, &flags); - - if (err > 0) - err = -EBUSY; - return err ? err : freq; -} - -int orinoco_hw_get_bitratelist(struct orinoco_private *priv, - int *numrates, s32 *rates, int max) -{ - struct hermes *hw = &priv->hw; - struct hermes_idstring list; - unsigned char *p = (unsigned char *)&list.val; - int err = 0; - int num; - int i; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES, - sizeof(list), NULL, &list); - orinoco_unlock(priv, &flags); - - if (err) - return err; - - num = le16_to_cpu(list.len); - *numrates = num; - num = min(num, max); - - for (i = 0; i < num; i++) - rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */ - - return 0; -} - -int orinoco_hw_trigger_scan(struct orinoco_private *priv, - const struct cfg80211_ssid *ssid) -{ - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - unsigned long flags; - int err = 0; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - /* Scanning with port 0 disabled would fail */ - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } - - /* In monitor mode, the scan results are always empty. - * Probe responses are passed to the driver as received - * frames and could be processed in software. */ - if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { - err = -EOPNOTSUPP; - goto out; - } - - if (priv->has_hostscan) { - switch (priv->firmware_type) { - case FIRMWARE_TYPE_SYMBOL: - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFHOSTSCAN_SYMBOL, - HERMES_HOSTSCAN_SYMBOL_ONCE | - HERMES_HOSTSCAN_SYMBOL_BCAST); - break; - case FIRMWARE_TYPE_INTERSIL: { - __le16 req[3]; - - req[0] = cpu_to_le16(0x3fff); /* All channels */ - req[1] = cpu_to_le16(0x0001); /* rate 1 Mbps */ - req[2] = 0; /* Any ESSID */ - err = HERMES_WRITE_RECORD(hw, USER_BAP, - HERMES_RID_CNFHOSTSCAN, &req); - break; - } - case FIRMWARE_TYPE_AGERE: - if (ssid->ssid_len > 0) { - struct hermes_idstring idbuf; - size_t len = ssid->ssid_len; - - idbuf.len = cpu_to_le16(len); - memcpy(idbuf.val, ssid->ssid, len); - - err = hw->ops->write_ltv(hw, USER_BAP, - HERMES_RID_CNFSCANSSID_AGERE, - HERMES_BYTES_TO_RECLEN(len + 2), - &idbuf); - } else - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFSCANSSID_AGERE, - 0); /* Any ESSID */ - if (err) - break; - - if (priv->has_ext_scan) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFSCANCHANNELS2GHZ, - 0x7FFF); - if (err) - goto out; - - err = hermes_inquire(hw, - HERMES_INQ_CHANNELINFO); - } else - err = hermes_inquire(hw, HERMES_INQ_SCAN); - - break; - } - } else - err = hermes_inquire(hw, HERMES_INQ_SCAN); - - out: - orinoco_unlock(priv, &flags); - - return err; -} - -/* Disassociate from node with BSSID addr */ -int orinoco_hw_disassociate(struct orinoco_private *priv, - u8 *addr, u16 reason_code) -{ - struct hermes *hw = &priv->hw; - int err; - - struct { - u8 addr[ETH_ALEN]; - __le16 reason_code; - } __packed buf; - - /* Currently only supported by WPA enabled Agere fw */ - if (!priv->has_wpa) - return -EOPNOTSUPP; - - memcpy(buf.addr, addr, ETH_ALEN); - buf.reason_code = cpu_to_le16(reason_code); - err = HERMES_WRITE_RECORD(hw, USER_BAP, - HERMES_RID_CNFDISASSOCIATE, - &buf); - return err; -} - -int orinoco_hw_get_current_bssid(struct orinoco_private *priv, - u8 *addr) -{ - struct hermes *hw = &priv->hw; - int err; - - err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID, - ETH_ALEN, NULL, addr); - - return err; -} diff --git a/drivers/net/wireless/intersil/orinoco/hw.h b/drivers/net/wireless/intersil/orinoco/hw.h deleted file mode 100644 index da5804dbdf34c..0000000000000 --- a/drivers/net/wireless/intersil/orinoco/hw.h +++ /dev/null @@ -1,60 +0,0 @@ -/* Encapsulate basic setting changes on Hermes hardware - * - * See copyright notice in main.c - */ -#ifndef _ORINOCO_HW_H_ -#define _ORINOCO_HW_H_ - -#include -#include -#include - -/* Hardware BAPs */ -#define USER_BAP 0 -#define IRQ_BAP 1 - -/* WEP key sizes */ -#define SMALL_KEY_SIZE 5 -#define LARGE_KEY_SIZE 13 - -/* Number of supported channels */ -#define NUM_CHANNELS 14 - -/* Forward declarations */ -struct orinoco_private; - -int determine_fw_capabilities(struct orinoco_private *priv, char *fw_name, - size_t fw_name_len, u32 *hw_ver); -int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr); -int orinoco_hw_allocate_fid(struct orinoco_private *priv); -int orinoco_get_bitratemode(int bitrate, int automatic); -void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic); - -int orinoco_hw_program_rids(struct orinoco_private *priv); -int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc); -int __orinoco_hw_set_bitrate(struct orinoco_private *priv); -int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate); -int __orinoco_hw_set_wap(struct orinoco_private *priv); -int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv); -int __orinoco_hw_setup_enc(struct orinoco_private *priv); -int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, - int set_tx, const u8 *key, size_t key_len, - const u8 *rsc, size_t rsc_len, - const u8 *tsc, size_t tsc_len); -int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx); -int __orinoco_hw_set_multicast_list(struct orinoco_private *priv, - struct net_device *dev, - int mc_count, int promisc); -int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, - char buf[IW_ESSID_MAX_SIZE + 1]); -int orinoco_hw_get_freq(struct orinoco_private *priv); -int orinoco_hw_get_bitratelist(struct orinoco_private *priv, - int *numrates, s32 *rates, int max); -int orinoco_hw_trigger_scan(struct orinoco_private *priv, - const struct cfg80211_ssid *ssid); -int orinoco_hw_disassociate(struct orinoco_private *priv, - u8 *addr, u16 reason_code); -int orinoco_hw_get_current_bssid(struct orinoco_private *priv, - u8 *addr); - -#endif /* _ORINOCO_HW_H_ */ diff --git a/drivers/net/wireless/intersil/orinoco/main.c b/drivers/net/wireless/intersil/orinoco/main.c deleted file mode 100644 index 7df88d20ff3dc..0000000000000 --- a/drivers/net/wireless/intersil/orinoco/main.c +++ /dev/null @@ -1,2414 +0,0 @@ -/* main.c - (formerly known as dldwd_cs.c, orinoco_cs.c and orinoco.c) - * - * A driver for Hermes or Prism 2 chipset based PCMCIA wireless - * adaptors, with Lucent/Agere, Intersil or Symbol firmware. - * - * Current maintainers (as of 29 September 2003) are: - * Pavel Roskin - * and David Gibson - * - * (C) Copyright David Gibson, IBM Corporation 2001-2003. - * Copyright (C) 2000 David Gibson, Linuxcare Australia. - * With some help from : - * Copyright (C) 2001 Jean Tourrilhes, HP Labs - * Copyright (C) 2001 Benjamin Herrenschmidt - * - * Based on dummy_cs.c 1.27 2000/06/12 21:27:25 - * - * Portions based on wvlan_cs.c 1.0.6, Copyright Andreas Neuhaus - * http://www.stud.fh-dortmund.de/~andy/wvlan/ - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * The initial developer of the original code is David A. Hinds - * . Portions created by David - * A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights - * Reserved. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. */ - -/* - * TODO - * o Handle de-encapsulation within network layer, provide 802.11 - * headers (patch from Thomas 'Dent' Mirlacher) - * o Fix possible races in SPY handling. - * o Disconnect wireless extensions from fundamental configuration. - * o (maybe) Software WEP support (patch from Stano Meduna). - * o (maybe) Use multiple Tx buffers - driver handling queue - * rather than firmware. - */ - -/* Locking and synchronization: - * - * The basic principle is that everything is serialized through a - * single spinlock, priv->lock. The lock is used in user, bh and irq - * context, so when taken outside hardirq context it should always be - * taken with interrupts disabled. The lock protects both the - * hardware and the struct orinoco_private. - * - * Another flag, priv->hw_unavailable indicates that the hardware is - * unavailable for an extended period of time (e.g. suspended, or in - * the middle of a hard reset). This flag is protected by the - * spinlock. All code which touches the hardware should check the - * flag after taking the lock, and if it is set, give up on whatever - * they are doing and drop the lock again. The orinoco_lock() - * function handles this (it unlocks and returns -EBUSY if - * hw_unavailable is non-zero). - */ - -#define DRIVER_NAME "orinoco" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "hermes_rid.h" -#include "hermes_dld.h" -#include "hw.h" -#include "scan.h" -#include "mic.h" -#include "fw.h" -#include "wext.h" -#include "cfg.h" -#include "main.h" - -#include "orinoco.h" - -/********************************************************************/ -/* Module information */ -/********************************************************************/ - -MODULE_AUTHOR("Pavel Roskin & " - "David Gibson "); -MODULE_DESCRIPTION("Driver for Lucent Orinoco, Prism II based " - "and similar wireless cards"); -MODULE_LICENSE("Dual MPL/GPL"); - -/* Level of debugging. Used in the macros in orinoco.h */ -#ifdef ORINOCO_DEBUG -int orinoco_debug = ORINOCO_DEBUG; -EXPORT_SYMBOL(orinoco_debug); -module_param(orinoco_debug, int, 0644); -MODULE_PARM_DESC(orinoco_debug, "Debug level"); -#endif - -static bool suppress_linkstatus; /* = 0 */ -module_param(suppress_linkstatus, bool, 0644); -MODULE_PARM_DESC(suppress_linkstatus, "Don't log link status changes"); - -static int ignore_disconnect; /* = 0 */ -module_param(ignore_disconnect, int, 0644); -MODULE_PARM_DESC(ignore_disconnect, - "Don't report lost link to the network layer"); - -int force_monitor; /* = 0 */ -module_param(force_monitor, int, 0644); -MODULE_PARM_DESC(force_monitor, "Allow monitor mode for all firmware versions"); - -/********************************************************************/ -/* Internal constants */ -/********************************************************************/ - -/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */ -static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; -#define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2) - -#define ORINOCO_MIN_MTU 256 -#define ORINOCO_MAX_MTU (IEEE80211_MAX_DATA_LEN - ENCAPS_OVERHEAD) - -#define MAX_IRQLOOPS_PER_IRQ 10 -#define MAX_IRQLOOPS_PER_JIFFY (20000 / HZ) /* Based on a guestimate of - * how many events the - * device could - * legitimately generate */ - -#define DUMMY_FID 0xFFFF - -/*#define MAX_MULTICAST(priv) (priv->firmware_type == FIRMWARE_TYPE_AGERE ? \ - HERMES_MAX_MULTICAST : 0)*/ -#define MAX_MULTICAST(priv) (HERMES_MAX_MULTICAST) - -#define ORINOCO_INTEN (HERMES_EV_RX | HERMES_EV_ALLOC \ - | HERMES_EV_TX | HERMES_EV_TXEXC \ - | HERMES_EV_WTERR | HERMES_EV_INFO \ - | HERMES_EV_INFDROP) - -/********************************************************************/ -/* Data types */ -/********************************************************************/ - -/* Beginning of the Tx descriptor, used in TxExc handling */ -struct hermes_txexc_data { - struct hermes_tx_descriptor desc; - __le16 frame_ctl; - __le16 duration_id; - u8 addr1[ETH_ALEN]; -} __packed; - -/* Rx frame header except compatibility 802.3 header */ -struct hermes_rx_descriptor { - /* Control */ - __le16 status; - __le32 time; - u8 silence; - u8 signal; - u8 rate; - u8 rxflow; - __le32 reserved; - - /* 802.11 header */ - __le16 frame_ctl; - __le16 duration_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 addr3[ETH_ALEN]; - __le16 seq_ctl; - u8 addr4[ETH_ALEN]; - - /* Data length */ - __le16 data_len; -} __packed; - -struct orinoco_rx_data { - struct hermes_rx_descriptor *desc; - struct sk_buff *skb; - struct list_head list; -}; - -struct orinoco_scan_data { - void *buf; - size_t len; - int type; - struct list_head list; -}; - -/********************************************************************/ -/* Function prototypes */ -/********************************************************************/ - -static int __orinoco_set_multicast_list(struct net_device *dev); -static int __orinoco_up(struct orinoco_private *priv); -static int __orinoco_down(struct orinoco_private *priv); -static int __orinoco_commit(struct orinoco_private *priv); - -/********************************************************************/ -/* Internal helper functions */ -/********************************************************************/ - -void set_port_type(struct orinoco_private *priv) -{ - switch (priv->iw_mode) { - case NL80211_IFTYPE_STATION: - priv->port_type = 1; - priv->createibss = 0; - break; - case NL80211_IFTYPE_ADHOC: - if (priv->prefer_port3) { - priv->port_type = 3; - priv->createibss = 0; - } else { - priv->port_type = priv->ibss_port; - priv->createibss = 1; - } - break; - case NL80211_IFTYPE_MONITOR: - priv->port_type = 3; - priv->createibss = 0; - break; - default: - printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n", - priv->ndev->name); - } -} - -/********************************************************************/ -/* Device methods */ -/********************************************************************/ - -int orinoco_open(struct net_device *dev) -{ - struct orinoco_private *priv = ndev_priv(dev); - unsigned long flags; - int err; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - err = __orinoco_up(priv); - - if (!err) - priv->open = 1; - - orinoco_unlock(priv, &flags); - - return err; -} -EXPORT_SYMBOL(orinoco_open); - -int orinoco_stop(struct net_device *dev) -{ - struct orinoco_private *priv = ndev_priv(dev); - int err = 0; - - /* We mustn't use orinoco_lock() here, because we need to be - able to close the interface even if hw_unavailable is set - (e.g. as we're released after a PC Card removal) */ - orinoco_lock_irq(priv); - - priv->open = 0; - - err = __orinoco_down(priv); - - orinoco_unlock_irq(priv); - - return err; -} -EXPORT_SYMBOL(orinoco_stop); - -void orinoco_set_multicast_list(struct net_device *dev) -{ - struct orinoco_private *priv = ndev_priv(dev); - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) { - printk(KERN_DEBUG "%s: orinoco_set_multicast_list() " - "called when hw_unavailable\n", dev->name); - return; - } - - __orinoco_set_multicast_list(dev); - orinoco_unlock(priv, &flags); -} -EXPORT_SYMBOL(orinoco_set_multicast_list); - -int orinoco_change_mtu(struct net_device *dev, int new_mtu) -{ - struct orinoco_private *priv = ndev_priv(dev); - - /* MTU + encapsulation + header length */ - if ((new_mtu + ENCAPS_OVERHEAD + sizeof(struct ieee80211_hdr)) > - (priv->nicbuf_size - ETH_HLEN)) - return -EINVAL; - - dev->mtu = new_mtu; - - return 0; -} -EXPORT_SYMBOL(orinoco_change_mtu); - -/********************************************************************/ -/* Tx path */ -/********************************************************************/ - -/* Add encapsulation and MIC to the existing SKB. - * The main xmit routine will then send the whole lot to the card. - * Need 8 bytes headroom - * Need 8 bytes tailroom - * - * With encapsulated ethernet II frame - * -------- - * 803.3 header (14 bytes) - * dst[6] - * -------- src[6] - * 803.3 header (14 bytes) len[2] - * dst[6] 803.2 header (8 bytes) - * src[6] encaps[6] - * len[2] <- leave alone -> len[2] - * -------- -------- <-- 0 - * Payload Payload - * ... ... - * - * -------- -------- - * MIC (8 bytes) - * -------- - * - * returns 0 on success, -ENOMEM on error. - */ -int orinoco_process_xmit_skb(struct sk_buff *skb, - struct net_device *dev, - struct orinoco_private *priv, - int *tx_control, - u8 *mic_buf) -{ - struct orinoco_tkip_key *key; - struct ethhdr *eh; - int do_mic; - - key = (struct orinoco_tkip_key *) priv->keys[priv->tx_key].key; - - do_mic = ((priv->encode_alg == ORINOCO_ALG_TKIP) && - (key != NULL)); - - if (do_mic) - *tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) | - HERMES_TXCTRL_MIC; - - eh = (struct ethhdr *)skb->data; - - /* Encapsulate Ethernet-II frames */ - if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */ - struct header_struct { - struct ethhdr eth; /* 802.3 header */ - u8 encap[6]; /* 802.2 header */ - } __packed hdr; - int len = skb->len + sizeof(encaps_hdr) - (2 * ETH_ALEN); - - if (skb_headroom(skb) < ENCAPS_OVERHEAD) { - if (net_ratelimit()) - printk(KERN_ERR - "%s: Not enough headroom for 802.2 headers %d\n", - dev->name, skb_headroom(skb)); - return -ENOMEM; - } - - /* Fill in new header */ - memcpy(&hdr.eth, eh, 2 * ETH_ALEN); - hdr.eth.h_proto = htons(len); - memcpy(hdr.encap, encaps_hdr, sizeof(encaps_hdr)); - - /* Make room for the new header, and copy it in */ - eh = skb_push(skb, ENCAPS_OVERHEAD); - memcpy(eh, &hdr, sizeof(hdr)); - } - - /* Calculate Michael MIC */ - if (do_mic) { - size_t len = skb->len - ETH_HLEN; - u8 *mic = &mic_buf[0]; - - /* Have to write to an even address, so copy the spare - * byte across */ - if (skb->len % 2) { - *mic = skb->data[skb->len - 1]; - mic++; - } - - orinoco_mic(priv->tx_tfm_mic, key->tx_mic, - eh->h_dest, eh->h_source, 0 /* priority */, - skb->data + ETH_HLEN, - len, mic); - } - - return 0; -} -EXPORT_SYMBOL(orinoco_process_xmit_skb); - -static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct orinoco_private *priv = ndev_priv(dev); - struct net_device_stats *stats = &dev->stats; - struct hermes *hw = &priv->hw; - int err = 0; - u16 txfid = priv->txfid; - int tx_control; - unsigned long flags; - u8 mic_buf[MICHAEL_MIC_LEN + 1]; - - if (!netif_running(dev)) { - printk(KERN_ERR "%s: Tx on stopped device!\n", - dev->name); - return NETDEV_TX_BUSY; - } - - if (netif_queue_stopped(dev)) { - printk(KERN_DEBUG "%s: Tx while transmitter busy!\n", - dev->name); - return NETDEV_TX_BUSY; - } - - if (orinoco_lock(priv, &flags) != 0) { - printk(KERN_ERR "%s: orinoco_xmit() called while hw_unavailable\n", - dev->name); - return NETDEV_TX_BUSY; - } - - if (!netif_carrier_ok(dev) || - (priv->iw_mode == NL80211_IFTYPE_MONITOR)) { - /* Oops, the firmware hasn't established a connection, - silently drop the packet (this seems to be the - safest approach). */ - goto drop; - } - - /* Check packet length */ - if (skb->len < ETH_HLEN) - goto drop; - - tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX; - - err = orinoco_process_xmit_skb(skb, dev, priv, &tx_control, - &mic_buf[0]); - if (err) - goto drop; - - if (priv->has_alt_txcntl) { - /* WPA enabled firmwares have tx_cntl at the end of - * the 802.11 header. So write zeroed descriptor and - * 802.11 header at the same time - */ - char desc[HERMES_802_3_OFFSET]; - __le16 *txcntl = (__le16 *) &desc[HERMES_TXCNTL2_OFFSET]; - - memset(&desc, 0, sizeof(desc)); - - *txcntl = cpu_to_le16(tx_control); - err = hw->ops->bap_pwrite(hw, USER_BAP, &desc, sizeof(desc), - txfid, 0); - if (err) { - if (net_ratelimit()) - printk(KERN_ERR "%s: Error %d writing Tx " - "descriptor to BAP\n", dev->name, err); - goto busy; - } - } else { - struct hermes_tx_descriptor desc; - - memset(&desc, 0, sizeof(desc)); - - desc.tx_control = cpu_to_le16(tx_control); - err = hw->ops->bap_pwrite(hw, USER_BAP, &desc, sizeof(desc), - txfid, 0); - if (err) { - if (net_ratelimit()) - printk(KERN_ERR "%s: Error %d writing Tx " - "descriptor to BAP\n", dev->name, err); - goto busy; - } - - /* Clear the 802.11 header and data length fields - some - * firmwares (e.g. Lucent/Agere 8.xx) appear to get confused - * if this isn't done. */ - hermes_clear_words(hw, HERMES_DATA0, - HERMES_802_3_OFFSET - HERMES_802_11_OFFSET); - } - - err = hw->ops->bap_pwrite(hw, USER_BAP, skb->data, skb->len, - txfid, HERMES_802_3_OFFSET); - if (err) { - printk(KERN_ERR "%s: Error %d writing packet to BAP\n", - dev->name, err); - goto busy; - } - - if (tx_control & HERMES_TXCTRL_MIC) { - size_t offset = HERMES_802_3_OFFSET + skb->len; - size_t len = MICHAEL_MIC_LEN; - - if (offset % 2) { - offset--; - len++; - } - err = hw->ops->bap_pwrite(hw, USER_BAP, &mic_buf[0], len, - txfid, offset); - if (err) { - printk(KERN_ERR "%s: Error %d writing MIC to BAP\n", - dev->name, err); - goto busy; - } - } - - /* Finally, we actually initiate the send */ - netif_stop_queue(dev); - - err = hw->ops->cmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL, - txfid, NULL); - if (err) { - netif_start_queue(dev); - if (net_ratelimit()) - printk(KERN_ERR "%s: Error %d transmitting packet\n", - dev->name, err); - goto busy; - } - - stats->tx_bytes += HERMES_802_3_OFFSET + skb->len; - goto ok; - - drop: - stats->tx_errors++; - stats->tx_dropped++; - - ok: - orinoco_unlock(priv, &flags); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - - busy: - if (err == -EIO) - schedule_work(&priv->reset_work); - orinoco_unlock(priv, &flags); - return NETDEV_TX_BUSY; -} - -static void __orinoco_ev_alloc(struct net_device *dev, struct hermes *hw) -{ - struct orinoco_private *priv = ndev_priv(dev); - u16 fid = hermes_read_regn(hw, ALLOCFID); - - if (fid != priv->txfid) { - if (fid != DUMMY_FID) - printk(KERN_WARNING "%s: Allocate event on unexpected fid (%04X)\n", - dev->name, fid); - return; - } - - hermes_write_regn(hw, ALLOCFID, DUMMY_FID); -} - -static void __orinoco_ev_tx(struct net_device *dev, struct hermes *hw) -{ - dev->stats.tx_packets++; - - netif_wake_queue(dev); - - hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); -} - -static void __orinoco_ev_txexc(struct net_device *dev, struct hermes *hw) -{ - struct net_device_stats *stats = &dev->stats; - u16 fid = hermes_read_regn(hw, TXCOMPLFID); - u16 status; - struct hermes_txexc_data hdr; - int err = 0; - - if (fid == DUMMY_FID) - return; /* Nothing's really happened */ - - /* Read part of the frame header - we need status and addr1 */ - err = hw->ops->bap_pread(hw, IRQ_BAP, &hdr, - sizeof(struct hermes_txexc_data), - fid, 0); - - hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); - stats->tx_errors++; - - if (err) { - printk(KERN_WARNING "%s: Unable to read descriptor on Tx error " - "(FID=%04X error %d)\n", - dev->name, fid, err); - return; - } - - DEBUG(1, "%s: Tx error, err %d (FID=%04X)\n", dev->name, - err, fid); - - /* We produce a TXDROP event only for retry or lifetime - * exceeded, because that's the only status that really mean - * that this particular node went away. - * Other errors means that *we* screwed up. - Jean II */ - status = le16_to_cpu(hdr.desc.status); - if (status & (HERMES_TXSTAT_RETRYERR | HERMES_TXSTAT_AGEDERR)) { - union iwreq_data wrqu; - - /* Copy 802.11 dest address. - * We use the 802.11 header because the frame may - * not be 802.3 or may be mangled... - * In Ad-Hoc mode, it will be the node address. - * In managed mode, it will be most likely the AP addr - * User space will figure out how to convert it to - * whatever it needs (IP address or else). - * - Jean II */ - memcpy(wrqu.addr.sa_data, hdr.addr1, ETH_ALEN); - wrqu.addr.sa_family = ARPHRD_ETHER; - - /* Send event to user space */ - wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL); - } - - netif_wake_queue(dev); -} - -void orinoco_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - struct orinoco_private *priv = ndev_priv(dev); - struct net_device_stats *stats = &dev->stats; - struct hermes *hw = &priv->hw; - - printk(KERN_WARNING "%s: Tx timeout! " - "ALLOCFID=%04x, TXCOMPLFID=%04x, EVSTAT=%04x\n", - dev->name, hermes_read_regn(hw, ALLOCFID), - hermes_read_regn(hw, TXCOMPLFID), hermes_read_regn(hw, EVSTAT)); - - stats->tx_errors++; - - schedule_work(&priv->reset_work); -} -EXPORT_SYMBOL(orinoco_tx_timeout); - -/********************************************************************/ -/* Rx path (data frames) */ -/********************************************************************/ - -/* Does the frame have a SNAP header indicating it should be - * de-encapsulated to Ethernet-II? */ -static inline int is_ethersnap(void *_hdr) -{ - u8 *hdr = _hdr; - - /* We de-encapsulate all packets which, a) have SNAP headers - * (i.e. SSAP=DSAP=0xaa and CTRL=0x3 in the 802.2 LLC header - * and where b) the OUI of the SNAP header is 00:00:00 or - * 00:00:f8 - we need both because different APs appear to use - * different OUIs for some reason */ - return (memcmp(hdr, &encaps_hdr, 5) == 0) - && ((hdr[5] == 0x00) || (hdr[5] == 0xf8)); -} - -static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac, - int level, int noise) -{ - struct iw_quality wstats; - wstats.level = level - 0x95; - wstats.noise = noise - 0x95; - wstats.qual = (level > noise) ? (level - noise) : 0; - wstats.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; - /* Update spy records */ - wireless_spy_update(dev, mac, &wstats); -} - -static void orinoco_stat_gather(struct net_device *dev, - struct sk_buff *skb, - struct hermes_rx_descriptor *desc) -{ - struct orinoco_private *priv = ndev_priv(dev); - - /* Using spy support with lots of Rx packets, like in an - * infrastructure (AP), will really slow down everything, because - * the MAC address must be compared to each entry of the spy list. - * If the user really asks for it (set some address in the - * spy list), we do it, but he will pay the price. - * Note that to get here, you need both WIRELESS_SPY - * compiled in AND some addresses in the list !!! - */ - /* Note : gcc will optimise the whole section away if - * WIRELESS_SPY is not defined... - Jean II */ - if (SPY_NUMBER(priv)) { - orinoco_spy_gather(dev, skb_mac_header(skb) + ETH_ALEN, - desc->signal, desc->silence); - } -} - -/* - * orinoco_rx_monitor - handle received monitor frames. - * - * Arguments: - * dev network device - * rxfid received FID - * desc rx descriptor of the frame - * - * Call context: interrupt - */ -static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid, - struct hermes_rx_descriptor *desc) -{ - u32 hdrlen = 30; /* return full header by default */ - u32 datalen = 0; - u16 fc; - int err; - int len; - struct sk_buff *skb; - struct orinoco_private *priv = ndev_priv(dev); - struct net_device_stats *stats = &dev->stats; - struct hermes *hw = &priv->hw; - - len = le16_to_cpu(desc->data_len); - - /* Determine the size of the header and the data */ - fc = le16_to_cpu(desc->frame_ctl); - switch (fc & IEEE80211_FCTL_FTYPE) { - case IEEE80211_FTYPE_DATA: - if ((fc & IEEE80211_FCTL_TODS) - && (fc & IEEE80211_FCTL_FROMDS)) - hdrlen = 30; - else - hdrlen = 24; - datalen = len; - break; - case IEEE80211_FTYPE_MGMT: - hdrlen = 24; - datalen = len; - break; - case IEEE80211_FTYPE_CTL: - switch (fc & IEEE80211_FCTL_STYPE) { - case IEEE80211_STYPE_PSPOLL: - case IEEE80211_STYPE_RTS: - case IEEE80211_STYPE_CFEND: - case IEEE80211_STYPE_CFENDACK: - hdrlen = 16; - break; - case IEEE80211_STYPE_CTS: - case IEEE80211_STYPE_ACK: - hdrlen = 10; - break; - } - break; - default: - /* Unknown frame type */ - break; - } - - /* sanity check the length */ - if (datalen > IEEE80211_MAX_DATA_LEN + 12) { - printk(KERN_DEBUG "%s: oversized monitor frame, " - "data length = %d\n", dev->name, datalen); - stats->rx_length_errors++; - goto update_stats; - } - - skb = dev_alloc_skb(hdrlen + datalen); - if (!skb) { - printk(KERN_WARNING "%s: Cannot allocate skb for monitor frame\n", - dev->name); - goto update_stats; - } - - /* Copy the 802.11 header to the skb */ - skb_put_data(skb, &(desc->frame_ctl), hdrlen); - skb_reset_mac_header(skb); - - /* If any, copy the data from the card to the skb */ - if (datalen > 0) { - err = hw->ops->bap_pread(hw, IRQ_BAP, skb_put(skb, datalen), - ALIGN(datalen, 2), rxfid, - HERMES_802_2_OFFSET); - if (err) { - printk(KERN_ERR "%s: error %d reading monitor frame\n", - dev->name, err); - goto drop; - } - } - - skb->dev = dev; - skb->ip_summed = CHECKSUM_NONE; - skb->pkt_type = PACKET_OTHERHOST; - skb->protocol = cpu_to_be16(ETH_P_802_2); - - stats->rx_packets++; - stats->rx_bytes += skb->len; - - netif_rx(skb); - return; - - drop: - dev_kfree_skb_irq(skb); - update_stats: - stats->rx_errors++; - stats->rx_dropped++; -} - -void __orinoco_ev_rx(struct net_device *dev, struct hermes *hw) -{ - struct orinoco_private *priv = ndev_priv(dev); - struct net_device_stats *stats = &dev->stats; - struct iw_statistics *wstats = &priv->wstats; - struct sk_buff *skb = NULL; - u16 rxfid, status; - int length; - struct hermes_rx_descriptor *desc; - struct orinoco_rx_data *rx_data; - int err; - - desc = kmalloc(sizeof(*desc), GFP_ATOMIC); - if (!desc) - goto update_stats; - - rxfid = hermes_read_regn(hw, RXFID); - - err = hw->ops->bap_pread(hw, IRQ_BAP, desc, sizeof(*desc), - rxfid, 0); - if (err) { - printk(KERN_ERR "%s: error %d reading Rx descriptor. " - "Frame dropped.\n", dev->name, err); - goto update_stats; - } - - status = le16_to_cpu(desc->status); - - if (status & HERMES_RXSTAT_BADCRC) { - DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", - dev->name); - stats->rx_crc_errors++; - goto update_stats; - } - - /* Handle frames in monitor mode */ - if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { - orinoco_rx_monitor(dev, rxfid, desc); - goto out; - } - - if (status & HERMES_RXSTAT_UNDECRYPTABLE) { - DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n", - dev->name); - wstats->discard.code++; - goto update_stats; - } - - length = le16_to_cpu(desc->data_len); - - /* Sanity checks */ - if (length < 3) { /* No for even an 802.2 LLC header */ - /* At least on Symbol firmware with PCF we get quite a - lot of these legitimately - Poll frames with no - data. */ - goto out; - } - if (length > IEEE80211_MAX_DATA_LEN) { - printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n", - dev->name, length); - stats->rx_length_errors++; - goto update_stats; - } - - /* Payload size does not include Michael MIC. Increase payload - * size to read it together with the data. */ - if (status & HERMES_RXSTAT_MIC) - length += MICHAEL_MIC_LEN; - - /* We need space for the packet data itself, plus an ethernet - header, plus 2 bytes so we can align the IP header on a - 32bit boundary, plus 1 byte so we can read in odd length - packets from the card, which has an IO granularity of 16 - bits */ - skb = dev_alloc_skb(length + ETH_HLEN + 2 + 1); - if (!skb) { - printk(KERN_WARNING "%s: Can't allocate skb for Rx\n", - dev->name); - goto update_stats; - } - - /* We'll prepend the header, so reserve space for it. The worst - case is no decapsulation, when 802.3 header is prepended and - nothing is removed. 2 is for aligning the IP header. */ - skb_reserve(skb, ETH_HLEN + 2); - - err = hw->ops->bap_pread(hw, IRQ_BAP, skb_put(skb, length), - ALIGN(length, 2), rxfid, - HERMES_802_2_OFFSET); - if (err) { - printk(KERN_ERR "%s: error %d reading frame. " - "Frame dropped.\n", dev->name, err); - goto drop; - } - - /* Add desc and skb to rx queue */ - rx_data = kzalloc(sizeof(*rx_data), GFP_ATOMIC); - if (!rx_data) - goto drop; - - rx_data->desc = desc; - rx_data->skb = skb; - list_add_tail(&rx_data->list, &priv->rx_list); - tasklet_schedule(&priv->rx_tasklet); - - return; - -drop: - dev_kfree_skb_irq(skb); -update_stats: - stats->rx_errors++; - stats->rx_dropped++; -out: - kfree(desc); -} -EXPORT_SYMBOL(__orinoco_ev_rx); - -static void orinoco_rx(struct net_device *dev, - struct hermes_rx_descriptor *desc, - struct sk_buff *skb) -{ - struct orinoco_private *priv = ndev_priv(dev); - struct net_device_stats *stats = &dev->stats; - u16 status, fc; - int length; - struct ethhdr *hdr; - - status = le16_to_cpu(desc->status); - length = le16_to_cpu(desc->data_len); - fc = le16_to_cpu(desc->frame_ctl); - - /* Calculate and check MIC */ - if (status & HERMES_RXSTAT_MIC) { - struct orinoco_tkip_key *key; - int key_id = ((status & HERMES_RXSTAT_MIC_KEY_ID) >> - HERMES_MIC_KEY_ID_SHIFT); - u8 mic[MICHAEL_MIC_LEN]; - u8 *rxmic; - u8 *src = (fc & IEEE80211_FCTL_FROMDS) ? - desc->addr3 : desc->addr2; - - /* Extract Michael MIC from payload */ - rxmic = skb->data + skb->len - MICHAEL_MIC_LEN; - - skb_trim(skb, skb->len - MICHAEL_MIC_LEN); - length -= MICHAEL_MIC_LEN; - - key = (struct orinoco_tkip_key *) priv->keys[key_id].key; - - if (!key) { - printk(KERN_WARNING "%s: Received encrypted frame from " - "%pM using key %i, but key is not installed\n", - dev->name, src, key_id); - goto drop; - } - - orinoco_mic(priv->rx_tfm_mic, key->rx_mic, desc->addr1, src, - 0, /* priority or QoS? */ - skb->data, skb->len, &mic[0]); - - if (memcmp(mic, rxmic, - MICHAEL_MIC_LEN)) { - union iwreq_data wrqu; - struct iw_michaelmicfailure wxmic; - - printk(KERN_WARNING "%s: " - "Invalid Michael MIC in data frame from %pM, " - "using key %i\n", - dev->name, src, key_id); - - /* TODO: update stats */ - - /* Notify userspace */ - memset(&wxmic, 0, sizeof(wxmic)); - wxmic.flags = key_id & IW_MICFAILURE_KEY_ID; - wxmic.flags |= (desc->addr1[0] & 1) ? - IW_MICFAILURE_GROUP : IW_MICFAILURE_PAIRWISE; - wxmic.src_addr.sa_family = ARPHRD_ETHER; - memcpy(wxmic.src_addr.sa_data, src, ETH_ALEN); - - (void) orinoco_hw_get_tkip_iv(priv, key_id, - &wxmic.tsc[0]); - - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = sizeof(wxmic); - wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, - (char *) &wxmic); - - goto drop; - } - } - - /* Handle decapsulation - * In most cases, the firmware tell us about SNAP frames. - * For some reason, the SNAP frames sent by LinkSys APs - * are not properly recognised by most firmwares. - * So, check ourselves */ - if (length >= ENCAPS_OVERHEAD && - (((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) || - ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) || - is_ethersnap(skb->data))) { - /* These indicate a SNAP within 802.2 LLC within - 802.11 frame which we'll need to de-encapsulate to - the original EthernetII frame. */ - hdr = skb_push(skb, ETH_HLEN - ENCAPS_OVERHEAD); - } else { - /* 802.3 frame - prepend 802.3 header as is */ - hdr = skb_push(skb, ETH_HLEN); - hdr->h_proto = htons(length); - } - memcpy(hdr->h_dest, desc->addr1, ETH_ALEN); - if (fc & IEEE80211_FCTL_FROMDS) - memcpy(hdr->h_source, desc->addr3, ETH_ALEN); - else - memcpy(hdr->h_source, desc->addr2, ETH_ALEN); - - skb->protocol = eth_type_trans(skb, dev); - skb->ip_summed = CHECKSUM_NONE; - if (fc & IEEE80211_FCTL_TODS) - skb->pkt_type = PACKET_OTHERHOST; - - /* Process the wireless stats if needed */ - orinoco_stat_gather(dev, skb, desc); - - /* Pass the packet to the networking stack */ - netif_rx(skb); - stats->rx_packets++; - stats->rx_bytes += length; - - return; - - drop: - dev_kfree_skb(skb); - stats->rx_errors++; - stats->rx_dropped++; -} - -static void orinoco_rx_isr_tasklet(struct tasklet_struct *t) -{ - struct orinoco_private *priv = from_tasklet(priv, t, rx_tasklet); - struct net_device *dev = priv->ndev; - struct orinoco_rx_data *rx_data, *temp; - struct hermes_rx_descriptor *desc; - struct sk_buff *skb; - unsigned long flags; - - /* orinoco_rx requires the driver lock, and we also need to - * protect priv->rx_list, so just hold the lock over the - * lot. - * - * If orinoco_lock fails, we've unplugged the card. In this - * case just abort. */ - if (orinoco_lock(priv, &flags) != 0) - return; - - /* extract desc and skb from queue */ - list_for_each_entry_safe(rx_data, temp, &priv->rx_list, list) { - desc = rx_data->desc; - skb = rx_data->skb; - list_del(&rx_data->list); - kfree(rx_data); - - orinoco_rx(dev, desc, skb); - - kfree(desc); - } - - orinoco_unlock(priv, &flags); -} - -/********************************************************************/ -/* Rx path (info frames) */ -/********************************************************************/ - -static void print_linkstatus(struct net_device *dev, u16 status) -{ - char *s; - - if (suppress_linkstatus) - return; - - switch (status) { - case HERMES_LINKSTATUS_NOT_CONNECTED: - s = "Not Connected"; - break; - case HERMES_LINKSTATUS_CONNECTED: - s = "Connected"; - break; - case HERMES_LINKSTATUS_DISCONNECTED: - s = "Disconnected"; - break; - case HERMES_LINKSTATUS_AP_CHANGE: - s = "AP Changed"; - break; - case HERMES_LINKSTATUS_AP_OUT_OF_RANGE: - s = "AP Out of Range"; - break; - case HERMES_LINKSTATUS_AP_IN_RANGE: - s = "AP In Range"; - break; - case HERMES_LINKSTATUS_ASSOC_FAILED: - s = "Association Failed"; - break; - default: - s = "UNKNOWN"; - } - - printk(KERN_DEBUG "%s: New link status: %s (%04x)\n", - dev->name, s, status); -} - -/* Search scan results for requested BSSID, join it if found */ -static void orinoco_join_ap(struct work_struct *work) -{ - struct orinoco_private *priv = - container_of(work, struct orinoco_private, join_work); - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - int err; - unsigned long flags; - struct join_req { - u8 bssid[ETH_ALEN]; - __le16 channel; - } __packed req; - const int atom_len = offsetof(struct prism2_scan_apinfo, atim); - struct prism2_scan_apinfo *atom = NULL; - int offset = 4; - int found = 0; - u8 *buf; - u16 len; - - /* Allocate buffer for scan results */ - buf = kmalloc(MAX_SCAN_LEN, GFP_KERNEL); - if (!buf) - return; - - if (orinoco_lock(priv, &flags) != 0) - goto fail_lock; - - /* Sanity checks in case user changed something in the meantime */ - if (!priv->bssid_fixed) - goto out; - - if (strlen(priv->desired_essid) == 0) - goto out; - - /* Read scan results from the firmware */ - err = hw->ops->read_ltv(hw, USER_BAP, - HERMES_RID_SCANRESULTSTABLE, - MAX_SCAN_LEN, &len, buf); - if (err) { - printk(KERN_ERR "%s: Cannot read scan results\n", - dev->name); - goto out; - } - - len = HERMES_RECLEN_TO_BYTES(len); - - /* Go through the scan results looking for the channel of the AP - * we were requested to join */ - for (; offset + atom_len <= len; offset += atom_len) { - atom = (struct prism2_scan_apinfo *) (buf + offset); - if (memcmp(&atom->bssid, priv->desired_bssid, ETH_ALEN) == 0) { - found = 1; - break; - } - } - - if (!found) { - DEBUG(1, "%s: Requested AP not found in scan results\n", - dev->name); - goto out; - } - - memcpy(req.bssid, priv->desired_bssid, ETH_ALEN); - req.channel = atom->channel; /* both are little-endian */ - err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNFJOINREQUEST, - &req); - if (err) - printk(KERN_ERR "%s: Error issuing join request\n", dev->name); - - out: - orinoco_unlock(priv, &flags); - - fail_lock: - kfree(buf); -} - -/* Send new BSSID to userspace */ -static void orinoco_send_bssid_wevent(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - union iwreq_data wrqu; - int err; - - err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID, - ETH_ALEN, NULL, wrqu.ap_addr.sa_data); - if (err != 0) - return; - - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - - /* Send event to user space */ - wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); -} - -static void orinoco_send_assocreqie_wevent(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - union iwreq_data wrqu; - int err; - u8 buf[88]; - u8 *ie; - - if (!priv->has_wpa) - return; - - err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO, - sizeof(buf), NULL, &buf); - if (err != 0) - return; - - ie = orinoco_get_wpa_ie(buf, sizeof(buf)); - if (ie) { - int rem = sizeof(buf) - (ie - &buf[0]); - wrqu.data.length = ie[1] + 2; - if (wrqu.data.length > rem) - wrqu.data.length = rem; - - if (wrqu.data.length) - /* Send event to user space */ - wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, ie); - } -} - -static void orinoco_send_assocrespie_wevent(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - union iwreq_data wrqu; - int err; - u8 buf[88]; /* TODO: verify max size or IW_GENERIC_IE_MAX */ - u8 *ie; - - if (!priv->has_wpa) - return; - - err = hw->ops->read_ltv(hw, USER_BAP, - HERMES_RID_CURRENT_ASSOC_RESP_INFO, - sizeof(buf), NULL, &buf); - if (err != 0) - return; - - ie = orinoco_get_wpa_ie(buf, sizeof(buf)); - if (ie) { - int rem = sizeof(buf) - (ie - &buf[0]); - wrqu.data.length = ie[1] + 2; - if (wrqu.data.length > rem) - wrqu.data.length = rem; - - if (wrqu.data.length) - /* Send event to user space */ - wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, ie); - } -} - -static void orinoco_send_wevents(struct work_struct *work) -{ - struct orinoco_private *priv = - container_of(work, struct orinoco_private, wevent_work); - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return; - - orinoco_send_assocreqie_wevent(priv); - orinoco_send_assocrespie_wevent(priv); - orinoco_send_bssid_wevent(priv); - - orinoco_unlock(priv, &flags); -} - -static void qbuf_scan(struct orinoco_private *priv, void *buf, - int len, int type) -{ - struct orinoco_scan_data *sd; - unsigned long flags; - - sd = kmalloc(sizeof(*sd), GFP_ATOMIC); - if (!sd) - return; - - sd->buf = buf; - sd->len = len; - sd->type = type; - - spin_lock_irqsave(&priv->scan_lock, flags); - list_add_tail(&sd->list, &priv->scan_list); - spin_unlock_irqrestore(&priv->scan_lock, flags); - - schedule_work(&priv->process_scan); -} - -static void qabort_scan(struct orinoco_private *priv) -{ - struct orinoco_scan_data *sd; - unsigned long flags; - - sd = kmalloc(sizeof(*sd), GFP_ATOMIC); - if (!sd) - return; - - sd->len = -1; /* Abort */ - - spin_lock_irqsave(&priv->scan_lock, flags); - list_add_tail(&sd->list, &priv->scan_list); - spin_unlock_irqrestore(&priv->scan_lock, flags); - - schedule_work(&priv->process_scan); -} - -static void orinoco_process_scan_results(struct work_struct *work) -{ - struct orinoco_private *priv = - container_of(work, struct orinoco_private, process_scan); - struct orinoco_scan_data *sd, *temp; - unsigned long flags; - void *buf; - int len; - int type; - - spin_lock_irqsave(&priv->scan_lock, flags); - list_for_each_entry_safe(sd, temp, &priv->scan_list, list) { - - buf = sd->buf; - len = sd->len; - type = sd->type; - - list_del(&sd->list); - spin_unlock_irqrestore(&priv->scan_lock, flags); - kfree(sd); - - if (len > 0) { - if (type == HERMES_INQ_CHANNELINFO) - orinoco_add_extscan_result(priv, buf, len); - else - orinoco_add_hostscan_results(priv, buf, len); - - kfree(buf); - } else { - /* Either abort or complete the scan */ - orinoco_scan_done(priv, (len < 0)); - } - - spin_lock_irqsave(&priv->scan_lock, flags); - } - spin_unlock_irqrestore(&priv->scan_lock, flags); -} - -void __orinoco_ev_info(struct net_device *dev, struct hermes *hw) -{ - struct orinoco_private *priv = ndev_priv(dev); - u16 infofid; - struct { - __le16 len; - __le16 type; - } __packed info; - int len, type; - int err; - - /* This is an answer to an INQUIRE command that we did earlier, - * or an information "event" generated by the card - * The controller return to us a pseudo frame containing - * the information in question - Jean II */ - infofid = hermes_read_regn(hw, INFOFID); - - /* Read the info frame header - don't try too hard */ - err = hw->ops->bap_pread(hw, IRQ_BAP, &info, sizeof(info), - infofid, 0); - if (err) { - printk(KERN_ERR "%s: error %d reading info frame. " - "Frame dropped.\n", dev->name, err); - return; - } - - len = HERMES_RECLEN_TO_BYTES(le16_to_cpu(info.len)); - type = le16_to_cpu(info.type); - - switch (type) { - case HERMES_INQ_TALLIES: { - struct hermes_tallies_frame tallies; - struct iw_statistics *wstats = &priv->wstats; - - if (len > sizeof(tallies)) { - printk(KERN_WARNING "%s: Tallies frame too long (%d bytes)\n", - dev->name, len); - len = sizeof(tallies); - } - - err = hw->ops->bap_pread(hw, IRQ_BAP, &tallies, len, - infofid, sizeof(info)); - if (err) - break; - - /* Increment our various counters */ - /* wstats->discard.nwid - no wrong BSSID stuff */ - wstats->discard.code += - le16_to_cpu(tallies.RxWEPUndecryptable); - if (len == sizeof(tallies)) - wstats->discard.code += - le16_to_cpu(tallies.RxDiscards_WEPICVError) + - le16_to_cpu(tallies.RxDiscards_WEPExcluded); - wstats->discard.misc += - le16_to_cpu(tallies.TxDiscardsWrongSA); - wstats->discard.fragment += - le16_to_cpu(tallies.RxMsgInBadMsgFragments); - wstats->discard.retries += - le16_to_cpu(tallies.TxRetryLimitExceeded); - /* wstats->miss.beacon - no match */ - } - break; - case HERMES_INQ_LINKSTATUS: { - struct hermes_linkstatus linkstatus; - u16 newstatus; - int connected; - - if (priv->iw_mode == NL80211_IFTYPE_MONITOR) - break; - - if (len != sizeof(linkstatus)) { - printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n", - dev->name, len); - break; - } - - err = hw->ops->bap_pread(hw, IRQ_BAP, &linkstatus, len, - infofid, sizeof(info)); - if (err) - break; - newstatus = le16_to_cpu(linkstatus.linkstatus); - - /* Symbol firmware uses "out of range" to signal that - * the hostscan frame can be requested. */ - if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE && - priv->firmware_type == FIRMWARE_TYPE_SYMBOL && - priv->has_hostscan && priv->scan_request) { - hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL); - break; - } - - connected = (newstatus == HERMES_LINKSTATUS_CONNECTED) - || (newstatus == HERMES_LINKSTATUS_AP_CHANGE) - || (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE); - - if (connected) - netif_carrier_on(dev); - else if (!ignore_disconnect) - netif_carrier_off(dev); - - if (newstatus != priv->last_linkstatus) { - priv->last_linkstatus = newstatus; - print_linkstatus(dev, newstatus); - /* The info frame contains only one word which is the - * status (see hermes.h). The status is pretty boring - * in itself, that's why we export the new BSSID... - * Jean II */ - schedule_work(&priv->wevent_work); - } - } - break; - case HERMES_INQ_SCAN: - if (!priv->scan_request && priv->bssid_fixed && - priv->firmware_type == FIRMWARE_TYPE_INTERSIL) { - schedule_work(&priv->join_work); - break; - } - fallthrough; - case HERMES_INQ_HOSTSCAN: - case HERMES_INQ_HOSTSCAN_SYMBOL: { - /* Result of a scanning. Contains information about - * cells in the vicinity - Jean II */ - unsigned char *buf; - - /* Sanity check */ - if (len > 4096) { - printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n", - dev->name, len); - qabort_scan(priv); - break; - } - - /* Allocate buffer for results */ - buf = kmalloc(len, GFP_ATOMIC); - if (buf == NULL) { - /* No memory, so can't printk()... */ - qabort_scan(priv); - break; - } - - /* Read scan data */ - err = hw->ops->bap_pread(hw, IRQ_BAP, (void *) buf, len, - infofid, sizeof(info)); - if (err) { - kfree(buf); - qabort_scan(priv); - break; - } - -#ifdef ORINOCO_DEBUG - { - int i; - printk(KERN_DEBUG "Scan result [%02X", buf[0]); - for (i = 1; i < (len * 2); i++) - printk(":%02X", buf[i]); - printk("]\n"); - } -#endif /* ORINOCO_DEBUG */ - - qbuf_scan(priv, buf, len, type); - } - break; - case HERMES_INQ_CHANNELINFO: - { - struct agere_ext_scan_info *bss; - - if (!priv->scan_request) { - printk(KERN_DEBUG "%s: Got chaninfo without scan, " - "len=%d\n", dev->name, len); - break; - } - - /* An empty result indicates that the scan is complete */ - if (len == 0) { - qbuf_scan(priv, NULL, len, type); - break; - } - - /* Sanity check */ - else if (len < (offsetof(struct agere_ext_scan_info, - data) + 2)) { - /* Drop this result now so we don't have to - * keep checking later */ - printk(KERN_WARNING - "%s: Ext scan results too short (%d bytes)\n", - dev->name, len); - break; - } - - bss = kmalloc(len, GFP_ATOMIC); - if (bss == NULL) - break; - - /* Read scan data */ - err = hw->ops->bap_pread(hw, IRQ_BAP, (void *) bss, len, - infofid, sizeof(info)); - if (err) - kfree(bss); - else - qbuf_scan(priv, bss, len, type); - - break; - } - case HERMES_INQ_SEC_STAT_AGERE: - /* Security status (Agere specific) */ - /* Ignore this frame for now */ - if (priv->firmware_type == FIRMWARE_TYPE_AGERE) - break; - fallthrough; - default: - printk(KERN_DEBUG "%s: Unknown information frame received: " - "type 0x%04x, length %d\n", dev->name, type, len); - /* We don't actually do anything about it */ - break; - } -} -EXPORT_SYMBOL(__orinoco_ev_info); - -static void __orinoco_ev_infdrop(struct net_device *dev, struct hermes *hw) -{ - if (net_ratelimit()) - printk(KERN_DEBUG "%s: Information frame lost.\n", dev->name); -} - -/********************************************************************/ -/* Internal hardware control routines */ -/********************************************************************/ - -static int __orinoco_up(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - int err; - - netif_carrier_off(dev); /* just to make sure */ - - err = __orinoco_commit(priv); - if (err) { - printk(KERN_ERR "%s: Error %d configuring card\n", - dev->name, err); - return err; - } - - /* Fire things up again */ - hermes_set_irqmask(hw, ORINOCO_INTEN); - err = hermes_enable_port(hw, 0); - if (err) { - printk(KERN_ERR "%s: Error %d enabling MAC port\n", - dev->name, err); - return err; - } - - netif_start_queue(dev); - - return 0; -} - -static int __orinoco_down(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - int err; - - netif_stop_queue(dev); - - if (!priv->hw_unavailable) { - if (!priv->broken_disableport) { - err = hermes_disable_port(hw, 0); - if (err) { - /* Some firmwares (e.g. Intersil 1.3.x) seem - * to have problems disabling the port, oh - * well, too bad. */ - printk(KERN_WARNING "%s: Error %d disabling MAC port\n", - dev->name, err); - priv->broken_disableport = 1; - } - } - hermes_set_irqmask(hw, 0); - hermes_write_regn(hw, EVACK, 0xffff); - } - - orinoco_scan_done(priv, true); - - /* firmware will have to reassociate */ - netif_carrier_off(dev); - priv->last_linkstatus = 0xffff; - - return 0; -} - -static int orinoco_reinit_firmware(struct orinoco_private *priv) -{ - struct hermes *hw = &priv->hw; - int err; - - err = hw->ops->init(hw); - if (priv->do_fw_download && !err) { - err = orinoco_download(priv); - if (err) - priv->do_fw_download = 0; - } - if (!err) - err = orinoco_hw_allocate_fid(priv); - - return err; -} - -static int -__orinoco_set_multicast_list(struct net_device *dev) -{ - struct orinoco_private *priv = ndev_priv(dev); - int err = 0; - int promisc, mc_count; - - /* The Hermes doesn't seem to have an allmulti mode, so we go - * into promiscuous mode and let the upper levels deal. */ - if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) || - (netdev_mc_count(dev) > MAX_MULTICAST(priv))) { - promisc = 1; - mc_count = 0; - } else { - promisc = 0; - mc_count = netdev_mc_count(dev); - } - - err = __orinoco_hw_set_multicast_list(priv, dev, mc_count, promisc); - - return err; -} - -/* This must be called from user context, without locks held - use - * schedule_work() */ -void orinoco_reset(struct work_struct *work) -{ - struct orinoco_private *priv = - container_of(work, struct orinoco_private, reset_work); - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - int err; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - /* When the hardware becomes available again, whatever - * detects that is responsible for re-initializing - * it. So no need for anything further */ - return; - - netif_stop_queue(dev); - - /* Shut off interrupts. Depending on what state the hardware - * is in, this might not work, but we'll try anyway */ - hermes_set_irqmask(hw, 0); - hermes_write_regn(hw, EVACK, 0xffff); - - priv->hw_unavailable++; - priv->last_linkstatus = 0xffff; /* firmware will have to reassociate */ - netif_carrier_off(dev); - - orinoco_unlock(priv, &flags); - - /* Scanning support: Notify scan cancellation */ - orinoco_scan_done(priv, true); - - if (priv->hard_reset) { - err = (*priv->hard_reset)(priv); - if (err) { - printk(KERN_ERR "%s: orinoco_reset: Error %d " - "performing hard reset\n", dev->name, err); - goto disable; - } - } - - err = orinoco_reinit_firmware(priv); - if (err) { - printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n", - dev->name, err); - goto disable; - } - - /* This has to be called from user context */ - orinoco_lock_irq(priv); - - priv->hw_unavailable--; - - /* priv->open or priv->hw_unavailable might have changed while - * we dropped the lock */ - if (priv->open && (!priv->hw_unavailable)) { - err = __orinoco_up(priv); - if (err) { - printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n", - dev->name, err); - } else - netif_trans_update(dev); - } - - orinoco_unlock_irq(priv); - - return; - disable: - hermes_set_irqmask(hw, 0); - netif_device_detach(dev); - printk(KERN_ERR "%s: Device has been disabled!\n", dev->name); -} - -static int __orinoco_commit(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - int err = 0; - - /* If we've called commit, we are reconfiguring or bringing the - * interface up. Maintaining countermeasures across this would - * be confusing, so note that we've disabled them. The port will - * be enabled later in orinoco_commit or __orinoco_up. */ - priv->tkip_cm_active = 0; - - err = orinoco_hw_program_rids(priv); - - /* FIXME: what about netif_tx_lock */ - (void) __orinoco_set_multicast_list(dev); - - return err; -} - -/* Ensures configuration changes are applied. May result in a reset. - * The caller should hold priv->lock - */ -int orinoco_commit(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - int err; - - if (priv->broken_disableport) { - schedule_work(&priv->reset_work); - return 0; - } - - err = hermes_disable_port(hw, 0); - if (err) { - printk(KERN_WARNING "%s: Unable to disable port " - "while reconfiguring card\n", dev->name); - priv->broken_disableport = 1; - goto out; - } - - err = __orinoco_commit(priv); - if (err) { - printk(KERN_WARNING "%s: Unable to reconfigure card\n", - dev->name); - goto out; - } - - err = hermes_enable_port(hw, 0); - if (err) { - printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n", - dev->name); - goto out; - } - - out: - if (err) { - printk(KERN_WARNING "%s: Resetting instead...\n", dev->name); - schedule_work(&priv->reset_work); - err = 0; - } - return err; -} - -/********************************************************************/ -/* Interrupt handler */ -/********************************************************************/ - -static void __orinoco_ev_tick(struct net_device *dev, struct hermes *hw) -{ - printk(KERN_DEBUG "%s: TICK\n", dev->name); -} - -static void __orinoco_ev_wterr(struct net_device *dev, struct hermes *hw) -{ - /* This seems to happen a fair bit under load, but ignoring it - seems to work fine...*/ - printk(KERN_DEBUG "%s: MAC controller error (WTERR). Ignoring.\n", - dev->name); -} - -irqreturn_t orinoco_interrupt(int irq, void *dev_id) -{ - struct orinoco_private *priv = dev_id; - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - int count = MAX_IRQLOOPS_PER_IRQ; - u16 evstat, events; - /* These are used to detect a runaway interrupt situation. - * - * If we get more than MAX_IRQLOOPS_PER_JIFFY iterations in a jiffy, - * we panic and shut down the hardware - */ - /* jiffies value the last time we were called */ - static int last_irq_jiffy; /* = 0 */ - static int loops_this_jiffy; /* = 0 */ - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) { - /* If hw is unavailable - we don't know if the irq was - * for us or not */ - return IRQ_HANDLED; - } - - evstat = hermes_read_regn(hw, EVSTAT); - events = evstat & hw->inten; - if (!events) { - orinoco_unlock(priv, &flags); - return IRQ_NONE; - } - - if (jiffies != last_irq_jiffy) - loops_this_jiffy = 0; - last_irq_jiffy = jiffies; - - while (events && count--) { - if (++loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY) { - printk(KERN_WARNING "%s: IRQ handler is looping too " - "much! Resetting.\n", dev->name); - /* Disable interrupts for now */ - hermes_set_irqmask(hw, 0); - schedule_work(&priv->reset_work); - break; - } - - /* Check the card hasn't been removed */ - if (!hermes_present(hw)) { - DEBUG(0, "orinoco_interrupt(): card removed\n"); - break; - } - - if (events & HERMES_EV_TICK) - __orinoco_ev_tick(dev, hw); - if (events & HERMES_EV_WTERR) - __orinoco_ev_wterr(dev, hw); - if (events & HERMES_EV_INFDROP) - __orinoco_ev_infdrop(dev, hw); - if (events & HERMES_EV_INFO) - __orinoco_ev_info(dev, hw); - if (events & HERMES_EV_RX) - __orinoco_ev_rx(dev, hw); - if (events & HERMES_EV_TXEXC) - __orinoco_ev_txexc(dev, hw); - if (events & HERMES_EV_TX) - __orinoco_ev_tx(dev, hw); - if (events & HERMES_EV_ALLOC) - __orinoco_ev_alloc(dev, hw); - - hermes_write_regn(hw, EVACK, evstat); - - evstat = hermes_read_regn(hw, EVSTAT); - events = evstat & hw->inten; - } - - orinoco_unlock(priv, &flags); - return IRQ_HANDLED; -} -EXPORT_SYMBOL(orinoco_interrupt); - -/********************************************************************/ -/* Power management */ -/********************************************************************/ -#if defined(CONFIG_PM_SLEEP) && !defined(CONFIG_HERMES_CACHE_FW_ON_INIT) -static int orinoco_pm_notifier(struct notifier_block *notifier, - unsigned long pm_event, - void *unused) -{ - struct orinoco_private *priv = container_of(notifier, - struct orinoco_private, - pm_notifier); - - /* All we need to do is cache the firmware before suspend, and - * release it when we come out. - * - * Only need to do this if we're downloading firmware. */ - if (!priv->do_fw_download) - return NOTIFY_DONE; - - switch (pm_event) { - case PM_HIBERNATION_PREPARE: - case PM_SUSPEND_PREPARE: - orinoco_cache_fw(priv, 0); - break; - - case PM_POST_RESTORE: - /* Restore from hibernation failed. We need to clean - * up in exactly the same way, so fall through. */ - case PM_POST_HIBERNATION: - case PM_POST_SUSPEND: - orinoco_uncache_fw(priv); - break; - - case PM_RESTORE_PREPARE: - default: - break; - } - - return NOTIFY_DONE; -} - -static void orinoco_register_pm_notifier(struct orinoco_private *priv) -{ - priv->pm_notifier.notifier_call = orinoco_pm_notifier; - register_pm_notifier(&priv->pm_notifier); -} - -static void orinoco_unregister_pm_notifier(struct orinoco_private *priv) -{ - unregister_pm_notifier(&priv->pm_notifier); -} -#else /* !PM_SLEEP || HERMES_CACHE_FW_ON_INIT */ -#define orinoco_register_pm_notifier(priv) do { } while (0) -#define orinoco_unregister_pm_notifier(priv) do { } while (0) -#endif - -/********************************************************************/ -/* Initialization */ -/********************************************************************/ - -int orinoco_init(struct orinoco_private *priv) -{ - struct device *dev = priv->dev; - struct wiphy *wiphy = priv_to_wiphy(priv); - struct hermes *hw = &priv->hw; - int err = 0; - - /* No need to lock, the hw_unavailable flag is already set in - * alloc_orinocodev() */ - priv->nicbuf_size = IEEE80211_MAX_FRAME_LEN + ETH_HLEN; - - /* Initialize the firmware */ - err = hw->ops->init(hw); - if (err != 0) { - dev_err(dev, "Failed to initialize firmware (err = %d)\n", - err); - goto out; - } - - err = determine_fw_capabilities(priv, wiphy->fw_version, - sizeof(wiphy->fw_version), - &wiphy->hw_version); - if (err != 0) { - dev_err(dev, "Incompatible firmware, aborting\n"); - goto out; - } - - if (priv->do_fw_download) { -#ifdef CONFIG_HERMES_CACHE_FW_ON_INIT - orinoco_cache_fw(priv, 0); -#endif - - err = orinoco_download(priv); - if (err) - priv->do_fw_download = 0; - - /* Check firmware version again */ - err = determine_fw_capabilities(priv, wiphy->fw_version, - sizeof(wiphy->fw_version), - &wiphy->hw_version); - if (err != 0) { - dev_err(dev, "Incompatible firmware, aborting\n"); - goto out; - } - } - - if (priv->has_port3) - dev_info(dev, "Ad-hoc demo mode supported\n"); - if (priv->has_ibss) - dev_info(dev, "IEEE standard IBSS ad-hoc mode supported\n"); - if (priv->has_wep) - dev_info(dev, "WEP supported, %s-bit key\n", - priv->has_big_wep ? "104" : "40"); - if (priv->has_wpa) { - dev_info(dev, "WPA-PSK supported\n"); - if (orinoco_mic_init(priv)) { - dev_err(dev, "Failed to setup MIC crypto algorithm. " - "Disabling WPA support\n"); - priv->has_wpa = 0; - } - } - - err = orinoco_hw_read_card_settings(priv, wiphy->perm_addr); - if (err) - goto out; - - err = orinoco_hw_allocate_fid(priv); - if (err) { - dev_err(dev, "Failed to allocate NIC buffer!\n"); - goto out; - } - - /* Set up the default configuration */ - priv->iw_mode = NL80211_IFTYPE_STATION; - /* By default use IEEE/IBSS ad-hoc mode if we have it */ - priv->prefer_port3 = priv->has_port3 && (!priv->has_ibss); - set_port_type(priv); - priv->channel = 0; /* use firmware default */ - - priv->promiscuous = 0; - priv->encode_alg = ORINOCO_ALG_NONE; - priv->tx_key = 0; - priv->wpa_enabled = 0; - priv->tkip_cm_active = 0; - priv->key_mgmt = 0; - priv->wpa_ie_len = 0; - priv->wpa_ie = NULL; - - if (orinoco_wiphy_register(wiphy)) { - err = -ENODEV; - goto out; - } - - /* Make the hardware available, as long as it hasn't been - * removed elsewhere (e.g. by PCMCIA hot unplug) */ - orinoco_lock_irq(priv); - priv->hw_unavailable--; - orinoco_unlock_irq(priv); - - dev_dbg(dev, "Ready\n"); - - out: - return err; -} -EXPORT_SYMBOL(orinoco_init); - -static const struct net_device_ops orinoco_netdev_ops = { - .ndo_open = orinoco_open, - .ndo_stop = orinoco_stop, - .ndo_start_xmit = orinoco_xmit, - .ndo_set_rx_mode = orinoco_set_multicast_list, - .ndo_change_mtu = orinoco_change_mtu, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, - .ndo_tx_timeout = orinoco_tx_timeout, -}; - -/* Allocate private data. - * - * This driver has a number of structures associated with it - * netdev - Net device structure for each network interface - * wiphy - structure associated with wireless phy - * wireless_dev (wdev) - structure for each wireless interface - * hw - structure for hermes chip info - * card - card specific structure for use by the card driver - * (airport, orinoco_cs) - * priv - orinoco private data - * device - generic linux device structure - * - * +---------+ +---------+ - * | wiphy | | netdev | - * | +-------+ | +-------+ - * | | priv | | | wdev | - * | | +-----+ +-+-------+ - * | | | hw | - * | +-+-----+ - * | | card | - * +-+-------+ - * - * priv has a link to netdev and device - * wdev has a link to wiphy - */ -struct orinoco_private -*alloc_orinocodev(int sizeof_card, - struct device *device, - int (*hard_reset)(struct orinoco_private *), - int (*stop_fw)(struct orinoco_private *, int)) -{ - struct orinoco_private *priv; - struct wiphy *wiphy; - - /* allocate wiphy - * NOTE: We only support a single virtual interface - * but this may change when monitor mode is added - */ - wiphy = wiphy_new(&orinoco_cfg_ops, - sizeof(struct orinoco_private) + sizeof_card); - if (!wiphy) - return NULL; - - priv = wiphy_priv(wiphy); - priv->dev = device; - - if (sizeof_card) - priv->card = (void *)((unsigned long)priv - + sizeof(struct orinoco_private)); - else - priv->card = NULL; - - orinoco_wiphy_init(wiphy); - -#ifdef WIRELESS_SPY - priv->wireless_data.spy_data = &priv->spy_data; -#endif - - /* Set up default callbacks */ - priv->hard_reset = hard_reset; - priv->stop_fw = stop_fw; - - spin_lock_init(&priv->lock); - priv->open = 0; - priv->hw_unavailable = 1; /* orinoco_init() must clear this - * before anything else touches the - * hardware */ - INIT_WORK(&priv->reset_work, orinoco_reset); - INIT_WORK(&priv->join_work, orinoco_join_ap); - INIT_WORK(&priv->wevent_work, orinoco_send_wevents); - - INIT_LIST_HEAD(&priv->rx_list); - tasklet_setup(&priv->rx_tasklet, orinoco_rx_isr_tasklet); - - spin_lock_init(&priv->scan_lock); - INIT_LIST_HEAD(&priv->scan_list); - INIT_WORK(&priv->process_scan, orinoco_process_scan_results); - - priv->last_linkstatus = 0xffff; - -#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP) - priv->cached_pri_fw = NULL; - priv->cached_fw = NULL; -#endif - - /* Register PM notifiers */ - orinoco_register_pm_notifier(priv); - - return priv; -} -EXPORT_SYMBOL(alloc_orinocodev); - -/* We can only support a single interface. We provide a separate - * function to set it up to distinguish between hardware - * initialisation and interface setup. - * - * The base_addr and irq parameters are passed on to netdev for use - * with SIOCGIFMAP. - */ -int orinoco_if_add(struct orinoco_private *priv, - unsigned long base_addr, - unsigned int irq, - const struct net_device_ops *ops) -{ - struct wiphy *wiphy = priv_to_wiphy(priv); - struct wireless_dev *wdev; - struct net_device *dev; - int ret; - - dev = alloc_etherdev(sizeof(struct wireless_dev)); - - if (!dev) - return -ENOMEM; - - /* Initialise wireless_dev */ - wdev = netdev_priv(dev); - wdev->wiphy = wiphy; - wdev->iftype = NL80211_IFTYPE_STATION; - - /* Setup / override net_device fields */ - dev->ieee80211_ptr = wdev; - dev->watchdog_timeo = HZ; /* 1 second timeout */ - dev->wireless_handlers = &orinoco_handler_def; -#ifdef WIRELESS_SPY - dev->wireless_data = &priv->wireless_data; -#endif - /* Default to standard ops if not set */ - if (ops) - dev->netdev_ops = ops; - else - dev->netdev_ops = &orinoco_netdev_ops; - - /* we use the default eth_mac_addr for setting the MAC addr */ - - /* Reserve space in skb for the SNAP header */ - dev->needed_headroom = ENCAPS_OVERHEAD; - - netif_carrier_off(dev); - - eth_hw_addr_set(dev, wiphy->perm_addr); - - dev->base_addr = base_addr; - dev->irq = irq; - - dev->min_mtu = ORINOCO_MIN_MTU; - dev->max_mtu = ORINOCO_MAX_MTU; - - SET_NETDEV_DEV(dev, priv->dev); - ret = register_netdev(dev); - if (ret) - goto fail; - - priv->ndev = dev; - - /* Report what we've done */ - dev_dbg(priv->dev, "Registered interface %s.\n", dev->name); - - return 0; - - fail: - free_netdev(dev); - return ret; -} -EXPORT_SYMBOL(orinoco_if_add); - -void orinoco_if_del(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - - unregister_netdev(dev); - free_netdev(dev); -} -EXPORT_SYMBOL(orinoco_if_del); - -void free_orinocodev(struct orinoco_private *priv) -{ - struct wiphy *wiphy = priv_to_wiphy(priv); - struct orinoco_rx_data *rx_data, *temp; - struct orinoco_scan_data *sd, *sdtemp; - - /* If the tasklet is scheduled when we call tasklet_kill it - * will run one final time. However the tasklet will only - * drain priv->rx_list if the hw is still available. */ - tasklet_kill(&priv->rx_tasklet); - - /* Explicitly drain priv->rx_list */ - list_for_each_entry_safe(rx_data, temp, &priv->rx_list, list) { - list_del(&rx_data->list); - - dev_kfree_skb(rx_data->skb); - kfree(rx_data->desc); - kfree(rx_data); - } - - cancel_work_sync(&priv->process_scan); - /* Explicitly drain priv->scan_list */ - list_for_each_entry_safe(sd, sdtemp, &priv->scan_list, list) { - list_del(&sd->list); - - if (sd->len > 0) - kfree(sd->buf); - kfree(sd); - } - - orinoco_unregister_pm_notifier(priv); - orinoco_uncache_fw(priv); - - priv->wpa_ie_len = 0; - kfree(priv->wpa_ie); - orinoco_mic_free(priv); - wiphy_free(wiphy); -} -EXPORT_SYMBOL(free_orinocodev); - -int orinoco_up(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - unsigned long flags; - int err; - - priv->hw.ops->lock_irqsave(&priv->lock, &flags); - - err = orinoco_reinit_firmware(priv); - if (err) { - printk(KERN_ERR "%s: Error %d re-initializing firmware\n", - dev->name, err); - goto exit; - } - - netif_device_attach(dev); - priv->hw_unavailable--; - - if (priv->open && !priv->hw_unavailable) { - err = __orinoco_up(priv); - if (err) - printk(KERN_ERR "%s: Error %d restarting card\n", - dev->name, err); - } - -exit: - priv->hw.ops->unlock_irqrestore(&priv->lock, &flags); - - return 0; -} -EXPORT_SYMBOL(orinoco_up); - -void orinoco_down(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - unsigned long flags; - int err; - - priv->hw.ops->lock_irqsave(&priv->lock, &flags); - err = __orinoco_down(priv); - if (err) - printk(KERN_WARNING "%s: Error %d downing interface\n", - dev->name, err); - - netif_device_detach(dev); - priv->hw_unavailable++; - priv->hw.ops->unlock_irqrestore(&priv->lock, &flags); -} -EXPORT_SYMBOL(orinoco_down); - -/********************************************************************/ -/* Module initialization */ -/********************************************************************/ - -/* Can't be declared "const" or the whole __initdata section will - * become const */ -static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION - " (David Gibson , " - "Pavel Roskin , et al)"; - -static int __init init_orinoco(void) -{ - printk(KERN_DEBUG "%s\n", version); - return 0; -} - -static void __exit exit_orinoco(void) -{ -} - -module_init(init_orinoco); -module_exit(exit_orinoco); diff --git a/drivers/net/wireless/intersil/orinoco/main.h b/drivers/net/wireless/intersil/orinoco/main.h deleted file mode 100644 index 5a8fec26136ef..0000000000000 --- a/drivers/net/wireless/intersil/orinoco/main.h +++ /dev/null @@ -1,50 +0,0 @@ -/* Exports from main to helper modules - * - * See copyright notice in main.c - */ -#ifndef _ORINOCO_MAIN_H_ -#define _ORINOCO_MAIN_H_ - -#include -#include "orinoco.h" - -/********************************************************************/ -/* Compile time configuration and compatibility stuff */ -/********************************************************************/ - -/* We do this this way to avoid ifdefs in the actual code */ -#ifdef WIRELESS_SPY -#define SPY_NUMBER(priv) (priv->spy_data.spy_number) -#else -#define SPY_NUMBER(priv) 0 -#endif /* WIRELESS_SPY */ - -/********************************************************************/ - -/* Export module parameter */ -extern int force_monitor; - -/* Forward declarations */ -struct net_device; -struct work_struct; - -void set_port_type(struct orinoco_private *priv); -int orinoco_commit(struct orinoco_private *priv); -void orinoco_reset(struct work_struct *work); - -/* Information element helpers - find a home for these... */ -#define WPA_OUI_TYPE "\x00\x50\xF2\x01" -#define WPA_SELECTOR_LEN 4 -static inline u8 *orinoco_get_wpa_ie(u8 *data, size_t len) -{ - u8 *p = data; - while ((p + 2 + WPA_SELECTOR_LEN) < (data + len)) { - if ((p[0] == WLAN_EID_VENDOR_SPECIFIC) && - (memcmp(&p[2], WPA_OUI_TYPE, WPA_SELECTOR_LEN) == 0)) - return p; - p += p[1] + 2; - } - return NULL; -} - -#endif /* _ORINOCO_MAIN_H_ */ diff --git a/drivers/net/wireless/intersil/orinoco/mic.c b/drivers/net/wireless/intersil/orinoco/mic.c deleted file mode 100644 index a324bc4b79388..0000000000000 --- a/drivers/net/wireless/intersil/orinoco/mic.c +++ /dev/null @@ -1,89 +0,0 @@ -/* Orinoco MIC helpers - * - * See copyright notice in main.c - */ -#include -#include -#include -#include -#include - -#include "orinoco.h" -#include "mic.h" - -/********************************************************************/ -/* Michael MIC crypto setup */ -/********************************************************************/ -int orinoco_mic_init(struct orinoco_private *priv) -{ - priv->tx_tfm_mic = crypto_alloc_shash("michael_mic", 0, 0); - if (IS_ERR(priv->tx_tfm_mic)) { - printk(KERN_DEBUG "%s: could not allocate " - "crypto API michael_mic\n", __func__); - priv->tx_tfm_mic = NULL; - return -ENOMEM; - } - - priv->rx_tfm_mic = crypto_alloc_shash("michael_mic", 0, 0); - if (IS_ERR(priv->rx_tfm_mic)) { - printk(KERN_DEBUG "%s: could not allocate " - "crypto API michael_mic\n", __func__); - priv->rx_tfm_mic = NULL; - return -ENOMEM; - } - - return 0; -} - -void orinoco_mic_free(struct orinoco_private *priv) -{ - if (priv->tx_tfm_mic) - crypto_free_shash(priv->tx_tfm_mic); - if (priv->rx_tfm_mic) - crypto_free_shash(priv->rx_tfm_mic); -} - -int orinoco_mic(struct crypto_shash *tfm_michael, u8 *key, - u8 *da, u8 *sa, u8 priority, - u8 *data, size_t data_len, u8 *mic) -{ - SHASH_DESC_ON_STACK(desc, tfm_michael); - u8 hdr[ETH_HLEN + 2]; /* size of header + padding */ - int err; - - if (tfm_michael == NULL) { - printk(KERN_WARNING "%s: tfm_michael == NULL\n", __func__); - return -1; - } - - /* Copy header into buffer. We need the padding on the end zeroed */ - memcpy(&hdr[0], da, ETH_ALEN); - memcpy(&hdr[ETH_ALEN], sa, ETH_ALEN); - hdr[ETH_ALEN * 2] = priority; - hdr[ETH_ALEN * 2 + 1] = 0; - hdr[ETH_ALEN * 2 + 2] = 0; - hdr[ETH_ALEN * 2 + 3] = 0; - - desc->tfm = tfm_michael; - - err = crypto_shash_setkey(tfm_michael, key, MIC_KEYLEN); - if (err) - return err; - - err = crypto_shash_init(desc); - if (err) - return err; - - err = crypto_shash_update(desc, hdr, sizeof(hdr)); - if (err) - return err; - - err = crypto_shash_update(desc, data, data_len); - if (err) - return err; - - err = crypto_shash_final(desc, mic); - shash_desc_zero(desc); - - return err; -} diff --git a/drivers/net/wireless/intersil/orinoco/mic.h b/drivers/net/wireless/intersil/orinoco/mic.h deleted file mode 100644 index e8724e8892194..0000000000000 --- a/drivers/net/wireless/intersil/orinoco/mic.h +++ /dev/null @@ -1,23 +0,0 @@ -/* Orinoco MIC helpers - * - * See copyright notice in main.c - */ -#ifndef _ORINOCO_MIC_H_ -#define _ORINOCO_MIC_H_ - -#include -#include - -#define MICHAEL_MIC_LEN 8 - -/* Forward declarations */ -struct orinoco_private; -struct crypto_ahash; - -int orinoco_mic_init(struct orinoco_private *priv); -void orinoco_mic_free(struct orinoco_private *priv); -int orinoco_mic(struct crypto_shash *tfm_michael, u8 *key, - u8 *da, u8 *sa, u8 priority, - u8 *data, size_t data_len, u8 *mic); - -#endif /* ORINOCO_MIC_H */ diff --git a/drivers/net/wireless/intersil/orinoco/orinoco.h b/drivers/net/wireless/intersil/orinoco/orinoco.h deleted file mode 100644 index cdd026af100b6..0000000000000 --- a/drivers/net/wireless/intersil/orinoco/orinoco.h +++ /dev/null @@ -1,251 +0,0 @@ -/* orinoco.h - * - * Common definitions to all pieces of the various orinoco - * drivers - */ - -#ifndef _ORINOCO_H -#define _ORINOCO_H - -#define DRIVER_VERSION "0.15" - -#include -#include -#include -#include -#include -#include - -#include "hermes.h" - -/* To enable debug messages */ -/*#define ORINOCO_DEBUG 3*/ - -#define WIRELESS_SPY /* enable iwspy support */ - -#define MAX_SCAN_LEN 4096 - -#define ORINOCO_SEQ_LEN 8 -#define ORINOCO_MAX_KEY_SIZE 14 -#define ORINOCO_MAX_KEYS 4 - -struct orinoco_key { - __le16 len; /* always stored as little-endian */ - char data[ORINOCO_MAX_KEY_SIZE]; -} __packed; - -#define TKIP_KEYLEN 16 -#define MIC_KEYLEN 8 - -struct orinoco_tkip_key { - u8 tkip[TKIP_KEYLEN]; - u8 tx_mic[MIC_KEYLEN]; - u8 rx_mic[MIC_KEYLEN]; -}; - -enum orinoco_alg { - ORINOCO_ALG_NONE, - ORINOCO_ALG_WEP, - ORINOCO_ALG_TKIP -}; - -enum fwtype { - FIRMWARE_TYPE_AGERE, - FIRMWARE_TYPE_INTERSIL, - FIRMWARE_TYPE_SYMBOL -}; - -struct firmware; - -struct orinoco_private { - void *card; /* Pointer to card dependent structure */ - struct device *dev; - int (*hard_reset)(struct orinoco_private *); - int (*stop_fw)(struct orinoco_private *, int); - - struct ieee80211_supported_band band; - struct ieee80211_channel channels[14]; - u32 cipher_suites[3]; - - /* Synchronisation stuff */ - spinlock_t lock; - int hw_unavailable; - struct work_struct reset_work; - - /* Interrupt tasklets */ - struct tasklet_struct rx_tasklet; - struct list_head rx_list; - - /* driver state */ - int open; - u16 last_linkstatus; - struct work_struct join_work; - struct work_struct wevent_work; - - /* Net device stuff */ - struct net_device *ndev; - struct iw_statistics wstats; - - /* Hardware control variables */ - struct hermes hw; - u16 txfid; - - /* Capabilities of the hardware/firmware */ - enum fwtype firmware_type; - int ibss_port; - int nicbuf_size; - u16 channel_mask; - - /* Boolean capabilities */ - unsigned int has_ibss:1; - unsigned int has_port3:1; - unsigned int has_wep:1; - unsigned int has_big_wep:1; - unsigned int has_mwo:1; - unsigned int has_pm:1; - unsigned int has_preamble:1; - unsigned int has_sensitivity:1; - unsigned int has_hostscan:1; - unsigned int has_alt_txcntl:1; - unsigned int has_ext_scan:1; - unsigned int has_wpa:1; - unsigned int do_fw_download:1; - unsigned int broken_disableport:1; - unsigned int broken_monitor:1; - unsigned int prefer_port3:1; - - /* Configuration paramaters */ - enum nl80211_iftype iw_mode; - enum orinoco_alg encode_alg; - u16 wep_restrict, tx_key; - struct key_params keys[ORINOCO_MAX_KEYS]; - - int bitratemode; - char nick[IW_ESSID_MAX_SIZE + 1]; - char desired_essid[IW_ESSID_MAX_SIZE + 1]; - char desired_bssid[ETH_ALEN]; - int bssid_fixed; - u16 frag_thresh, mwo_robust; - u16 channel; - u16 ap_density, rts_thresh; - u16 pm_on, pm_mcast, pm_period, pm_timeout; - u16 preamble; - u16 short_retry_limit, long_retry_limit; - u16 retry_lifetime; -#ifdef WIRELESS_SPY - struct iw_spy_data spy_data; /* iwspy support */ - struct iw_public_data wireless_data; -#endif - - /* Configuration dependent variables */ - int port_type, createibss; - int promiscuous, mc_count; - - /* Scanning support */ - struct cfg80211_scan_request *scan_request; - struct work_struct process_scan; - struct list_head scan_list; - spinlock_t scan_lock; /* protects the scan list */ - - /* WPA support */ - u8 *wpa_ie; - int wpa_ie_len; - - struct crypto_shash *rx_tfm_mic; - struct crypto_shash *tx_tfm_mic; - - unsigned int wpa_enabled:1; - unsigned int tkip_cm_active:1; - unsigned int key_mgmt:3; - -#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP) - /* Cached in memory firmware to use during ->resume. */ - const struct firmware *cached_pri_fw; - const struct firmware *cached_fw; -#endif - - struct notifier_block pm_notifier; -}; - -#ifdef ORINOCO_DEBUG -extern int orinoco_debug; -#define DEBUG(n, args...) do { \ - if (orinoco_debug > (n)) \ - printk(KERN_DEBUG args); \ -} while (0) -#else -#define DEBUG(n, args...) do { } while (0) -#endif /* ORINOCO_DEBUG */ - -/********************************************************************/ -/* Exported prototypes */ -/********************************************************************/ - -struct orinoco_private *alloc_orinocodev(int sizeof_card, struct device *device, - int (*hard_reset)(struct orinoco_private *), - int (*stop_fw)(struct orinoco_private *, int)); -void free_orinocodev(struct orinoco_private *priv); -int orinoco_init(struct orinoco_private *priv); -int orinoco_if_add(struct orinoco_private *priv, unsigned long base_addr, - unsigned int irq, const struct net_device_ops *ops); -void orinoco_if_del(struct orinoco_private *priv); -int orinoco_up(struct orinoco_private *priv); -void orinoco_down(struct orinoco_private *priv); -irqreturn_t orinoco_interrupt(int irq, void *dev_id); - -void __orinoco_ev_info(struct net_device *dev, struct hermes *hw); -void __orinoco_ev_rx(struct net_device *dev, struct hermes *hw); - -int orinoco_process_xmit_skb(struct sk_buff *skb, - struct net_device *dev, - struct orinoco_private *priv, - int *tx_control, - u8 *mic); - -/* Common ndo functions exported for reuse by orinoco_usb */ -int orinoco_open(struct net_device *dev); -int orinoco_stop(struct net_device *dev); -void orinoco_set_multicast_list(struct net_device *dev); -int orinoco_change_mtu(struct net_device *dev, int new_mtu); -void orinoco_tx_timeout(struct net_device *dev, unsigned int txqueue); - -/********************************************************************/ -/* Locking and synchronization functions */ -/********************************************************************/ - -static inline int orinoco_lock(struct orinoco_private *priv, - unsigned long *flags) -{ - priv->hw.ops->lock_irqsave(&priv->lock, flags); - if (priv->hw_unavailable) { - DEBUG(1, "orinoco_lock() called with hw_unavailable (dev=%p)\n", - priv->ndev); - priv->hw.ops->unlock_irqrestore(&priv->lock, flags); - return -EBUSY; - } - return 0; -} - -static inline void orinoco_unlock(struct orinoco_private *priv, - unsigned long *flags) -{ - priv->hw.ops->unlock_irqrestore(&priv->lock, flags); -} - -static inline void orinoco_lock_irq(struct orinoco_private *priv) -{ - priv->hw.ops->lock_irq(&priv->lock); -} - -static inline void orinoco_unlock_irq(struct orinoco_private *priv) -{ - priv->hw.ops->unlock_irq(&priv->lock); -} - -/*** Navigate from net_device to orinoco_private ***/ -static inline struct orinoco_private *ndev_priv(struct net_device *dev) -{ - struct wireless_dev *wdev = netdev_priv(dev); - return wdev_priv(wdev); -} -#endif /* _ORINOCO_H */ diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_cs.c b/drivers/net/wireless/intersil/orinoco/orinoco_cs.c deleted file mode 100644 index 03bfd2482656c..0000000000000 --- a/drivers/net/wireless/intersil/orinoco/orinoco_cs.c +++ /dev/null @@ -1,350 +0,0 @@ -/* orinoco_cs.c (formerly known as dldwd_cs.c) - * - * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such - * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ - * EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and others). - * It should also be usable on various Prism II based cards such as the - * Linksys, D-Link and Farallon Skyline. It should also work on Symbol - * cards such as the 3Com AirConnect and Ericsson WLAN. - * - * Copyright notice & release notes in file main.c - */ - -#define DRIVER_NAME "orinoco_cs" -#define PFX DRIVER_NAME ": " - -#include -#include -#include -#include -#include -#include - -#include "orinoco.h" - -/********************************************************************/ -/* Module stuff */ -/********************************************************************/ - -MODULE_AUTHOR("David Gibson "); -MODULE_DESCRIPTION("Driver for PCMCIA Lucent Orinoco," - " Prism II based and similar wireless cards"); -MODULE_LICENSE("Dual MPL/GPL"); - -/* Module parameters */ - -/* Some D-Link cards have buggy CIS. They do work at 5v properly, but - * don't have any CIS entry for it. This workaround it... */ -static int ignore_cis_vcc; /* = 0 */ -module_param(ignore_cis_vcc, int, 0); -MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket"); - -/********************************************************************/ -/* Data structures */ -/********************************************************************/ - -/* PCMCIA specific device information (goes in the card field of - * struct orinoco_private */ -struct orinoco_pccard { - struct pcmcia_device *p_dev; - - /* Used to handle hard reset */ - /* yuck, we need this hack to work around the insanity of the - * PCMCIA layer */ - unsigned long hard_reset_in_progress; -}; - - -/********************************************************************/ -/* Function prototypes */ -/********************************************************************/ - -static int orinoco_cs_config(struct pcmcia_device *link); -static void orinoco_cs_release(struct pcmcia_device *link); -static void orinoco_cs_detach(struct pcmcia_device *p_dev); - -/********************************************************************/ -/* Device methods */ -/********************************************************************/ - -static int -orinoco_cs_hard_reset(struct orinoco_private *priv) -{ - struct orinoco_pccard *card = priv->card; - struct pcmcia_device *link = card->p_dev; - int err; - - /* We need atomic ops here, because we're not holding the lock */ - set_bit(0, &card->hard_reset_in_progress); - - err = pcmcia_reset_card(link->socket); - if (err) - return err; - - msleep(100); - clear_bit(0, &card->hard_reset_in_progress); - - return 0; -} - -/********************************************************************/ -/* PCMCIA stuff */ -/********************************************************************/ - -static int -orinoco_cs_probe(struct pcmcia_device *link) -{ - struct orinoco_private *priv; - struct orinoco_pccard *card; - int ret; - - priv = alloc_orinocodev(sizeof(*card), &link->dev, - orinoco_cs_hard_reset, NULL); - if (!priv) - return -ENOMEM; - card = priv->card; - - /* Link both structures together */ - card->p_dev = link; - link->priv = priv; - - ret = orinoco_cs_config(link); - if (ret) - goto err_free_orinocodev; - - return 0; - -err_free_orinocodev: - free_orinocodev(priv); - return ret; -} - -static void orinoco_cs_detach(struct pcmcia_device *link) -{ - struct orinoco_private *priv = link->priv; - - orinoco_if_del(priv); - - orinoco_cs_release(link); - - wiphy_unregister(priv_to_wiphy(priv)); - free_orinocodev(priv); -} /* orinoco_cs_detach */ - -static int orinoco_cs_config_check(struct pcmcia_device *p_dev, void *priv_data) -{ - if (p_dev->config_index == 0) - return -EINVAL; - - return pcmcia_request_io(p_dev); -}; - -static int -orinoco_cs_config(struct pcmcia_device *link) -{ - struct orinoco_private *priv = link->priv; - struct hermes *hw = &priv->hw; - int ret; - void __iomem *mem; - - link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC | - CONF_AUTO_SET_IO | CONF_ENABLE_IRQ; - if (ignore_cis_vcc) - link->config_flags &= ~CONF_AUTO_CHECK_VCC; - ret = pcmcia_loop_config(link, orinoco_cs_config_check, NULL); - if (ret) { - if (!ignore_cis_vcc) - printk(KERN_ERR PFX "GetNextTuple(): No matching " - "CIS configuration. Maybe you need the " - "ignore_cis_vcc=1 parameter.\n"); - goto failed; - } - - mem = ioport_map(link->resource[0]->start, - resource_size(link->resource[0])); - if (!mem) - goto failed; - - /* We initialize the hermes structure before completing PCMCIA - * configuration just in case the interrupt handler gets - * called. */ - hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING); - - ret = pcmcia_request_irq(link, orinoco_interrupt); - if (ret) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - /* Initialise the main driver */ - if (orinoco_init(priv) != 0) { - printk(KERN_ERR PFX "orinoco_init() failed\n"); - goto failed; - } - - /* Register an interface with the stack */ - if (orinoco_if_add(priv, link->resource[0]->start, - link->irq, NULL) != 0) { - printk(KERN_ERR PFX "orinoco_if_add() failed\n"); - goto failed; - } - - return 0; - - failed: - orinoco_cs_release(link); - return -ENODEV; -} /* orinoco_cs_config */ - -static void -orinoco_cs_release(struct pcmcia_device *link) -{ - struct orinoco_private *priv = link->priv; - unsigned long flags; - - /* We're committed to taking the device away now, so mark the - * hardware as unavailable */ - priv->hw.ops->lock_irqsave(&priv->lock, &flags); - priv->hw_unavailable++; - priv->hw.ops->unlock_irqrestore(&priv->lock, &flags); - - pcmcia_disable_device(link); - if (priv->hw.iobase) - ioport_unmap(priv->hw.iobase); -} /* orinoco_cs_release */ - -static int orinoco_cs_suspend(struct pcmcia_device *link) -{ - struct orinoco_private *priv = link->priv; - struct orinoco_pccard *card = priv->card; - - /* This is probably racy, but I can't think of - a better way, short of rewriting the PCMCIA - layer to not suck :-( */ - if (!test_bit(0, &card->hard_reset_in_progress)) - orinoco_down(priv); - - return 0; -} - -static int orinoco_cs_resume(struct pcmcia_device *link) -{ - struct orinoco_private *priv = link->priv; - struct orinoco_pccard *card = priv->card; - int err = 0; - - if (!test_bit(0, &card->hard_reset_in_progress)) - err = orinoco_up(priv); - - return err; -} - - -/********************************************************************/ -/* Module initialization */ -/********************************************************************/ - -static const struct pcmcia_device_id orinoco_cs_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), /* 3Com AirConnect PCI 777A */ - PCMCIA_DEVICE_MANF_CARD(0x016b, 0x0001), /* Ericsson WLAN Card C11 */ - PCMCIA_DEVICE_MANF_CARD(0x01eb, 0x080a), /* Nortel Networks eMobility 802.11 Wireless Adapter */ - PCMCIA_DEVICE_MANF_CARD(0x0261, 0x0002), /* AirWay 802.11 Adapter (PCMCIA) */ - PCMCIA_DEVICE_MANF_CARD(0x0268, 0x0001), /* ARtem Onair */ - PCMCIA_DEVICE_MANF_CARD(0x0268, 0x0003), /* ARtem Onair Comcard 11 */ - PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0305), /* Buffalo WLI-PCM-S11 */ - PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002), /* ASUS SpaceLink WL-100 */ - PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x0002), /* SpeedStream SS1021 Wireless Adapter */ - PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x3021), /* SpeedStream Wireless Adapter */ - PCMCIA_DEVICE_MANF_CARD(0x14ea, 0xb001), /* PLANEX RoadLannerWave GW-NS11H */ - PCMCIA_DEVICE_PROD_ID12("3Com", "3CRWE737A AirConnect Wireless LAN PC Card", 0x41240e5b, 0x56010af3), - PCMCIA_DEVICE_PROD_ID12("Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio", 0x5cd01705, 0x4271660f), - PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11B_CF_CARD_25", 0x78fc06ee, 0x45a50c1e), - PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11b_PC_CARD_25", 0x78fc06ee, 0xdb9aa842), - PCMCIA_DEVICE_PROD_ID12("Avaya Communication", "Avaya Wireless PC Card", 0xd8a43b78, 0x0d341169), - PCMCIA_DEVICE_PROD_ID12("BENQ", "AWL100 PCMCIA ADAPTER", 0x35dadc74, 0x01f7fedb), - PCMCIA_DEVICE_PROD_ID12("Cabletron", "RoamAbout 802.11 DS", 0x32d445f5, 0xedeffd90), - PCMCIA_DEVICE_PROD_ID12("D-Link Corporation", "D-Link DWL-650H 11Mbps WLAN Adapter", 0xef544d24, 0xcd8ea916), - PCMCIA_DEVICE_PROD_ID12("ELSA", "AirLancer MC-11", 0x4507a33a, 0xef54f0e3), - PCMCIA_DEVICE_PROD_ID12("HyperLink", "Wireless PC Card 11Mbps", 0x56cc3f1a, 0x0bcf220c), - PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless 2011 LAN PC Card", 0x816cc815, 0x07f58077), - PCMCIA_DEVICE_PROD_ID12("LeArtery", "SYNCBYAIR 11Mbps Wireless LAN PC Card", 0x7e3b326a, 0x49893e92), - PCMCIA_DEVICE_PROD_ID12("Lucent Technologies", "WaveLAN/IEEE", 0x23eb9949, 0xc562e72a), - PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11", 0x481e0094, 0x7360e410), - PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11G", 0x481e0094, 0xf57ca4b3), - PCMCIA_DEVICE_PROD_ID12("NCR", "WaveLAN/IEEE", 0x24358cd4, 0xc562e72a), - PCMCIA_DEVICE_PROD_ID12("Nortel Networks", "emobility 802.11 Wireless LAN PC Card", 0x2d617ea0, 0x88cd5767), - PCMCIA_DEVICE_PROD_ID12("OTC", "Wireless AirEZY 2411-PCC WLAN Card", 0x4ac44287, 0x235a6bed), - PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PC CARD HARMONY 80211B", 0xc6536a5e, 0x090c3cd9), - PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PCI CARD HARMONY 80211B", 0xc6536a5e, 0x9f494e26), - PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "11Mbps WLAN Card", 0x43d74cb4, 0x579bd91b), - PCMCIA_DEVICE_PROD_ID12("Symbol Technologies", "LA4111 Spectrum24 Wireless LAN PC Card", 0x3f02b4d6, 0x3663cb0e), - PCMCIA_DEVICE_MANF_CARD_PROD_ID3(0x0156, 0x0002, "Version 01.01", 0xd27deb1a), /* Lucent Orinoco */ -#ifdef CONFIG_HERMES_PRISM - /* Only entries that certainly identify Prism chipset */ - PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100), /* SonicWALL Long Range Wireless Card */ - PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300), /* Sohoware NCP110, Philips 802.11b */ - PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0002), /* AnyPoint(TM) Wireless II PC Card */ - PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000), /* PROXIM RangeLAN-DS/LAN PC CARD */ - PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002), /* Compaq WL100 11 Mbps Wireless Adapter */ - PCMCIA_DEVICE_MANF_CARD(0x01ff, 0x0008), /* Intermec MobileLAN 11Mbps 802.11b WLAN Card */ - PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002), /* Samsung SWL2000-N 11Mb/s WLAN Card */ - PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612), /* Linksys WPC11 Version 2.5 */ - PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613), /* Linksys WPC11 Version 3 */ - PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002), /* Compaq HNW-100 11 Mbps Wireless Adapter */ - PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0673), /* Linksys WCF12 Wireless CompactFlash Card */ - PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300), /* Airvast WN-100 */ - PCMCIA_DEVICE_MANF_CARD(0x9005, 0x0021), /* Adaptec Ultra Wireless ANW-8030 */ - PCMCIA_DEVICE_MANF_CARD(0xc001, 0x0008), /* CONTEC FLEXSCAN/FX-DDS110-PCC */ - PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002), /* Conceptronic CON11Cpro, EMTAC A2424i */ - PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002), /* Safeway 802.11b, ZCOMAX AirRunner/XI-300 */ - PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005), /* D-Link DCF660, Sandisk Connect SDWCFB-000 */ - PCMCIA_DEVICE_PROD_ID123("Instant Wireless ", " Network PC CARD", "Version 01.02", 0x11d901af, 0x6e9bd926, 0x4b74baa0), - PCMCIA_DEVICE_PROD_ID12("ACTIONTEC", "PRISM Wireless LAN PC Card", 0x393089da, 0xa71e69d5), - PCMCIA_DEVICE_PROD_ID12("Addtron", "AWP-100 Wireless PCMCIA", 0xe6ec52ce, 0x08649af2), - PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G", 0x2decece3, 0x82067c18), - PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-PCM-L11G", 0x2decece3, 0xf57ca4b3), - PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card", 0x54f7c49c, 0x15a75e5b), - PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCC-11", 0x5261440f, 0xa6405584), - PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCCA-11", 0x5261440f, 0xdf6115f9), - PCMCIA_DEVICE_PROD_ID12("corega_K.K.", "Wireless_LAN_PCCB-11", 0x29e33311, 0xee7a27ae), - PCMCIA_DEVICE_PROD_ID12("Digital Data Communications", "WPC-0100", 0xfdd73470, 0xe0b6f146), - PCMCIA_DEVICE_PROD_ID12("D", "Link DRC-650 11Mbps WLAN Card", 0x71b18589, 0xf144e3ac), - PCMCIA_DEVICE_PROD_ID12("D", "Link DWL-650 11Mbps WLAN Card", 0x71b18589, 0xb6f1b0ab), - PCMCIA_DEVICE_PROD_ID12(" ", "IEEE 802.11 Wireless LAN/PC Card", 0x3b6e20c8, 0xefccafe9), - PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE", 0x74c5e40d, 0xdb472a18), - PCMCIA_DEVICE_PROD_ID12("INTERSIL", "I-GATE 11M PC Card / PC Card plus", 0x74c5e40d, 0x8304ff77), - PCMCIA_DEVICE_PROD_ID12("Intersil", "PRISM 2_5 PCMCIA ADAPTER", 0x4b801a17, 0x6345a0bf), - PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card", 0x0733cc81, 0x0c52f395), - PCMCIA_DEVICE_PROD_ID12("Microsoft", "Wireless Notebook Adapter MN-520", 0x5961bf85, 0x6eec8c01), - PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401RA Wireless PC", "Card", 0x0306467f, 0x9762e8f1), - PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401 Wireless PC", "Card", 0xa37434e9, 0x9762e8f1), - PCMCIA_DEVICE_PROD_ID12("OEM", "PRISM2 IEEE 802.11 PC-Card", 0xfea54c90, 0x48f2bdd6), - PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-CF110", 0x209f40ab, 0xd9715264), - PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-NS110", 0x209f40ab, 0x46263178), - PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2532W-B EliteConnect Wireless Adapter", 0xc4f8b18b, 0x196bd757), - PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2632W", 0xc4f8b18b, 0x474a1f2a), - PCMCIA_DEVICE_PROD_ID12("ZoomAir 11Mbps High", "Rate wireless Networking", 0x273fe3db, 0x32a1eaee), - PCMCIA_DEVICE_PROD_ID3("HFA3863", 0x355cb092), - PCMCIA_DEVICE_PROD_ID3("ISL37100P", 0x630d52b2), - PCMCIA_DEVICE_PROD_ID3("ISL37101P-10", 0xdd97a26b), - PCMCIA_DEVICE_PROD_ID3("ISL37300P", 0xc9049a39), - - /* This may be Agere or Intersil Firmware */ - PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002), -#endif - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, orinoco_cs_ids); - -static struct pcmcia_driver orinoco_driver = { - .owner = THIS_MODULE, - .name = DRIVER_NAME, - .probe = orinoco_cs_probe, - .remove = orinoco_cs_detach, - .id_table = orinoco_cs_ids, - .suspend = orinoco_cs_suspend, - .resume = orinoco_cs_resume, -}; -module_pcmcia_driver(orinoco_driver); diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_nortel.c b/drivers/net/wireless/intersil/orinoco/orinoco_nortel.c deleted file mode 100644 index 18bd0d9876c23..0000000000000 --- a/drivers/net/wireless/intersil/orinoco/orinoco_nortel.c +++ /dev/null @@ -1,314 +0,0 @@ -/* orinoco_nortel.c - * - * Driver for Prism II devices which would usually be driven by orinoco_cs, - * but are connected to the PCI bus by a PCI-to-PCMCIA adapter used in - * Nortel emobility, Symbol LA-4113 and Symbol LA-4123. - * - * Copyright (C) 2002 Tobias Hoffmann - * (C) 2003 Christoph Jungegger - * - * Some of this code is borrowed from orinoco_plx.c - * Copyright (C) 2001 Daniel Barlow - * Some of this code is borrowed from orinoco_pci.c - * Copyright (C) 2001 Jean Tourrilhes - * Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing - * has been copied from it. linux-wlan-ng-0.1.10 is originally : - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - */ - -#define DRIVER_NAME "orinoco_nortel" -#define PFX DRIVER_NAME ": " - -#include -#include -#include -#include -#include -#include - -#include "orinoco.h" -#include "orinoco_pci.h" - -#define COR_OFFSET (0xe0) /* COR attribute offset of Prism2 PC card */ -#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ - - -/* - * Do a soft reset of the card using the Configuration Option Register - * We need this to get going... - * This is the part of the code that is strongly inspired from wlan-ng - * - * Note bis : Don't try to access HERMES_CMD during the reset phase. - * It just won't work ! - */ -static int orinoco_nortel_cor_reset(struct orinoco_private *priv) -{ - struct orinoco_pci_card *card = priv->card; - - /* Assert the reset until the card notices */ - iowrite16(8, card->bridge_io + 2); - ioread16(card->attr_io + COR_OFFSET); - iowrite16(0x80, card->attr_io + COR_OFFSET); - mdelay(1); - - /* Give time for the card to recover from this hard effort */ - iowrite16(0, card->attr_io + COR_OFFSET); - iowrite16(0, card->attr_io + COR_OFFSET); - mdelay(1); - - /* Set COR as usual */ - iowrite16(COR_VALUE, card->attr_io + COR_OFFSET); - iowrite16(COR_VALUE, card->attr_io + COR_OFFSET); - mdelay(1); - - iowrite16(0x228, card->bridge_io + 2); - - return 0; -} - -static int orinoco_nortel_hw_init(struct orinoco_pci_card *card) -{ - int i; - u32 reg; - - /* Setup bridge */ - if (ioread16(card->bridge_io) & 1) { - printk(KERN_ERR PFX "brg1 answer1 wrong\n"); - return -EBUSY; - } - iowrite16(0x118, card->bridge_io + 2); - iowrite16(0x108, card->bridge_io + 2); - mdelay(30); - iowrite16(0x8, card->bridge_io + 2); - for (i = 0; i < 30; i++) { - mdelay(30); - if (ioread16(card->bridge_io) & 0x10) - break; - } - if (i == 30) { - printk(KERN_ERR PFX "brg1 timed out\n"); - return -EBUSY; - } - if (ioread16(card->attr_io + COR_OFFSET) & 1) { - printk(KERN_ERR PFX "brg2 answer1 wrong\n"); - return -EBUSY; - } - if (ioread16(card->attr_io + COR_OFFSET + 2) & 1) { - printk(KERN_ERR PFX "brg2 answer2 wrong\n"); - return -EBUSY; - } - if (ioread16(card->attr_io + COR_OFFSET + 4) & 1) { - printk(KERN_ERR PFX "brg2 answer3 wrong\n"); - return -EBUSY; - } - - /* Set the PCMCIA COR register */ - iowrite16(COR_VALUE, card->attr_io + COR_OFFSET); - mdelay(1); - reg = ioread16(card->attr_io + COR_OFFSET); - if (reg != COR_VALUE) { - printk(KERN_ERR PFX "Error setting COR value (reg=%x)\n", - reg); - return -EBUSY; - } - - /* Set LEDs */ - iowrite16(1, card->bridge_io + 10); - return 0; -} - -static int orinoco_nortel_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - int err; - struct orinoco_private *priv; - struct orinoco_pci_card *card; - void __iomem *hermes_io, *bridge_io, *attr_io; - - err = pci_enable_device(pdev); - if (err) { - printk(KERN_ERR PFX "Cannot enable PCI device\n"); - return err; - } - - err = pci_request_regions(pdev, DRIVER_NAME); - if (err) { - printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); - goto fail_resources; - } - - bridge_io = pci_iomap(pdev, 0, 0); - if (!bridge_io) { - printk(KERN_ERR PFX "Cannot map bridge registers\n"); - err = -EIO; - goto fail_map_bridge; - } - - attr_io = pci_iomap(pdev, 1, 0); - if (!attr_io) { - printk(KERN_ERR PFX "Cannot map PCMCIA attributes\n"); - err = -EIO; - goto fail_map_attr; - } - - hermes_io = pci_iomap(pdev, 2, 0); - if (!hermes_io) { - printk(KERN_ERR PFX "Cannot map chipset registers\n"); - err = -EIO; - goto fail_map_hermes; - } - - /* Allocate network device */ - priv = alloc_orinocodev(sizeof(*card), &pdev->dev, - orinoco_nortel_cor_reset, NULL); - if (!priv) { - printk(KERN_ERR PFX "Cannot allocate network device\n"); - err = -ENOMEM; - goto fail_alloc; - } - - card = priv->card; - card->bridge_io = bridge_io; - card->attr_io = attr_io; - - hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); - - err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - DRIVER_NAME, priv); - if (err) { - printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); - err = -EBUSY; - goto fail_irq; - } - - err = orinoco_nortel_hw_init(card); - if (err) { - printk(KERN_ERR PFX "Hardware initialization failed\n"); - goto fail; - } - - err = orinoco_nortel_cor_reset(priv); - if (err) { - printk(KERN_ERR PFX "Initial reset failed\n"); - goto fail; - } - - err = orinoco_init(priv); - if (err) { - printk(KERN_ERR PFX "orinoco_init() failed\n"); - goto fail; - } - - err = orinoco_if_add(priv, 0, 0, NULL); - if (err) { - printk(KERN_ERR PFX "orinoco_if_add() failed\n"); - goto fail_wiphy; - } - - pci_set_drvdata(pdev, priv); - - return 0; - - fail_wiphy: - wiphy_unregister(priv_to_wiphy(priv)); - fail: - free_irq(pdev->irq, priv); - - fail_irq: - free_orinocodev(priv); - - fail_alloc: - pci_iounmap(pdev, hermes_io); - - fail_map_hermes: - pci_iounmap(pdev, attr_io); - - fail_map_attr: - pci_iounmap(pdev, bridge_io); - - fail_map_bridge: - pci_release_regions(pdev); - - fail_resources: - pci_disable_device(pdev); - - return err; -} - -static void orinoco_nortel_remove_one(struct pci_dev *pdev) -{ - struct orinoco_private *priv = pci_get_drvdata(pdev); - struct orinoco_pci_card *card = priv->card; - - /* Clear LEDs */ - iowrite16(0, card->bridge_io + 10); - - orinoco_if_del(priv); - wiphy_unregister(priv_to_wiphy(priv)); - free_irq(pdev->irq, priv); - free_orinocodev(priv); - pci_iounmap(pdev, priv->hw.iobase); - pci_iounmap(pdev, card->attr_io); - pci_iounmap(pdev, card->bridge_io); - pci_release_regions(pdev); - pci_disable_device(pdev); -} - -static const struct pci_device_id orinoco_nortel_id_table[] = { - /* Nortel emobility PCI */ - {0x126c, 0x8030, PCI_ANY_ID, PCI_ANY_ID,}, - /* Symbol LA-4123 PCI */ - {0x1562, 0x0001, PCI_ANY_ID, PCI_ANY_ID,}, - {0,}, -}; - -MODULE_DEVICE_TABLE(pci, orinoco_nortel_id_table); - -static struct pci_driver orinoco_nortel_driver = { - .name = DRIVER_NAME, - .id_table = orinoco_nortel_id_table, - .probe = orinoco_nortel_init_one, - .remove = orinoco_nortel_remove_one, - .driver.pm = &orinoco_pci_pm_ops, -}; - -static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION - " (Tobias Hoffmann & Christoph Jungegger )"; -MODULE_AUTHOR("Christoph Jungegger "); -MODULE_DESCRIPTION("Driver for wireless LAN cards using the Nortel PCI bridge"); -MODULE_LICENSE("Dual MPL/GPL"); - -static int __init orinoco_nortel_init(void) -{ - printk(KERN_DEBUG "%s\n", version); - return pci_register_driver(&orinoco_nortel_driver); -} - -static void __exit orinoco_nortel_exit(void) -{ - pci_unregister_driver(&orinoco_nortel_driver); -} - -module_init(orinoco_nortel_init); -module_exit(orinoco_nortel_exit); diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_pci.c b/drivers/net/wireless/intersil/orinoco/orinoco_pci.c deleted file mode 100644 index 7e3a6dd60c157..0000000000000 --- a/drivers/net/wireless/intersil/orinoco/orinoco_pci.c +++ /dev/null @@ -1,257 +0,0 @@ -/* orinoco_pci.c - * - * Driver for Prism 2.5/3 devices that have a direct PCI interface - * (i.e. these are not PCMCIA cards in a PCMCIA-to-PCI bridge). - * The card contains only one PCI region, which contains all the usual - * hermes registers, as well as the COR register. - * - * Current maintainers are: - * Pavel Roskin - * and David Gibson - * - * Some of this code is borrowed from orinoco_plx.c - * Copyright (C) 2001 Daniel Barlow - * Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing - * has been copied from it. linux-wlan-ng-0.1.10 is originally : - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * This file originally written by: - * Copyright (C) 2001 Jean Tourrilhes - * And is now maintained by: - * (C) Copyright David Gibson, IBM Corp. 2002-2003. - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - */ - -#define DRIVER_NAME "orinoco_pci" -#define PFX DRIVER_NAME ": " - -#include -#include -#include -#include -#include - -#include "orinoco.h" -#include "orinoco_pci.h" - -/* Offset of the COR register of the PCI card */ -#define HERMES_PCI_COR (0x26) - -/* Bitmask to reset the card */ -#define HERMES_PCI_COR_MASK (0x0080) - -/* Magic timeouts for doing the reset. - * Those times are straight from wlan-ng, and it is claimed that they - * are necessary. Alan will kill me. Take your time and grab a coffee. */ -#define HERMES_PCI_COR_ONT (250) /* ms */ -#define HERMES_PCI_COR_OFFT (500) /* ms */ -#define HERMES_PCI_COR_BUSYT (500) /* ms */ - -/* - * Do a soft reset of the card using the Configuration Option Register - * We need this to get going... - * This is the part of the code that is strongly inspired from wlan-ng - * - * Note : This code is done with irq enabled. This mean that many - * interrupts will occur while we are there. This is why we use the - * jiffies to regulate time instead of a straight mdelay(). Usually we - * need only around 245 iteration of the loop to do 250 ms delay. - * - * Note bis : Don't try to access HERMES_CMD during the reset phase. - * It just won't work ! - */ -static int orinoco_pci_cor_reset(struct orinoco_private *priv) -{ - struct hermes *hw = &priv->hw; - unsigned long timeout; - u16 reg; - - /* Assert the reset until the card notices */ - hermes_write_regn(hw, PCI_COR, HERMES_PCI_COR_MASK); - mdelay(HERMES_PCI_COR_ONT); - - /* Give time for the card to recover from this hard effort */ - hermes_write_regn(hw, PCI_COR, 0x0000); - mdelay(HERMES_PCI_COR_OFFT); - - /* The card is ready when it's no longer busy */ - timeout = jiffies + msecs_to_jiffies(HERMES_PCI_COR_BUSYT); - reg = hermes_read_regn(hw, CMD); - while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) { - mdelay(1); - reg = hermes_read_regn(hw, CMD); - } - - /* Still busy? */ - if (reg & HERMES_CMD_BUSY) { - printk(KERN_ERR PFX "Busy timeout\n"); - return -ETIMEDOUT; - } - - return 0; -} - -static int orinoco_pci_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - int err; - struct orinoco_private *priv; - struct orinoco_pci_card *card; - void __iomem *hermes_io; - - err = pci_enable_device(pdev); - if (err) { - printk(KERN_ERR PFX "Cannot enable PCI device\n"); - return err; - } - - err = pci_request_regions(pdev, DRIVER_NAME); - if (err) { - printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); - goto fail_resources; - } - - hermes_io = pci_iomap(pdev, 0, 0); - if (!hermes_io) { - printk(KERN_ERR PFX "Cannot remap chipset registers\n"); - err = -EIO; - goto fail_map_hermes; - } - - /* Allocate network device */ - priv = alloc_orinocodev(sizeof(*card), &pdev->dev, - orinoco_pci_cor_reset, NULL); - if (!priv) { - printk(KERN_ERR PFX "Cannot allocate network device\n"); - err = -ENOMEM; - goto fail_alloc; - } - - card = priv->card; - - hermes_struct_init(&priv->hw, hermes_io, HERMES_32BIT_REGSPACING); - - err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - DRIVER_NAME, priv); - if (err) { - printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); - err = -EBUSY; - goto fail_irq; - } - - err = orinoco_pci_cor_reset(priv); - if (err) { - printk(KERN_ERR PFX "Initial reset failed\n"); - goto fail; - } - - err = orinoco_init(priv); - if (err) { - printk(KERN_ERR PFX "orinoco_init() failed\n"); - goto fail; - } - - err = orinoco_if_add(priv, 0, 0, NULL); - if (err) { - printk(KERN_ERR PFX "orinoco_if_add() failed\n"); - goto fail_wiphy; - } - - pci_set_drvdata(pdev, priv); - - return 0; - - fail_wiphy: - wiphy_unregister(priv_to_wiphy(priv)); - fail: - free_irq(pdev->irq, priv); - - fail_irq: - free_orinocodev(priv); - - fail_alloc: - pci_iounmap(pdev, hermes_io); - - fail_map_hermes: - pci_release_regions(pdev); - - fail_resources: - pci_disable_device(pdev); - - return err; -} - -static void orinoco_pci_remove_one(struct pci_dev *pdev) -{ - struct orinoco_private *priv = pci_get_drvdata(pdev); - - orinoco_if_del(priv); - wiphy_unregister(priv_to_wiphy(priv)); - free_irq(pdev->irq, priv); - free_orinocodev(priv); - pci_iounmap(pdev, priv->hw.iobase); - pci_release_regions(pdev); - pci_disable_device(pdev); -} - -static const struct pci_device_id orinoco_pci_id_table[] = { - /* Intersil Prism 3 */ - {0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID,}, - /* Intersil Prism 2.5 */ - {0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID,}, - /* Samsung MagicLAN SWL-2210P */ - {0x167d, 0xa000, PCI_ANY_ID, PCI_ANY_ID,}, - {0,}, -}; - -MODULE_DEVICE_TABLE(pci, orinoco_pci_id_table); - -static struct pci_driver orinoco_pci_driver = { - .name = DRIVER_NAME, - .id_table = orinoco_pci_id_table, - .probe = orinoco_pci_init_one, - .remove = orinoco_pci_remove_one, - .driver.pm = &orinoco_pci_pm_ops, -}; - -static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION - " (Pavel Roskin ," - " David Gibson &" - " Jean Tourrilhes )"; -MODULE_AUTHOR("Pavel Roskin &" - " David Gibson "); -MODULE_DESCRIPTION("Driver for wireless LAN cards using direct PCI interface"); -MODULE_LICENSE("Dual MPL/GPL"); - -static int __init orinoco_pci_init(void) -{ - printk(KERN_DEBUG "%s\n", version); - return pci_register_driver(&orinoco_pci_driver); -} - -static void __exit orinoco_pci_exit(void) -{ - pci_unregister_driver(&orinoco_pci_driver); -} - -module_init(orinoco_pci_init); -module_exit(orinoco_pci_exit); diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_pci.h b/drivers/net/wireless/intersil/orinoco/orinoco_pci.h deleted file mode 100644 index d49d940864b41..0000000000000 --- a/drivers/net/wireless/intersil/orinoco/orinoco_pci.h +++ /dev/null @@ -1,54 +0,0 @@ -/* orinoco_pci.h - * - * Common code for all Orinoco drivers for PCI devices, including - * both native PCI and PCMCIA-to-PCI bridges. - * - * Copyright (C) 2005, Pavel Roskin. - * See main.c for license. - */ - -#ifndef _ORINOCO_PCI_H -#define _ORINOCO_PCI_H - -#include - -/* Driver specific data */ -struct orinoco_pci_card { - void __iomem *bridge_io; - void __iomem *attr_io; -}; - -static int __maybe_unused orinoco_pci_suspend(struct device *dev_d) -{ - struct pci_dev *pdev = to_pci_dev(dev_d); - struct orinoco_private *priv = pci_get_drvdata(pdev); - - orinoco_down(priv); - free_irq(pdev->irq, priv); - - return 0; -} - -static int __maybe_unused orinoco_pci_resume(struct device *dev_d) -{ - struct pci_dev *pdev = to_pci_dev(dev_d); - struct orinoco_private *priv = pci_get_drvdata(pdev); - struct net_device *dev = priv->ndev; - int err; - - err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - dev->name, priv); - if (err) { - printk(KERN_ERR "%s: cannot re-allocate IRQ on resume\n", - dev->name); - return -EBUSY; - } - - return orinoco_up(priv); -} - -static SIMPLE_DEV_PM_OPS(orinoco_pci_pm_ops, - orinoco_pci_suspend, - orinoco_pci_resume); - -#endif /* _ORINOCO_PCI_H */ diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_plx.c b/drivers/net/wireless/intersil/orinoco/orinoco_plx.c deleted file mode 100644 index 73e6ae1240130..0000000000000 --- a/drivers/net/wireless/intersil/orinoco/orinoco_plx.c +++ /dev/null @@ -1,362 +0,0 @@ -/* orinoco_plx.c - * - * Driver for Prism II devices which would usually be driven by orinoco_cs, - * but are connected to the PCI bus by a PLX9052. - * - * Current maintainers are: - * Pavel Roskin - * and David Gibson - * - * (C) Copyright David Gibson, IBM Corp. 2001-2003. - * Copyright (C) 2001 Daniel Barlow - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - * - * Here's the general details on how the PLX9052 adapter works: - * - * - Two PCI I/O address spaces, one 0x80 long which contains the - * PLX9052 registers, and one that's 0x40 long mapped to the PCMCIA - * slot I/O address space. - * - * - One PCI memory address space, mapped to the PCMCIA attribute space - * (containing the CIS). - * - * Using the later, you can read through the CIS data to make sure the - * card is compatible with the driver. Keep in mind that the PCMCIA - * spec specifies the CIS as the lower 8 bits of each word read from - * the CIS, so to read the bytes of the CIS, read every other byte - * (0,2,4,...). Passing that test, you need to enable the I/O address - * space on the PCMCIA card via the PCMCIA COR register. This is the - * first byte following the CIS. In my case (which may not have any - * relation to what's on the PRISM2 cards), COR was at offset 0x800 - * within the PCI memory space. Write 0x41 to the COR register to - * enable I/O mode and to select level triggered interrupts. To - * confirm you actually succeeded, read the COR register back and make - * sure it actually got set to 0x41, in case you have an unexpected - * card inserted. - * - * Following that, you can treat the second PCI I/O address space (the - * one that's not 0x80 in length) as the PCMCIA I/O space. - * - * Note that in the Eumitcom's source for their drivers, they register - * the interrupt as edge triggered when registering it with the - * Windows kernel. I don't recall how to register edge triggered on - * Linux (if it can be done at all). But in some experimentation, I - * don't see much operational difference between using either - * interrupt mode. Don't mess with the interrupt mode in the COR - * register though, as the PLX9052 wants level triggers with the way - * the serial EEPROM configures it on the WL11000. - * - * There's some other little quirks related to timing that I bumped - * into, but I don't recall right now. Also, there's two variants of - * the WL11000 I've seen, revision A1 and T2. These seem to differ - * slightly in the timings configured in the wait-state generator in - * the PLX9052. There have also been some comments from Eumitcom that - * cards shouldn't be hot swapped, apparently due to risk of cooking - * the PLX9052. I'm unsure why they believe this, as I can't see - * anything in the design that would really cause a problem, except - * for crashing drivers not written to expect it. And having developed - * drivers for the WL11000, I'd say it's quite tricky to write code - * that will successfully deal with a hot unplug. Very odd things - * happen on the I/O side of things. But anyway, be warned. Despite - * that, I've hot-swapped a number of times during debugging and - * driver development for various reasons (stuck WAIT# line after the - * radio card's firmware locks up). - */ - -#define DRIVER_NAME "orinoco_plx" -#define PFX DRIVER_NAME ": " - -#include -#include -#include -#include -#include -#include - -#include "orinoco.h" -#include "orinoco_pci.h" - -#define COR_OFFSET (0x3e0) /* COR attribute offset of Prism2 PC card */ -#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ -#define COR_RESET (0x80) /* reset bit in the COR register */ -#define PLX_RESET_TIME (500) /* milliseconds */ - -#define PLX_INTCSR 0x4c /* Interrupt Control & Status Register */ -#define PLX_INTCSR_INTEN (1 << 6) /* Interrupt Enable bit */ - -/* - * Do a soft reset of the card using the Configuration Option Register - */ -static int orinoco_plx_cor_reset(struct orinoco_private *priv) -{ - struct hermes *hw = &priv->hw; - struct orinoco_pci_card *card = priv->card; - unsigned long timeout; - u16 reg; - - iowrite8(COR_VALUE | COR_RESET, card->attr_io + COR_OFFSET); - mdelay(1); - - iowrite8(COR_VALUE, card->attr_io + COR_OFFSET); - mdelay(1); - - /* Just in case, wait more until the card is no longer busy */ - timeout = jiffies + msecs_to_jiffies(PLX_RESET_TIME); - reg = hermes_read_regn(hw, CMD); - while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) { - mdelay(1); - reg = hermes_read_regn(hw, CMD); - } - - /* Still busy? */ - if (reg & HERMES_CMD_BUSY) { - printk(KERN_ERR PFX "Busy timeout\n"); - return -ETIMEDOUT; - } - - return 0; -} - -static int orinoco_plx_hw_init(struct orinoco_pci_card *card) -{ - int i; - u32 csr_reg; - static const u8 cis_magic[] = { - 0x01, 0x03, 0x00, 0x00, 0xff, 0x17, 0x04, 0x67 - }; - - printk(KERN_DEBUG PFX "CIS: "); - for (i = 0; i < 16; i++) - printk("%02X:", ioread8(card->attr_io + (i << 1))); - printk("\n"); - - /* Verify whether a supported PC card is present */ - /* FIXME: we probably need to be smarted about this */ - for (i = 0; i < sizeof(cis_magic); i++) { - if (cis_magic[i] != ioread8(card->attr_io + (i << 1))) { - printk(KERN_ERR PFX "The CIS value of Prism2 PC " - "card is unexpected\n"); - return -ENODEV; - } - } - - /* bjoern: We need to tell the card to enable interrupts, in - case the serial eprom didn't do this already. See the - PLX9052 data book, p8-1 and 8-24 for reference. */ - csr_reg = ioread32(card->bridge_io + PLX_INTCSR); - if (!(csr_reg & PLX_INTCSR_INTEN)) { - csr_reg |= PLX_INTCSR_INTEN; - iowrite32(csr_reg, card->bridge_io + PLX_INTCSR); - csr_reg = ioread32(card->bridge_io + PLX_INTCSR); - if (!(csr_reg & PLX_INTCSR_INTEN)) { - printk(KERN_ERR PFX "Cannot enable interrupts\n"); - return -EIO; - } - } - - return 0; -} - -static int orinoco_plx_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - int err; - struct orinoco_private *priv; - struct orinoco_pci_card *card; - void __iomem *hermes_io, *attr_io, *bridge_io; - - err = pci_enable_device(pdev); - if (err) { - printk(KERN_ERR PFX "Cannot enable PCI device\n"); - return err; - } - - err = pci_request_regions(pdev, DRIVER_NAME); - if (err) { - printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); - goto fail_resources; - } - - bridge_io = pci_iomap(pdev, 1, 0); - if (!bridge_io) { - printk(KERN_ERR PFX "Cannot map bridge registers\n"); - err = -EIO; - goto fail_map_bridge; - } - - attr_io = pci_iomap(pdev, 2, 0); - if (!attr_io) { - printk(KERN_ERR PFX "Cannot map PCMCIA attributes\n"); - err = -EIO; - goto fail_map_attr; - } - - hermes_io = pci_iomap(pdev, 3, 0); - if (!hermes_io) { - printk(KERN_ERR PFX "Cannot map chipset registers\n"); - err = -EIO; - goto fail_map_hermes; - } - - /* Allocate network device */ - priv = alloc_orinocodev(sizeof(*card), &pdev->dev, - orinoco_plx_cor_reset, NULL); - if (!priv) { - printk(KERN_ERR PFX "Cannot allocate network device\n"); - err = -ENOMEM; - goto fail_alloc; - } - - card = priv->card; - card->bridge_io = bridge_io; - card->attr_io = attr_io; - - hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); - - err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - DRIVER_NAME, priv); - if (err) { - printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); - err = -EBUSY; - goto fail_irq; - } - - err = orinoco_plx_hw_init(card); - if (err) { - printk(KERN_ERR PFX "Hardware initialization failed\n"); - goto fail; - } - - err = orinoco_plx_cor_reset(priv); - if (err) { - printk(KERN_ERR PFX "Initial reset failed\n"); - goto fail; - } - - err = orinoco_init(priv); - if (err) { - printk(KERN_ERR PFX "orinoco_init() failed\n"); - goto fail; - } - - err = orinoco_if_add(priv, 0, 0, NULL); - if (err) { - printk(KERN_ERR PFX "orinoco_if_add() failed\n"); - goto fail_wiphy; - } - - pci_set_drvdata(pdev, priv); - - return 0; - - fail_wiphy: - wiphy_unregister(priv_to_wiphy(priv)); - fail: - free_irq(pdev->irq, priv); - - fail_irq: - free_orinocodev(priv); - - fail_alloc: - pci_iounmap(pdev, hermes_io); - - fail_map_hermes: - pci_iounmap(pdev, attr_io); - - fail_map_attr: - pci_iounmap(pdev, bridge_io); - - fail_map_bridge: - pci_release_regions(pdev); - - fail_resources: - pci_disable_device(pdev); - - return err; -} - -static void orinoco_plx_remove_one(struct pci_dev *pdev) -{ - struct orinoco_private *priv = pci_get_drvdata(pdev); - struct orinoco_pci_card *card = priv->card; - - orinoco_if_del(priv); - wiphy_unregister(priv_to_wiphy(priv)); - free_irq(pdev->irq, priv); - free_orinocodev(priv); - pci_iounmap(pdev, priv->hw.iobase); - pci_iounmap(pdev, card->attr_io); - pci_iounmap(pdev, card->bridge_io); - pci_release_regions(pdev); - pci_disable_device(pdev); -} - -static const struct pci_device_id orinoco_plx_id_table[] = { - {0x111a, 0x1023, PCI_ANY_ID, PCI_ANY_ID,}, /* Siemens SpeedStream SS1023 */ - {0x1385, 0x4100, PCI_ANY_ID, PCI_ANY_ID,}, /* Netgear MA301 */ - {0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,}, /* Correga - does this work? */ - {0x1638, 0x1100, PCI_ANY_ID, PCI_ANY_ID,}, /* SMC EZConnect SMC2602W, - Eumitcom PCI WL11000, - Addtron AWA-100 */ - {0x16ab, 0x1100, PCI_ANY_ID, PCI_ANY_ID,}, /* Global Sun Tech GL24110P */ - {0x16ab, 0x1101, PCI_ANY_ID, PCI_ANY_ID,}, /* Reported working, but unknown */ - {0x16ab, 0x1102, PCI_ANY_ID, PCI_ANY_ID,}, /* Linksys WDT11 */ - {0x16ec, 0x3685, PCI_ANY_ID, PCI_ANY_ID,}, /* USR 2415 */ - {0xec80, 0xec00, PCI_ANY_ID, PCI_ANY_ID,}, /* Belkin F5D6000 tested by - Brendan W. McAdams */ - {0x10b7, 0x7770, PCI_ANY_ID, PCI_ANY_ID,}, /* 3Com AirConnect PCI tested by - Damien Persohn */ - {0,}, -}; - -MODULE_DEVICE_TABLE(pci, orinoco_plx_id_table); - -static struct pci_driver orinoco_plx_driver = { - .name = DRIVER_NAME, - .id_table = orinoco_plx_id_table, - .probe = orinoco_plx_init_one, - .remove = orinoco_plx_remove_one, - .driver.pm = &orinoco_pci_pm_ops, -}; - -static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION - " (Pavel Roskin ," - " David Gibson ," - " Daniel Barlow )"; -MODULE_AUTHOR("Daniel Barlow "); -MODULE_DESCRIPTION("Driver for wireless LAN cards using the PLX9052 PCI bridge"); -MODULE_LICENSE("Dual MPL/GPL"); - -static int __init orinoco_plx_init(void) -{ - printk(KERN_DEBUG "%s\n", version); - return pci_register_driver(&orinoco_plx_driver); -} - -static void __exit orinoco_plx_exit(void) -{ - pci_unregister_driver(&orinoco_plx_driver); -} - -module_init(orinoco_plx_init); -module_exit(orinoco_plx_exit); diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_tmd.c b/drivers/net/wireless/intersil/orinoco/orinoco_tmd.c deleted file mode 100644 index 939d5a1dce970..0000000000000 --- a/drivers/net/wireless/intersil/orinoco/orinoco_tmd.c +++ /dev/null @@ -1,237 +0,0 @@ -/* orinoco_tmd.c - * - * Driver for Prism II devices which would usually be driven by orinoco_cs, - * but are connected to the PCI bus by a TMD7160. - * - * Copyright (C) 2003 Joerg Dorchain - * based heavily upon orinoco_plx.c Copyright (C) 2001 Daniel Barlow - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - * - * The actual driving is done by main.c, this is just resource - * allocation stuff. - * - * This driver is modeled after the orinoco_plx driver. The main - * difference is that the TMD chip has only IO port ranges and doesn't - * provide access to the PCMCIA attribute space. - * - * Pheecom sells cards with the TMD chip as "ASIC version" - */ - -#define DRIVER_NAME "orinoco_tmd" -#define PFX DRIVER_NAME ": " - -#include -#include -#include -#include -#include -#include - -#include "orinoco.h" -#include "orinoco_pci.h" - -#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ -#define COR_RESET (0x80) /* reset bit in the COR register */ -#define TMD_RESET_TIME (500) /* milliseconds */ - -/* - * Do a soft reset of the card using the Configuration Option Register - */ -static int orinoco_tmd_cor_reset(struct orinoco_private *priv) -{ - struct hermes *hw = &priv->hw; - struct orinoco_pci_card *card = priv->card; - unsigned long timeout; - u16 reg; - - iowrite8(COR_VALUE | COR_RESET, card->bridge_io); - mdelay(1); - - iowrite8(COR_VALUE, card->bridge_io); - mdelay(1); - - /* Just in case, wait more until the card is no longer busy */ - timeout = jiffies + msecs_to_jiffies(TMD_RESET_TIME); - reg = hermes_read_regn(hw, CMD); - while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) { - mdelay(1); - reg = hermes_read_regn(hw, CMD); - } - - /* Still busy? */ - if (reg & HERMES_CMD_BUSY) { - printk(KERN_ERR PFX "Busy timeout\n"); - return -ETIMEDOUT; - } - - return 0; -} - - -static int orinoco_tmd_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - int err; - struct orinoco_private *priv; - struct orinoco_pci_card *card; - void __iomem *hermes_io, *bridge_io; - - err = pci_enable_device(pdev); - if (err) { - printk(KERN_ERR PFX "Cannot enable PCI device\n"); - return err; - } - - err = pci_request_regions(pdev, DRIVER_NAME); - if (err) { - printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); - goto fail_resources; - } - - bridge_io = pci_iomap(pdev, 1, 0); - if (!bridge_io) { - printk(KERN_ERR PFX "Cannot map bridge registers\n"); - err = -EIO; - goto fail_map_bridge; - } - - hermes_io = pci_iomap(pdev, 2, 0); - if (!hermes_io) { - printk(KERN_ERR PFX "Cannot map chipset registers\n"); - err = -EIO; - goto fail_map_hermes; - } - - /* Allocate network device */ - priv = alloc_orinocodev(sizeof(*card), &pdev->dev, - orinoco_tmd_cor_reset, NULL); - if (!priv) { - printk(KERN_ERR PFX "Cannot allocate network device\n"); - err = -ENOMEM; - goto fail_alloc; - } - - card = priv->card; - card->bridge_io = bridge_io; - - hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); - - err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - DRIVER_NAME, priv); - if (err) { - printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); - err = -EBUSY; - goto fail_irq; - } - - err = orinoco_tmd_cor_reset(priv); - if (err) { - printk(KERN_ERR PFX "Initial reset failed\n"); - goto fail; - } - - err = orinoco_init(priv); - if (err) { - printk(KERN_ERR PFX "orinoco_init() failed\n"); - goto fail; - } - - err = orinoco_if_add(priv, 0, 0, NULL); - if (err) { - printk(KERN_ERR PFX "orinoco_if_add() failed\n"); - goto fail; - } - - pci_set_drvdata(pdev, priv); - - return 0; - - fail: - free_irq(pdev->irq, priv); - - fail_irq: - free_orinocodev(priv); - - fail_alloc: - pci_iounmap(pdev, hermes_io); - - fail_map_hermes: - pci_iounmap(pdev, bridge_io); - - fail_map_bridge: - pci_release_regions(pdev); - - fail_resources: - pci_disable_device(pdev); - - return err; -} - -static void orinoco_tmd_remove_one(struct pci_dev *pdev) -{ - struct orinoco_private *priv = pci_get_drvdata(pdev); - struct orinoco_pci_card *card = priv->card; - - orinoco_if_del(priv); - free_irq(pdev->irq, priv); - free_orinocodev(priv); - pci_iounmap(pdev, priv->hw.iobase); - pci_iounmap(pdev, card->bridge_io); - pci_release_regions(pdev); - pci_disable_device(pdev); -} - -static const struct pci_device_id orinoco_tmd_id_table[] = { - {0x15e8, 0x0131, PCI_ANY_ID, PCI_ANY_ID,}, /* NDC and OEMs, e.g. pheecom */ - {0,}, -}; - -MODULE_DEVICE_TABLE(pci, orinoco_tmd_id_table); - -static struct pci_driver orinoco_tmd_driver = { - .name = DRIVER_NAME, - .id_table = orinoco_tmd_id_table, - .probe = orinoco_tmd_init_one, - .remove = orinoco_tmd_remove_one, - .driver.pm = &orinoco_pci_pm_ops, -}; - -static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION - " (Joerg Dorchain )"; -MODULE_AUTHOR("Joerg Dorchain "); -MODULE_DESCRIPTION("Driver for wireless LAN cards using the TMD7160 PCI bridge"); -MODULE_LICENSE("Dual MPL/GPL"); - -static int __init orinoco_tmd_init(void) -{ - printk(KERN_DEBUG "%s\n", version); - return pci_register_driver(&orinoco_tmd_driver); -} - -static void __exit orinoco_tmd_exit(void) -{ - pci_unregister_driver(&orinoco_tmd_driver); -} - -module_init(orinoco_tmd_init); -module_exit(orinoco_tmd_exit); diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c deleted file mode 100644 index 866e0230df251..0000000000000 --- a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c +++ /dev/null @@ -1,1787 +0,0 @@ -/* - * USB Orinoco driver - * - * Copyright (c) 2003 Manuel Estrada Sainz - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - * - * Queueing code based on linux-wlan-ng 0.2.1-pre5 - * - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * - * The license is the same as above. - * - * Initialy based on USB Skeleton driver - 0.7 - * - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.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. - * - * NOTE: The original USB Skeleton driver is GPL, but all that code is - * gone so MPL/GPL applies. - */ - -#define DRIVER_NAME "orinoco_usb" -#define PFX DRIVER_NAME ": " - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "mic.h" -#include "orinoco.h" - -#ifndef URB_ASYNC_UNLINK -#define URB_ASYNC_UNLINK 0 -#endif - -struct header_struct { - /* 802.3 */ - u8 dest[ETH_ALEN]; - u8 src[ETH_ALEN]; - __be16 len; - /* 802.2 */ - u8 dsap; - u8 ssap; - u8 ctrl; - /* SNAP */ - u8 oui[3]; - __be16 ethertype; -} __packed; - -struct ez_usb_fw { - u16 size; - const u8 *code; -}; - -static struct ez_usb_fw firmware = { - .size = 0, - .code = NULL, -}; - -/* Debugging macros */ -#undef err -#define err(format, arg...) \ - do { printk(KERN_ERR PFX format "\n", ## arg); } while (0) - -MODULE_FIRMWARE("orinoco_ezusb_fw"); - -/* - * Under some conditions, the card gets stuck and stops paying attention - * to the world (i.e. data communication stalls) until we do something to - * it. Sending an INQ_TALLIES command seems to be enough and should be - * harmless otherwise. This behaviour has been observed when using the - * driver on a systemimager client during installation. In the past a - * timer was used to send INQ_TALLIES commands when there was no other - * activity, but it was troublesome and was removed. - */ - -#define USB_COMPAQ_VENDOR_ID 0x049f /* Compaq Computer Corp. */ -#define USB_COMPAQ_WL215_ID 0x001f /* Compaq WL215 USB Adapter */ -#define USB_COMPAQ_W200_ID 0x0076 /* Compaq W200 USB Adapter */ -#define USB_HP_WL215_ID 0x0082 /* Compaq WL215 USB Adapter */ - -#define USB_MELCO_VENDOR_ID 0x0411 -#define USB_BUFFALO_L11_ID 0x0006 /* BUFFALO WLI-USB-L11 */ -#define USB_BUFFALO_L11G_WR_ID 0x000B /* BUFFALO WLI-USB-L11G-WR */ -#define USB_BUFFALO_L11G_ID 0x000D /* BUFFALO WLI-USB-L11G */ - -#define USB_LUCENT_VENDOR_ID 0x047E /* Lucent Technologies */ -#define USB_LUCENT_ORINOCO_ID 0x0300 /* Lucent/Agere Orinoco USB Client */ - -#define USB_AVAYA8_VENDOR_ID 0x0D98 -#define USB_AVAYAE_VENDOR_ID 0x0D9E -#define USB_AVAYA_WIRELESS_ID 0x0300 /* Avaya USB Wireless Card */ - -#define USB_AGERE_VENDOR_ID 0x0D4E /* Agere Systems */ -#define USB_AGERE_MODEL0801_ID 0x1000 /* USB Wireless Card Model 0801 */ -#define USB_AGERE_MODEL0802_ID 0x1001 /* USB Wireless Card Model 0802 */ -#define USB_AGERE_REBRANDED_ID 0x047A /* USB WLAN Card */ - -#define USB_ELSA_VENDOR_ID 0x05CC -#define USB_ELSA_AIRLANCER_ID 0x3100 /* ELSA AirLancer USB-11 */ - -#define USB_LEGEND_VENDOR_ID 0x0E7C -#define USB_LEGEND_JOYNET_ID 0x0300 /* Joynet USB WLAN Card */ - -#define USB_SAMSUNG_VENDOR_ID 0x04E8 -#define USB_SAMSUNG_SEW2001U1_ID 0x5002 /* Samsung SEW-2001u Card */ -#define USB_SAMSUNG_SEW2001U2_ID 0x5B11 /* Samsung SEW-2001u Card */ -#define USB_SAMSUNG_SEW2003U_ID 0x7011 /* Samsung SEW-2003U Card */ - -#define USB_IGATE_VENDOR_ID 0x0681 -#define USB_IGATE_IGATE_11M_ID 0x0012 /* I-GATE 11M USB Card */ - -#define USB_FUJITSU_VENDOR_ID 0x0BF8 -#define USB_FUJITSU_E1100_ID 0x1002 /* connect2AIR WLAN E-1100 USB */ - -#define USB_2WIRE_VENDOR_ID 0x1630 -#define USB_2WIRE_WIRELESS_ID 0xff81 /* 2Wire USB Wireless adapter */ - - -#define EZUSB_REQUEST_FW_TRANS 0xA0 -#define EZUSB_REQUEST_TRIGGER 0xAA -#define EZUSB_REQUEST_TRIG_AC 0xAC -#define EZUSB_CPUCS_REG 0x7F92 - -#define EZUSB_RID_TX 0x0700 -#define EZUSB_RID_RX 0x0701 -#define EZUSB_RID_INIT1 0x0702 -#define EZUSB_RID_ACK 0x0710 -#define EZUSB_RID_READ_PDA 0x0800 -#define EZUSB_RID_PROG_INIT 0x0852 -#define EZUSB_RID_PROG_SET_ADDR 0x0853 -#define EZUSB_RID_PROG_BYTES 0x0854 -#define EZUSB_RID_PROG_END 0x0855 -#define EZUSB_RID_DOCMD 0x0860 - -/* Recognize info frames */ -#define EZUSB_IS_INFO(id) ((id >= 0xF000) && (id <= 0xF2FF)) - -#define EZUSB_MAGIC 0x0210 - -#define EZUSB_FRAME_DATA 1 -#define EZUSB_FRAME_CONTROL 2 - -#define DEF_TIMEOUT (3 * HZ) - -#define BULK_BUF_SIZE 2048 - -#define MAX_DL_SIZE (BULK_BUF_SIZE - sizeof(struct ezusb_packet)) - -#define FW_BUF_SIZE 64 -#define FW_VAR_OFFSET_PTR 0x359 -#define FW_VAR_VALUE 0 -#define FW_HOLE_START 0x100 -#define FW_HOLE_END 0x300 - -struct ezusb_packet { - __le16 magic; /* 0x0210 */ - u8 req_reply_count; - u8 ans_reply_count; - __le16 frame_type; /* 0x01 for data frames, 0x02 otherwise */ - __le16 size; /* transport size */ - __le16 crc; /* CRC up to here */ - __le16 hermes_len; - __le16 hermes_rid; - u8 data[]; -} __packed; - -/* Table of devices that work or may work with this driver */ -static const struct usb_device_id ezusb_table[] = { - {USB_DEVICE(USB_COMPAQ_VENDOR_ID, USB_COMPAQ_WL215_ID)}, - {USB_DEVICE(USB_COMPAQ_VENDOR_ID, USB_HP_WL215_ID)}, - {USB_DEVICE(USB_COMPAQ_VENDOR_ID, USB_COMPAQ_W200_ID)}, - {USB_DEVICE(USB_MELCO_VENDOR_ID, USB_BUFFALO_L11_ID)}, - {USB_DEVICE(USB_MELCO_VENDOR_ID, USB_BUFFALO_L11G_WR_ID)}, - {USB_DEVICE(USB_MELCO_VENDOR_ID, USB_BUFFALO_L11G_ID)}, - {USB_DEVICE(USB_LUCENT_VENDOR_ID, USB_LUCENT_ORINOCO_ID)}, - {USB_DEVICE(USB_AVAYA8_VENDOR_ID, USB_AVAYA_WIRELESS_ID)}, - {USB_DEVICE(USB_AVAYAE_VENDOR_ID, USB_AVAYA_WIRELESS_ID)}, - {USB_DEVICE(USB_AGERE_VENDOR_ID, USB_AGERE_MODEL0801_ID)}, - {USB_DEVICE(USB_AGERE_VENDOR_ID, USB_AGERE_MODEL0802_ID)}, - {USB_DEVICE(USB_ELSA_VENDOR_ID, USB_ELSA_AIRLANCER_ID)}, - {USB_DEVICE(USB_LEGEND_VENDOR_ID, USB_LEGEND_JOYNET_ID)}, - {USB_DEVICE_VER(USB_SAMSUNG_VENDOR_ID, USB_SAMSUNG_SEW2001U1_ID, - 0, 0)}, - {USB_DEVICE(USB_SAMSUNG_VENDOR_ID, USB_SAMSUNG_SEW2001U2_ID)}, - {USB_DEVICE(USB_SAMSUNG_VENDOR_ID, USB_SAMSUNG_SEW2003U_ID)}, - {USB_DEVICE(USB_IGATE_VENDOR_ID, USB_IGATE_IGATE_11M_ID)}, - {USB_DEVICE(USB_FUJITSU_VENDOR_ID, USB_FUJITSU_E1100_ID)}, - {USB_DEVICE(USB_2WIRE_VENDOR_ID, USB_2WIRE_WIRELESS_ID)}, - {USB_DEVICE(USB_AGERE_VENDOR_ID, USB_AGERE_REBRANDED_ID)}, - {} /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, ezusb_table); - -/* Structure to hold all of our device specific stuff */ -struct ezusb_priv { - struct usb_device *udev; - struct net_device *dev; - struct mutex mtx; - spinlock_t req_lock; - struct list_head req_pending; - struct list_head req_active; - spinlock_t reply_count_lock; - u16 hermes_reg_fake[0x40]; - u8 *bap_buf; - struct urb *read_urb; - int read_pipe; - int write_pipe; - u8 reply_count; -}; - -enum ezusb_state { - EZUSB_CTX_START, - EZUSB_CTX_QUEUED, - EZUSB_CTX_REQ_SUBMITTED, - EZUSB_CTX_REQ_COMPLETE, - EZUSB_CTX_RESP_RECEIVED, - EZUSB_CTX_REQ_TIMEOUT, - EZUSB_CTX_REQ_FAILED, - EZUSB_CTX_RESP_TIMEOUT, - EZUSB_CTX_REQSUBMIT_FAIL, - EZUSB_CTX_COMPLETE, -}; - -struct request_context { - struct list_head list; - refcount_t refcount; - struct completion done; /* Signals that CTX is dead */ - int killed; - struct urb *outurb; /* OUT for req pkt */ - struct ezusb_priv *upriv; - struct ezusb_packet *buf; - int buf_length; - struct timer_list timer; /* Timeout handling */ - enum ezusb_state state; /* Current state */ - /* the RID that we will wait for */ - u16 out_rid; - u16 in_rid; -}; - - -/* Forward declarations */ -static void ezusb_ctx_complete(struct request_context *ctx); -static void ezusb_req_queue_run(struct ezusb_priv *upriv); -static void ezusb_bulk_in_callback(struct urb *urb); - -static inline u8 ezusb_reply_inc(u8 count) -{ - if (count < 0x7F) - return count + 1; - else - return 1; -} - -static void ezusb_request_context_put(struct request_context *ctx) -{ - if (!refcount_dec_and_test(&ctx->refcount)) - return; - - WARN_ON(!ctx->done.done); - BUG_ON(ctx->outurb->status == -EINPROGRESS); - BUG_ON(timer_pending(&ctx->timer)); - usb_free_urb(ctx->outurb); - kfree(ctx->buf); - kfree(ctx); -} - -static inline void ezusb_mod_timer(struct ezusb_priv *upriv, - struct timer_list *timer, - unsigned long expire) -{ - if (!upriv->udev) - return; - mod_timer(timer, expire); -} - -static void ezusb_request_timerfn(struct timer_list *t) -{ - struct request_context *ctx = from_timer(ctx, t, timer); - - ctx->outurb->transfer_flags |= URB_ASYNC_UNLINK; - if (usb_unlink_urb(ctx->outurb) == -EINPROGRESS) { - ctx->state = EZUSB_CTX_REQ_TIMEOUT; - } else { - ctx->state = EZUSB_CTX_RESP_TIMEOUT; - dev_dbg(&ctx->outurb->dev->dev, "couldn't unlink\n"); - refcount_inc(&ctx->refcount); - ctx->killed = 1; - ezusb_ctx_complete(ctx); - ezusb_request_context_put(ctx); - } -}; - -static struct request_context *ezusb_alloc_ctx(struct ezusb_priv *upriv, - u16 out_rid, u16 in_rid) -{ - struct request_context *ctx; - - ctx = kzalloc(sizeof(*ctx), GFP_ATOMIC); - if (!ctx) - return NULL; - - ctx->buf = kmalloc(BULK_BUF_SIZE, GFP_ATOMIC); - if (!ctx->buf) { - kfree(ctx); - return NULL; - } - ctx->outurb = usb_alloc_urb(0, GFP_ATOMIC); - if (!ctx->outurb) { - kfree(ctx->buf); - kfree(ctx); - return NULL; - } - - ctx->upriv = upriv; - ctx->state = EZUSB_CTX_START; - ctx->out_rid = out_rid; - ctx->in_rid = in_rid; - - refcount_set(&ctx->refcount, 1); - init_completion(&ctx->done); - - timer_setup(&ctx->timer, ezusb_request_timerfn, 0); - return ctx; -} - -static void ezusb_ctx_complete(struct request_context *ctx) -{ - struct ezusb_priv *upriv = ctx->upriv; - unsigned long flags; - - spin_lock_irqsave(&upriv->req_lock, flags); - - list_del_init(&ctx->list); - if (upriv->udev) { - spin_unlock_irqrestore(&upriv->req_lock, flags); - ezusb_req_queue_run(upriv); - spin_lock_irqsave(&upriv->req_lock, flags); - } - - switch (ctx->state) { - case EZUSB_CTX_COMPLETE: - case EZUSB_CTX_REQSUBMIT_FAIL: - case EZUSB_CTX_REQ_FAILED: - case EZUSB_CTX_REQ_TIMEOUT: - case EZUSB_CTX_RESP_TIMEOUT: - spin_unlock_irqrestore(&upriv->req_lock, flags); - - if ((ctx->out_rid == EZUSB_RID_TX) && upriv->dev) { - struct net_device *dev = upriv->dev; - struct net_device_stats *stats = &dev->stats; - - if (ctx->state != EZUSB_CTX_COMPLETE) - stats->tx_errors++; - else - stats->tx_packets++; - - netif_wake_queue(dev); - } - complete_all(&ctx->done); - ezusb_request_context_put(ctx); - break; - - default: - spin_unlock_irqrestore(&upriv->req_lock, flags); - if (!upriv->udev) { - /* This is normal, as all request contexts get flushed - * when the device is disconnected */ - err("Called, CTX not terminating, but device gone"); - complete_all(&ctx->done); - ezusb_request_context_put(ctx); - break; - } - - err("Called, CTX not in terminating state."); - /* Things are really bad if this happens. Just leak - * the CTX because it may still be linked to the - * queue or the OUT urb may still be active. - * Just leaking at least prevents an Oops or Panic. - */ - break; - } -} - -/* - * ezusb_req_queue_run: - * Description: - * Note: Only one active CTX at any one time, because there's no - * other (reliable) way to match the response URB to the correct - * CTX. - */ -static void ezusb_req_queue_run(struct ezusb_priv *upriv) -{ - unsigned long flags; - struct request_context *ctx; - int result; - - spin_lock_irqsave(&upriv->req_lock, flags); - - if (!list_empty(&upriv->req_active)) - goto unlock; - - if (list_empty(&upriv->req_pending)) - goto unlock; - - ctx = - list_entry(upriv->req_pending.next, struct request_context, - list); - - if (!ctx->upriv->udev) - goto unlock; - - /* We need to split this off to avoid a race condition */ - list_move_tail(&ctx->list, &upriv->req_active); - - if (ctx->state == EZUSB_CTX_QUEUED) { - refcount_inc(&ctx->refcount); - result = usb_submit_urb(ctx->outurb, GFP_ATOMIC); - if (result) { - ctx->state = EZUSB_CTX_REQSUBMIT_FAIL; - - spin_unlock_irqrestore(&upriv->req_lock, flags); - - err("Fatal, failed to submit command urb." - " error=%d\n", result); - - ezusb_ctx_complete(ctx); - ezusb_request_context_put(ctx); - goto done; - } - - ctx->state = EZUSB_CTX_REQ_SUBMITTED; - ezusb_mod_timer(ctx->upriv, &ctx->timer, - jiffies + DEF_TIMEOUT); - } - - unlock: - spin_unlock_irqrestore(&upriv->req_lock, flags); - - done: - return; -} - -static void ezusb_req_enqueue_run(struct ezusb_priv *upriv, - struct request_context *ctx) -{ - unsigned long flags; - - spin_lock_irqsave(&upriv->req_lock, flags); - - if (!ctx->upriv->udev) { - spin_unlock_irqrestore(&upriv->req_lock, flags); - goto done; - } - refcount_inc(&ctx->refcount); - list_add_tail(&ctx->list, &upriv->req_pending); - spin_unlock_irqrestore(&upriv->req_lock, flags); - - ctx->state = EZUSB_CTX_QUEUED; - ezusb_req_queue_run(upriv); - - done: - return; -} - -static void ezusb_request_out_callback(struct urb *urb) -{ - unsigned long flags; - enum ezusb_state state; - struct request_context *ctx = urb->context; - struct ezusb_priv *upriv = ctx->upriv; - - spin_lock_irqsave(&upriv->req_lock, flags); - - del_timer(&ctx->timer); - - if (ctx->killed) { - spin_unlock_irqrestore(&upriv->req_lock, flags); - pr_warn("interrupt called with dead ctx\n"); - goto out; - } - - state = ctx->state; - - if (urb->status == 0) { - switch (state) { - case EZUSB_CTX_REQ_SUBMITTED: - if (ctx->in_rid) { - ctx->state = EZUSB_CTX_REQ_COMPLETE; - /* reply URB still pending */ - ezusb_mod_timer(upriv, &ctx->timer, - jiffies + DEF_TIMEOUT); - spin_unlock_irqrestore(&upriv->req_lock, - flags); - break; - } - fallthrough; - case EZUSB_CTX_RESP_RECEIVED: - /* IN already received before this OUT-ACK */ - ctx->state = EZUSB_CTX_COMPLETE; - spin_unlock_irqrestore(&upriv->req_lock, flags); - ezusb_ctx_complete(ctx); - break; - - default: - spin_unlock_irqrestore(&upriv->req_lock, flags); - err("Unexpected state(0x%x, %d) in OUT URB", - state, urb->status); - break; - } - } else { - /* If someone cancels the OUT URB then its status - * should be either -ECONNRESET or -ENOENT. - */ - switch (state) { - case EZUSB_CTX_REQ_SUBMITTED: - case EZUSB_CTX_RESP_RECEIVED: - ctx->state = EZUSB_CTX_REQ_FAILED; - fallthrough; - - case EZUSB_CTX_REQ_FAILED: - case EZUSB_CTX_REQ_TIMEOUT: - spin_unlock_irqrestore(&upriv->req_lock, flags); - - ezusb_ctx_complete(ctx); - break; - - default: - spin_unlock_irqrestore(&upriv->req_lock, flags); - - err("Unexpected state(0x%x, %d) in OUT URB", - state, urb->status); - break; - } - } - out: - ezusb_request_context_put(ctx); -} - -static void ezusb_request_in_callback(struct ezusb_priv *upriv, - struct urb *urb) -{ - struct ezusb_packet *ans = urb->transfer_buffer; - struct request_context *ctx = NULL; - enum ezusb_state state; - unsigned long flags; - - /* Find the CTX on the active queue that requested this URB */ - spin_lock_irqsave(&upriv->req_lock, flags); - if (upriv->udev) { - struct list_head *item; - - list_for_each(item, &upriv->req_active) { - struct request_context *c; - int reply_count; - - c = list_entry(item, struct request_context, list); - reply_count = - ezusb_reply_inc(c->buf->req_reply_count); - if ((ans->ans_reply_count == reply_count) - && (le16_to_cpu(ans->hermes_rid) == c->in_rid)) { - ctx = c; - break; - } - netdev_dbg(upriv->dev, "Skipped (0x%x/0x%x) (%d/%d)\n", - le16_to_cpu(ans->hermes_rid), c->in_rid, - ans->ans_reply_count, reply_count); - } - } - - if (ctx == NULL) { - spin_unlock_irqrestore(&upriv->req_lock, flags); - err("%s: got unexpected RID: 0x%04X", __func__, - le16_to_cpu(ans->hermes_rid)); - ezusb_req_queue_run(upriv); - return; - } - - /* The data we want is in the in buffer, exchange */ - urb->transfer_buffer = ctx->buf; - ctx->buf = (void *) ans; - ctx->buf_length = urb->actual_length; - - state = ctx->state; - switch (state) { - case EZUSB_CTX_REQ_SUBMITTED: - /* We have received our response URB before - * our request has been acknowledged. Do NOT - * destroy our CTX yet, because our OUT URB - * is still alive ... - */ - ctx->state = EZUSB_CTX_RESP_RECEIVED; - spin_unlock_irqrestore(&upriv->req_lock, flags); - - /* Let the machine continue running. */ - break; - - case EZUSB_CTX_REQ_COMPLETE: - /* This is the usual path: our request - * has already been acknowledged, and - * we have now received the reply. - */ - ctx->state = EZUSB_CTX_COMPLETE; - - /* Stop the intimer */ - del_timer(&ctx->timer); - spin_unlock_irqrestore(&upriv->req_lock, flags); - - /* Call the completion handler */ - ezusb_ctx_complete(ctx); - break; - - default: - spin_unlock_irqrestore(&upriv->req_lock, flags); - - pr_warn("Matched IN URB, unexpected context state(0x%x)\n", - state); - /* Throw this CTX away and try submitting another */ - del_timer(&ctx->timer); - ctx->outurb->transfer_flags |= URB_ASYNC_UNLINK; - usb_unlink_urb(ctx->outurb); - ezusb_req_queue_run(upriv); - break; - } /* switch */ -} - -typedef void (*ezusb_ctx_wait)(struct ezusb_priv *, struct request_context *); - -static void ezusb_req_ctx_wait_compl(struct ezusb_priv *upriv, - struct request_context *ctx) -{ - switch (ctx->state) { - case EZUSB_CTX_QUEUED: - case EZUSB_CTX_REQ_SUBMITTED: - case EZUSB_CTX_REQ_COMPLETE: - case EZUSB_CTX_RESP_RECEIVED: - wait_for_completion(&ctx->done); - break; - default: - /* Done or failed - nothing to wait for */ - break; - } -} - -static void ezusb_req_ctx_wait_poll(struct ezusb_priv *upriv, - struct request_context *ctx) -{ - int msecs; - - switch (ctx->state) { - case EZUSB_CTX_QUEUED: - case EZUSB_CTX_REQ_SUBMITTED: - case EZUSB_CTX_REQ_COMPLETE: - case EZUSB_CTX_RESP_RECEIVED: - /* If we get called from a timer or with our lock acquired, then - * we can't wait for the completion and have to poll. This won't - * happen if the USB controller completes the URB requests in - * BH. - */ - msecs = DEF_TIMEOUT * (1000 / HZ); - - while (!try_wait_for_completion(&ctx->done) && msecs--) - udelay(1000); - break; - default: - /* Done or failed - nothing to wait for */ - break; - } -} - -static void ezusb_req_ctx_wait_skip(struct ezusb_priv *upriv, - struct request_context *ctx) -{ - WARN(1, "Shouldn't be invoked for in_rid\n"); -} - -static inline u16 build_crc(struct ezusb_packet *data) -{ - u16 crc = 0; - u8 *bytes = (u8 *)data; - int i; - - for (i = 0; i < 8; i++) - crc = (crc << 1) + bytes[i]; - - return crc; -} - -/* - * ezusb_fill_req: - * - * if data == NULL and length > 0 the data is assumed to be already in - * the target buffer and only the header is filled. - * - */ -static int ezusb_fill_req(struct ezusb_packet *req, u16 length, u16 rid, - const void *data, u16 frame_type, u8 reply_count) -{ - int total_size = sizeof(*req) + length; - - BUG_ON(total_size > BULK_BUF_SIZE); - - req->magic = cpu_to_le16(EZUSB_MAGIC); - req->req_reply_count = reply_count; - req->ans_reply_count = 0; - req->frame_type = cpu_to_le16(frame_type); - req->size = cpu_to_le16(length + 4); - req->crc = cpu_to_le16(build_crc(req)); - req->hermes_len = cpu_to_le16(HERMES_BYTES_TO_RECLEN(length)); - req->hermes_rid = cpu_to_le16(rid); - if (data) - memcpy(req->data, data, length); - return total_size; -} - -static int ezusb_submit_in_urb(struct ezusb_priv *upriv) -{ - int retval = 0; - void *cur_buf = upriv->read_urb->transfer_buffer; - - if (upriv->read_urb->status == -EINPROGRESS) { - netdev_dbg(upriv->dev, "urb busy, not resubmiting\n"); - retval = -EBUSY; - goto exit; - } - usb_fill_bulk_urb(upriv->read_urb, upriv->udev, upriv->read_pipe, - cur_buf, BULK_BUF_SIZE, - ezusb_bulk_in_callback, upriv); - upriv->read_urb->transfer_flags = 0; - retval = usb_submit_urb(upriv->read_urb, GFP_ATOMIC); - if (retval) - err("%s submit failed %d", __func__, retval); - - exit: - return retval; -} - -static inline int ezusb_8051_cpucs(struct ezusb_priv *upriv, int reset) -{ - int ret; - u8 *res_val = NULL; - - if (!upriv->udev) { - err("%s: !upriv->udev", __func__); - return -EFAULT; - } - - res_val = kmalloc(sizeof(*res_val), GFP_KERNEL); - - if (!res_val) - return -ENOMEM; - - *res_val = reset; /* avoid argument promotion */ - - ret = usb_control_msg(upriv->udev, - usb_sndctrlpipe(upriv->udev, 0), - EZUSB_REQUEST_FW_TRANS, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | - USB_DIR_OUT, EZUSB_CPUCS_REG, 0, res_val, - sizeof(*res_val), DEF_TIMEOUT); - - kfree(res_val); - - return ret; -} - -static int ezusb_firmware_download(struct ezusb_priv *upriv, - struct ez_usb_fw *fw) -{ - u8 *fw_buffer; - int retval, addr; - int variant_offset; - - fw_buffer = kmalloc(FW_BUF_SIZE, GFP_KERNEL); - if (!fw_buffer) { - printk(KERN_ERR PFX "Out of memory for firmware buffer.\n"); - return -ENOMEM; - } - /* - * This byte is 1 and should be replaced with 0. The offset is - * 0x10AD in version 0.0.6. The byte in question should follow - * the end of the code pointed to by the jump in the beginning - * of the firmware. Also, it is read by code located at 0x358. - */ - variant_offset = be16_to_cpup((__be16 *) &fw->code[FW_VAR_OFFSET_PTR]); - if (variant_offset >= fw->size) { - printk(KERN_ERR PFX "Invalid firmware variant offset: " - "0x%04x\n", variant_offset); - retval = -EINVAL; - goto fail; - } - - retval = ezusb_8051_cpucs(upriv, 1); - if (retval < 0) - goto fail; - for (addr = 0; addr < fw->size; addr += FW_BUF_SIZE) { - /* 0x100-0x300 should be left alone, it contains card - * specific data, like USB enumeration information */ - if ((addr >= FW_HOLE_START) && (addr < FW_HOLE_END)) - continue; - - memcpy(fw_buffer, &fw->code[addr], FW_BUF_SIZE); - if (variant_offset >= addr && - variant_offset < addr + FW_BUF_SIZE) { - netdev_dbg(upriv->dev, - "Patching card_variant byte at 0x%04X\n", - variant_offset); - fw_buffer[variant_offset - addr] = FW_VAR_VALUE; - } - retval = usb_control_msg(upriv->udev, - usb_sndctrlpipe(upriv->udev, 0), - EZUSB_REQUEST_FW_TRANS, - USB_TYPE_VENDOR | USB_RECIP_DEVICE - | USB_DIR_OUT, - addr, 0x0, - fw_buffer, FW_BUF_SIZE, - DEF_TIMEOUT); - - if (retval < 0) - goto fail; - } - retval = ezusb_8051_cpucs(upriv, 0); - if (retval < 0) - goto fail; - - goto exit; - fail: - printk(KERN_ERR PFX "Firmware download failed, error %d\n", - retval); - exit: - kfree(fw_buffer); - return retval; -} - -static int ezusb_access_ltv(struct ezusb_priv *upriv, - struct request_context *ctx, - u16 length, const void *data, u16 frame_type, - void *ans_buff, unsigned ans_size, u16 *ans_length, - ezusb_ctx_wait ezusb_ctx_wait_func) -{ - int req_size; - int retval = 0; - enum ezusb_state state; - - if (!upriv->udev) { - retval = -ENODEV; - goto exit; - } - - if (upriv->read_urb->status != -EINPROGRESS) - err("%s: in urb not pending", __func__); - - /* protect upriv->reply_count, guarantee sequential numbers */ - spin_lock_bh(&upriv->reply_count_lock); - req_size = ezusb_fill_req(ctx->buf, length, ctx->out_rid, data, - frame_type, upriv->reply_count); - usb_fill_bulk_urb(ctx->outurb, upriv->udev, upriv->write_pipe, - ctx->buf, req_size, - ezusb_request_out_callback, ctx); - - if (ctx->in_rid) - upriv->reply_count = ezusb_reply_inc(upriv->reply_count); - - ezusb_req_enqueue_run(upriv, ctx); - - spin_unlock_bh(&upriv->reply_count_lock); - - if (ctx->in_rid) - ezusb_ctx_wait_func(upriv, ctx); - - state = ctx->state; - switch (state) { - case EZUSB_CTX_COMPLETE: - retval = ctx->outurb->status; - break; - - case EZUSB_CTX_QUEUED: - case EZUSB_CTX_REQ_SUBMITTED: - if (!ctx->in_rid) - break; - fallthrough; - default: - err("%s: Unexpected context state %d", __func__, - state); - fallthrough; - case EZUSB_CTX_REQ_TIMEOUT: - case EZUSB_CTX_REQ_FAILED: - case EZUSB_CTX_RESP_TIMEOUT: - case EZUSB_CTX_REQSUBMIT_FAIL: - printk(KERN_ERR PFX "Access failed, resetting (state %d," - " reply_count %d)\n", state, upriv->reply_count); - upriv->reply_count = 0; - if (state == EZUSB_CTX_REQ_TIMEOUT - || state == EZUSB_CTX_RESP_TIMEOUT) { - printk(KERN_ERR PFX "ctx timed out\n"); - retval = -ETIMEDOUT; - } else { - printk(KERN_ERR PFX "ctx failed\n"); - retval = -EFAULT; - } - goto exit; - } - if (ctx->in_rid) { - struct ezusb_packet *ans = ctx->buf; - unsigned exp_len; - - if (ans->hermes_len != 0) - exp_len = le16_to_cpu(ans->hermes_len) * 2 + 12; - else - exp_len = 14; - - if (exp_len != ctx->buf_length) { - err("%s: length mismatch for RID 0x%04x: " - "expected %d, got %d", __func__, - ctx->in_rid, exp_len, ctx->buf_length); - retval = -EIO; - goto exit; - } - - if (ans_buff) - memcpy(ans_buff, ans->data, min(exp_len, ans_size)); - if (ans_length) - *ans_length = le16_to_cpu(ans->hermes_len); - } - exit: - ezusb_request_context_put(ctx); - return retval; -} - -static int __ezusb_write_ltv(struct hermes *hw, int bap, u16 rid, - u16 length, const void *data, - ezusb_ctx_wait ezusb_ctx_wait_func) -{ - struct ezusb_priv *upriv = hw->priv; - u16 frame_type; - struct request_context *ctx; - - if (length == 0) - return -EINVAL; - - length = HERMES_RECLEN_TO_BYTES(length); - - /* On memory mapped devices HERMES_RID_CNFGROUPADDRESSES can be - * set to be empty, but the USB bridge doesn't like it */ - if (length == 0) - return 0; - - ctx = ezusb_alloc_ctx(upriv, rid, EZUSB_RID_ACK); - if (!ctx) - return -ENOMEM; - - if (rid == EZUSB_RID_TX) - frame_type = EZUSB_FRAME_DATA; - else - frame_type = EZUSB_FRAME_CONTROL; - - return ezusb_access_ltv(upriv, ctx, length, data, frame_type, - NULL, 0, NULL, ezusb_ctx_wait_func); -} - -static int ezusb_write_ltv(struct hermes *hw, int bap, u16 rid, - u16 length, const void *data) -{ - return __ezusb_write_ltv(hw, bap, rid, length, data, - ezusb_req_ctx_wait_poll); -} - -static int __ezusb_read_ltv(struct hermes *hw, int bap, u16 rid, - unsigned bufsize, u16 *length, void *buf, - ezusb_ctx_wait ezusb_ctx_wait_func) - -{ - struct ezusb_priv *upriv = hw->priv; - struct request_context *ctx; - - if (bufsize % 2) - return -EINVAL; - - ctx = ezusb_alloc_ctx(upriv, rid, rid); - if (!ctx) - return -ENOMEM; - - return ezusb_access_ltv(upriv, ctx, 0, NULL, EZUSB_FRAME_CONTROL, - buf, bufsize, length, ezusb_req_ctx_wait_poll); -} - -static int ezusb_read_ltv(struct hermes *hw, int bap, u16 rid, - unsigned bufsize, u16 *length, void *buf) -{ - return __ezusb_read_ltv(hw, bap, rid, bufsize, length, buf, - ezusb_req_ctx_wait_poll); -} - -static int ezusb_read_ltv_preempt(struct hermes *hw, int bap, u16 rid, - unsigned bufsize, u16 *length, void *buf) -{ - return __ezusb_read_ltv(hw, bap, rid, bufsize, length, buf, - ezusb_req_ctx_wait_compl); -} - -static int ezusb_doicmd_wait(struct hermes *hw, u16 cmd, u16 parm0, u16 parm1, - u16 parm2, struct hermes_response *resp) -{ - WARN_ON_ONCE(1); - return -EINVAL; -} - -static int __ezusb_docmd_wait(struct hermes *hw, u16 cmd, u16 parm0, - struct hermes_response *resp, - ezusb_ctx_wait ezusb_ctx_wait_func) -{ - struct ezusb_priv *upriv = hw->priv; - struct request_context *ctx; - - __le16 data[4] = { - cpu_to_le16(cmd), - cpu_to_le16(parm0), - 0, - 0, - }; - netdev_dbg(upriv->dev, "0x%04X, parm0 0x%04X\n", cmd, parm0); - ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_DOCMD, EZUSB_RID_ACK); - if (!ctx) - return -ENOMEM; - - return ezusb_access_ltv(upriv, ctx, sizeof(data), &data, - EZUSB_FRAME_CONTROL, NULL, 0, NULL, - ezusb_ctx_wait_func); -} - -static int ezusb_docmd_wait(struct hermes *hw, u16 cmd, u16 parm0, - struct hermes_response *resp) -{ - return __ezusb_docmd_wait(hw, cmd, parm0, resp, ezusb_req_ctx_wait_poll); -} - -static int ezusb_bap_pread(struct hermes *hw, int bap, - void *buf, int len, u16 id, u16 offset) -{ - struct ezusb_priv *upriv = hw->priv; - struct ezusb_packet *ans = (void *) upriv->read_urb->transfer_buffer; - int actual_length = upriv->read_urb->actual_length; - - if (id == EZUSB_RID_RX) { - if ((sizeof(*ans) + offset + len) > actual_length) { - printk(KERN_ERR PFX "BAP read beyond buffer end " - "in rx frame\n"); - return -EINVAL; - } - memcpy(buf, ans->data + offset, len); - return 0; - } - - if (EZUSB_IS_INFO(id)) { - /* Include 4 bytes for length/type */ - if ((sizeof(*ans) + offset + len - 4) > actual_length) { - printk(KERN_ERR PFX "BAP read beyond buffer end " - "in info frame\n"); - return -EFAULT; - } - memcpy(buf, ans->data + offset - 4, len); - } else { - printk(KERN_ERR PFX "Unexpected fid 0x%04x\n", id); - return -EINVAL; - } - - return 0; -} - -static int ezusb_read_pda(struct hermes *hw, __le16 *pda, - u32 pda_addr, u16 pda_len) -{ - struct ezusb_priv *upriv = hw->priv; - struct request_context *ctx; - __le16 data[] = { - cpu_to_le16(pda_addr & 0xffff), - cpu_to_le16(pda_len - 4) - }; - ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_READ_PDA, EZUSB_RID_READ_PDA); - if (!ctx) - return -ENOMEM; - - /* wl_lkm does not include PDA size in the PDA area. - * We will pad the information into pda, so other routines - * don't have to be modified */ - pda[0] = cpu_to_le16(pda_len - 2); - /* Includes CFG_PROD_DATA but not itself */ - pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */ - - return ezusb_access_ltv(upriv, ctx, sizeof(data), &data, - EZUSB_FRAME_CONTROL, &pda[2], pda_len - 4, - NULL, ezusb_req_ctx_wait_compl); -} - -static int ezusb_program_init(struct hermes *hw, u32 entry_point) -{ - struct ezusb_priv *upriv = hw->priv; - struct request_context *ctx; - __le32 data = cpu_to_le32(entry_point); - - ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_INIT, EZUSB_RID_ACK); - if (!ctx) - return -ENOMEM; - - return ezusb_access_ltv(upriv, ctx, sizeof(data), &data, - EZUSB_FRAME_CONTROL, NULL, 0, NULL, - ezusb_req_ctx_wait_compl); -} - -static int ezusb_program_end(struct hermes *hw) -{ - struct ezusb_priv *upriv = hw->priv; - struct request_context *ctx; - - ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_END, EZUSB_RID_ACK); - if (!ctx) - return -ENOMEM; - - return ezusb_access_ltv(upriv, ctx, 0, NULL, - EZUSB_FRAME_CONTROL, NULL, 0, NULL, - ezusb_req_ctx_wait_compl); -} - -static int ezusb_program_bytes(struct hermes *hw, const char *buf, - u32 addr, u32 len) -{ - struct ezusb_priv *upriv = hw->priv; - struct request_context *ctx; - __le32 data = cpu_to_le32(addr); - int err; - - ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_SET_ADDR, EZUSB_RID_ACK); - if (!ctx) - return -ENOMEM; - - err = ezusb_access_ltv(upriv, ctx, sizeof(data), &data, - EZUSB_FRAME_CONTROL, NULL, 0, NULL, - ezusb_req_ctx_wait_compl); - if (err) - return err; - - ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_BYTES, EZUSB_RID_ACK); - if (!ctx) - return -ENOMEM; - - return ezusb_access_ltv(upriv, ctx, len, buf, - EZUSB_FRAME_CONTROL, NULL, 0, NULL, - ezusb_req_ctx_wait_compl); -} - -static int ezusb_program(struct hermes *hw, const char *buf, - u32 addr, u32 len) -{ - u32 ch_addr; - u32 ch_len; - int err = 0; - - /* We can only send 2048 bytes out of the bulk xmit at a time, - * so we have to split any programming into chunks of <2048 - * bytes. */ - - ch_len = (len < MAX_DL_SIZE) ? len : MAX_DL_SIZE; - ch_addr = addr; - - while (ch_addr < (addr + len)) { - pr_debug("Programming subblock of length %d " - "to address 0x%08x. Data @ %p\n", - ch_len, ch_addr, &buf[ch_addr - addr]); - - err = ezusb_program_bytes(hw, &buf[ch_addr - addr], - ch_addr, ch_len); - if (err) - break; - - ch_addr += ch_len; - ch_len = ((addr + len - ch_addr) < MAX_DL_SIZE) ? - (addr + len - ch_addr) : MAX_DL_SIZE; - } - - return err; -} - -static netdev_tx_t ezusb_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct orinoco_private *priv = ndev_priv(dev); - struct net_device_stats *stats = &dev->stats; - struct ezusb_priv *upriv = priv->card; - u8 mic[MICHAEL_MIC_LEN + 1]; - int err = 0; - int tx_control; - unsigned long flags; - struct request_context *ctx; - u8 *buf; - int tx_size; - - if (!netif_running(dev)) { - printk(KERN_ERR "%s: Tx on stopped device!\n", - dev->name); - return NETDEV_TX_BUSY; - } - - if (netif_queue_stopped(dev)) { - printk(KERN_DEBUG "%s: Tx while transmitter busy!\n", - dev->name); - return NETDEV_TX_BUSY; - } - - if (orinoco_lock(priv, &flags) != 0) { - printk(KERN_ERR - "%s: ezusb_xmit() called while hw_unavailable\n", - dev->name); - return NETDEV_TX_BUSY; - } - - if (!netif_carrier_ok(dev) || - (priv->iw_mode == NL80211_IFTYPE_MONITOR)) { - /* Oops, the firmware hasn't established a connection, - silently drop the packet (this seems to be the - safest approach). */ - goto drop; - } - - /* Check packet length */ - if (skb->len < ETH_HLEN) - goto drop; - - tx_control = 0; - - err = orinoco_process_xmit_skb(skb, dev, priv, &tx_control, - &mic[0]); - if (err) - goto drop; - - ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_TX, 0); - if (!ctx) - goto drop; - - memset(ctx->buf, 0, BULK_BUF_SIZE); - buf = ctx->buf->data; - - { - __le16 *tx_cntl = (__le16 *)buf; - *tx_cntl = cpu_to_le16(tx_control); - buf += sizeof(*tx_cntl); - } - - memcpy(buf, skb->data, skb->len); - buf += skb->len; - - if (tx_control & HERMES_TXCTRL_MIC) { - u8 *m = mic; - /* Mic has been offset so it can be copied to an even - * address. We're copying eveything anyway, so we - * don't need to copy that first byte. */ - if (skb->len % 2) - m++; - memcpy(buf, m, MICHAEL_MIC_LEN); - buf += MICHAEL_MIC_LEN; - } - - /* Finally, we actually initiate the send */ - netif_stop_queue(dev); - - /* The card may behave better if we send evenly sized usb transfers */ - tx_size = ALIGN(buf - ctx->buf->data, 2); - - err = ezusb_access_ltv(upriv, ctx, tx_size, NULL, - EZUSB_FRAME_DATA, NULL, 0, NULL, - ezusb_req_ctx_wait_skip); - - if (err) { - netif_start_queue(dev); - if (net_ratelimit()) - printk(KERN_ERR "%s: Error %d transmitting packet\n", - dev->name, err); - goto busy; - } - - netif_trans_update(dev); - stats->tx_bytes += skb->len; - goto ok; - - drop: - stats->tx_errors++; - stats->tx_dropped++; - - ok: - orinoco_unlock(priv, &flags); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - - busy: - orinoco_unlock(priv, &flags); - return NETDEV_TX_BUSY; -} - -static int ezusb_allocate(struct hermes *hw, u16 size, u16 *fid) -{ - *fid = EZUSB_RID_TX; - return 0; -} - - -static int ezusb_hard_reset(struct orinoco_private *priv) -{ - struct ezusb_priv *upriv = priv->card; - int retval = ezusb_8051_cpucs(upriv, 1); - - if (retval < 0) { - err("Failed to reset"); - return retval; - } - - retval = ezusb_8051_cpucs(upriv, 0); - if (retval < 0) { - err("Failed to unreset"); - return retval; - } - - netdev_dbg(upriv->dev, "sending control message\n"); - retval = usb_control_msg(upriv->udev, - usb_sndctrlpipe(upriv->udev, 0), - EZUSB_REQUEST_TRIGGER, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | - USB_DIR_OUT, 0x0, 0x0, NULL, 0, - DEF_TIMEOUT); - if (retval < 0) { - err("EZUSB_REQUEST_TRIGGER failed retval %d", retval); - return retval; - } -#if 0 - dbg("Sending EZUSB_REQUEST_TRIG_AC"); - retval = usb_control_msg(upriv->udev, - usb_sndctrlpipe(upriv->udev, 0), - EZUSB_REQUEST_TRIG_AC, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | - USB_DIR_OUT, 0x00FA, 0x0, NULL, 0, - DEF_TIMEOUT); - if (retval < 0) { - err("EZUSB_REQUEST_TRIG_AC failed retval %d", retval); - return retval; - } -#endif - - return 0; -} - - -static int ezusb_init(struct hermes *hw) -{ - struct ezusb_priv *upriv = hw->priv; - int retval; - - if (!upriv) - return -EINVAL; - - upriv->reply_count = 0; - /* Write the MAGIC number on the simulated registers to keep - * orinoco.c happy */ - hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC); - hermes_write_regn(hw, RXFID, EZUSB_RID_RX); - - usb_kill_urb(upriv->read_urb); - ezusb_submit_in_urb(upriv); - - retval = __ezusb_write_ltv(hw, 0, EZUSB_RID_INIT1, - HERMES_BYTES_TO_RECLEN(2), "\x10\x00", - ezusb_req_ctx_wait_compl); - if (retval < 0) { - printk(KERN_ERR PFX "EZUSB_RID_INIT1 error %d\n", retval); - return retval; - } - - retval = __ezusb_docmd_wait(hw, HERMES_CMD_INIT, 0, NULL, - ezusb_req_ctx_wait_compl); - if (retval < 0) { - printk(KERN_ERR PFX "HERMES_CMD_INIT error %d\n", retval); - return retval; - } - - return 0; -} - -static void ezusb_bulk_in_callback(struct urb *urb) -{ - struct ezusb_priv *upriv = (struct ezusb_priv *) urb->context; - struct ezusb_packet *ans = urb->transfer_buffer; - u16 crc; - u16 hermes_rid; - - if (upriv->udev == NULL) - return; - - if (urb->status == -ETIMEDOUT) { - /* When a device gets unplugged we get this every time - * we resubmit, flooding the logs. Since we don't use - * USB timeouts, it shouldn't happen any other time*/ - pr_warn("%s: urb timed out, not resubmitting\n", __func__); - return; - } - if (urb->status == -ECONNABORTED) { - pr_warn("%s: connection abort, resubmitting urb\n", - __func__); - goto resubmit; - } - if ((urb->status == -EILSEQ) - || (urb->status == -ENOENT) - || (urb->status == -ECONNRESET)) { - netdev_dbg(upriv->dev, "status %d, not resubmiting\n", - urb->status); - return; - } - if (urb->status) - netdev_dbg(upriv->dev, "status: %d length: %d\n", - urb->status, urb->actual_length); - if (urb->actual_length < sizeof(*ans)) { - err("%s: short read, ignoring", __func__); - goto resubmit; - } - crc = build_crc(ans); - if (le16_to_cpu(ans->crc) != crc) { - err("CRC error, ignoring packet"); - goto resubmit; - } - - hermes_rid = le16_to_cpu(ans->hermes_rid); - if ((hermes_rid != EZUSB_RID_RX) && !EZUSB_IS_INFO(hermes_rid)) { - ezusb_request_in_callback(upriv, urb); - } else if (upriv->dev) { - struct net_device *dev = upriv->dev; - struct orinoco_private *priv = ndev_priv(dev); - struct hermes *hw = &priv->hw; - - if (hermes_rid == EZUSB_RID_RX) { - __orinoco_ev_rx(dev, hw); - } else { - hermes_write_regn(hw, INFOFID, - le16_to_cpu(ans->hermes_rid)); - __orinoco_ev_info(dev, hw); - } - } - - resubmit: - if (upriv->udev) - ezusb_submit_in_urb(upriv); -} - -static inline void ezusb_delete(struct ezusb_priv *upriv) -{ - struct list_head *item; - struct list_head *tmp_item; - unsigned long flags; - - BUG_ON(!upriv); - - mutex_lock(&upriv->mtx); - - upriv->udev = NULL; /* No timer will be rearmed from here */ - - usb_kill_urb(upriv->read_urb); - - spin_lock_irqsave(&upriv->req_lock, flags); - list_for_each_safe(item, tmp_item, &upriv->req_active) { - struct request_context *ctx; - int err; - - ctx = list_entry(item, struct request_context, list); - refcount_inc(&ctx->refcount); - - ctx->outurb->transfer_flags |= URB_ASYNC_UNLINK; - err = usb_unlink_urb(ctx->outurb); - - spin_unlock_irqrestore(&upriv->req_lock, flags); - if (err == -EINPROGRESS) - wait_for_completion(&ctx->done); - - del_timer_sync(&ctx->timer); - /* FIXME: there is an slight chance for the irq handler to - * be running */ - if (!list_empty(&ctx->list)) - ezusb_ctx_complete(ctx); - - ezusb_request_context_put(ctx); - spin_lock_irqsave(&upriv->req_lock, flags); - } - spin_unlock_irqrestore(&upriv->req_lock, flags); - - list_for_each_safe(item, tmp_item, &upriv->req_pending) - ezusb_ctx_complete(list_entry(item, - struct request_context, list)); - - if (upriv->read_urb && upriv->read_urb->status == -EINPROGRESS) - printk(KERN_ERR PFX "Some URB in progress\n"); - - mutex_unlock(&upriv->mtx); - - if (upriv->read_urb) { - kfree(upriv->read_urb->transfer_buffer); - usb_free_urb(upriv->read_urb); - } - kfree(upriv->bap_buf); - if (upriv->dev) { - struct orinoco_private *priv = ndev_priv(upriv->dev); - orinoco_if_del(priv); - wiphy_unregister(priv_to_wiphy(upriv)); - free_orinocodev(priv); - } -} - -static void ezusb_lock_irqsave(spinlock_t *lock, - unsigned long *flags) __acquires(lock) -{ - spin_lock_bh(lock); -} - -static void ezusb_unlock_irqrestore(spinlock_t *lock, - unsigned long *flags) __releases(lock) -{ - spin_unlock_bh(lock); -} - -static void ezusb_lock_irq(spinlock_t *lock) __acquires(lock) -{ - spin_lock_bh(lock); -} - -static void ezusb_unlock_irq(spinlock_t *lock) __releases(lock) -{ - spin_unlock_bh(lock); -} - -static const struct hermes_ops ezusb_ops = { - .init = ezusb_init, - .cmd_wait = ezusb_docmd_wait, - .init_cmd_wait = ezusb_doicmd_wait, - .allocate = ezusb_allocate, - .read_ltv = ezusb_read_ltv, - .read_ltv_pr = ezusb_read_ltv_preempt, - .write_ltv = ezusb_write_ltv, - .bap_pread = ezusb_bap_pread, - .read_pda = ezusb_read_pda, - .program_init = ezusb_program_init, - .program_end = ezusb_program_end, - .program = ezusb_program, - .lock_irqsave = ezusb_lock_irqsave, - .unlock_irqrestore = ezusb_unlock_irqrestore, - .lock_irq = ezusb_lock_irq, - .unlock_irq = ezusb_unlock_irq, -}; - -static const struct net_device_ops ezusb_netdev_ops = { - .ndo_open = orinoco_open, - .ndo_stop = orinoco_stop, - .ndo_start_xmit = ezusb_xmit, - .ndo_set_rx_mode = orinoco_set_multicast_list, - .ndo_change_mtu = orinoco_change_mtu, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, - .ndo_tx_timeout = orinoco_tx_timeout, -}; - -static int ezusb_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(interface); - struct orinoco_private *priv; - struct hermes *hw; - struct ezusb_priv *upriv = NULL; - struct usb_interface_descriptor *iface_desc; - struct usb_endpoint_descriptor *ep; - const struct firmware *fw_entry = NULL; - int retval = 0; - int i; - - priv = alloc_orinocodev(sizeof(*upriv), &udev->dev, - ezusb_hard_reset, NULL); - if (!priv) { - err("Couldn't allocate orinocodev"); - retval = -ENOMEM; - goto exit; - } - - hw = &priv->hw; - - upriv = priv->card; - - mutex_init(&upriv->mtx); - spin_lock_init(&upriv->reply_count_lock); - - spin_lock_init(&upriv->req_lock); - INIT_LIST_HEAD(&upriv->req_pending); - INIT_LIST_HEAD(&upriv->req_active); - - upriv->udev = udev; - - hw->iobase = (void __force __iomem *) &upriv->hermes_reg_fake; - hw->reg_spacing = HERMES_16BIT_REGSPACING; - hw->priv = upriv; - hw->ops = &ezusb_ops; - - /* set up the endpoint information */ - /* check out the endpoints */ - - iface_desc = &interface->cur_altsetting->desc; - for (i = 0; i < iface_desc->bNumEndpoints; ++i) { - ep = &interface->cur_altsetting->endpoint[i].desc; - - if (usb_endpoint_is_bulk_in(ep)) { - /* we found a bulk in endpoint */ - if (upriv->read_urb != NULL) { - pr_warn("Found a second bulk in ep, ignored\n"); - continue; - } - - upriv->read_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!upriv->read_urb) - goto error; - if (le16_to_cpu(ep->wMaxPacketSize) != 64) - pr_warn("bulk in: wMaxPacketSize!= 64\n"); - if (ep->bEndpointAddress != (2 | USB_DIR_IN)) - pr_warn("bulk in: bEndpointAddress: %d\n", - ep->bEndpointAddress); - upriv->read_pipe = usb_rcvbulkpipe(udev, - ep-> - bEndpointAddress); - upriv->read_urb->transfer_buffer = - kmalloc(BULK_BUF_SIZE, GFP_KERNEL); - if (!upriv->read_urb->transfer_buffer) { - err("Couldn't allocate IN buffer"); - goto error; - } - } - - if (usb_endpoint_is_bulk_out(ep)) { - /* we found a bulk out endpoint */ - if (upriv->bap_buf != NULL) { - pr_warn("Found a second bulk out ep, ignored\n"); - continue; - } - - if (le16_to_cpu(ep->wMaxPacketSize) != 64) - pr_warn("bulk out: wMaxPacketSize != 64\n"); - if (ep->bEndpointAddress != 2) - pr_warn("bulk out: bEndpointAddress: %d\n", - ep->bEndpointAddress); - upriv->write_pipe = usb_sndbulkpipe(udev, - ep-> - bEndpointAddress); - upriv->bap_buf = kmalloc(BULK_BUF_SIZE, GFP_KERNEL); - if (!upriv->bap_buf) { - err("Couldn't allocate bulk_out_buffer"); - goto error; - } - } - } - if (!upriv->bap_buf || !upriv->read_urb) { - err("Didn't find the required bulk endpoints"); - goto error; - } - - if (request_firmware(&fw_entry, "orinoco_ezusb_fw", - &interface->dev) == 0) { - firmware.size = fw_entry->size; - firmware.code = fw_entry->data; - } - if (firmware.size && firmware.code) { - if (ezusb_firmware_download(upriv, &firmware) < 0) - goto error; - } else { - err("No firmware to download"); - goto error; - } - - if (ezusb_hard_reset(priv) < 0) { - err("Cannot reset the device"); - goto error; - } - - /* If the firmware is already downloaded orinoco.c will call - * ezusb_init but if the firmware is not already there, that will make - * the kernel very unstable, so we try initializing here and quit in - * case of error */ - if (ezusb_init(hw) < 0) { - err("Couldn't initialize the device"); - err("Firmware may not be downloaded or may be wrong."); - goto error; - } - - /* Initialise the main driver */ - if (orinoco_init(priv) != 0) { - err("orinoco_init() failed\n"); - goto error; - } - - if (orinoco_if_add(priv, 0, 0, &ezusb_netdev_ops) != 0) { - upriv->dev = NULL; - err("%s: orinoco_if_add() failed", __func__); - wiphy_unregister(priv_to_wiphy(priv)); - goto error; - } - upriv->dev = priv->ndev; - - goto exit; - - error: - ezusb_delete(upriv); - if (upriv->dev) { - /* upriv->dev was 0, so ezusb_delete() didn't free it */ - free_orinocodev(priv); - } - upriv = NULL; - retval = -EFAULT; - exit: - if (fw_entry) { - firmware.code = NULL; - firmware.size = 0; - release_firmware(fw_entry); - } - usb_set_intfdata(interface, upriv); - return retval; -} - - -static void ezusb_disconnect(struct usb_interface *intf) -{ - struct ezusb_priv *upriv = usb_get_intfdata(intf); - usb_set_intfdata(intf, NULL); - ezusb_delete(upriv); - printk(KERN_INFO PFX "Disconnected\n"); -} - - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver orinoco_driver = { - .name = DRIVER_NAME, - .probe = ezusb_probe, - .disconnect = ezusb_disconnect, - .id_table = ezusb_table, - .disable_hub_initiated_lpm = 1, -}; - -module_usb_driver(orinoco_driver); - -MODULE_AUTHOR("Manuel Estrada Sainz"); -MODULE_DESCRIPTION("Driver for Orinoco wireless LAN cards using EZUSB bridge"); -MODULE_LICENSE("Dual MPL/GPL"); diff --git a/drivers/net/wireless/intersil/orinoco/scan.c b/drivers/net/wireless/intersil/orinoco/scan.c deleted file mode 100644 index 6d1d084854fb3..0000000000000 --- a/drivers/net/wireless/intersil/orinoco/scan.c +++ /dev/null @@ -1,259 +0,0 @@ -/* Helpers for managing scan queues - * - * See copyright notice in main.c - */ - -#include -#include -#include -#include -#include - -#include "hermes.h" -#include "orinoco.h" -#include "main.h" - -#include "scan.h" - -#define ZERO_DBM_OFFSET 0x95 -#define MAX_SIGNAL_LEVEL 0x8A -#define MIN_SIGNAL_LEVEL 0x2F - -#define SIGNAL_TO_DBM(x) \ - (clamp_t(s32, (x), MIN_SIGNAL_LEVEL, MAX_SIGNAL_LEVEL) \ - - ZERO_DBM_OFFSET) -#define SIGNAL_TO_MBM(x) (SIGNAL_TO_DBM(x) * 100) - -static int symbol_build_supp_rates(u8 *buf, const __le16 *rates) -{ - int i; - u8 rate; - - buf[0] = WLAN_EID_SUPP_RATES; - for (i = 0; i < 5; i++) { - rate = le16_to_cpu(rates[i]); - /* NULL terminated */ - if (rate == 0x0) - break; - buf[i + 2] = rate; - } - buf[1] = i; - - return i + 2; -} - -static int prism_build_supp_rates(u8 *buf, const u8 *rates) -{ - int i; - - buf[0] = WLAN_EID_SUPP_RATES; - for (i = 0; i < 8; i++) { - /* NULL terminated */ - if (rates[i] == 0x0) - break; - buf[i + 2] = rates[i]; - } - buf[1] = i; - - /* We might still have another 2 rates, which need to go in - * extended supported rates */ - if (i == 8 && rates[i] > 0) { - buf[10] = WLAN_EID_EXT_SUPP_RATES; - for (; i < 10; i++) { - /* NULL terminated */ - if (rates[i] == 0x0) - break; - buf[i + 2] = rates[i]; - } - buf[11] = i - 8; - } - - return (i < 8) ? i + 2 : i + 4; -} - -static void orinoco_add_hostscan_result(struct orinoco_private *priv, - const union hermes_scan_info *bss) -{ - struct wiphy *wiphy = priv_to_wiphy(priv); - struct ieee80211_channel *channel; - struct cfg80211_bss *cbss; - u8 *ie; - u8 ie_buf[46]; - u64 timestamp; - s32 signal; - u16 capability; - u16 beacon_interval; - int ie_len; - int freq; - int len; - - len = le16_to_cpu(bss->a.essid_len); - - /* Reconstruct SSID and bitrate IEs to pass up */ - ie_buf[0] = WLAN_EID_SSID; - ie_buf[1] = len; - memcpy(&ie_buf[2], bss->a.essid, len); - - ie = ie_buf + len + 2; - ie_len = ie_buf[1] + 2; - switch (priv->firmware_type) { - case FIRMWARE_TYPE_SYMBOL: - ie_len += symbol_build_supp_rates(ie, bss->s.rates); - break; - - case FIRMWARE_TYPE_INTERSIL: - ie_len += prism_build_supp_rates(ie, bss->p.rates); - break; - - case FIRMWARE_TYPE_AGERE: - default: - break; - } - - freq = ieee80211_channel_to_frequency( - le16_to_cpu(bss->a.channel), NL80211_BAND_2GHZ); - channel = ieee80211_get_channel(wiphy, freq); - if (!channel) { - printk(KERN_DEBUG "Invalid channel designation %04X(%04X)", - bss->a.channel, freq); - return; /* Then ignore it for now */ - } - timestamp = 0; - capability = le16_to_cpu(bss->a.capabilities); - beacon_interval = le16_to_cpu(bss->a.beacon_interv); - signal = SIGNAL_TO_MBM(le16_to_cpu(bss->a.level)); - - cbss = cfg80211_inform_bss(wiphy, channel, CFG80211_BSS_FTYPE_UNKNOWN, - bss->a.bssid, timestamp, capability, - beacon_interval, ie_buf, ie_len, signal, - GFP_KERNEL); - cfg80211_put_bss(wiphy, cbss); -} - -void orinoco_add_extscan_result(struct orinoco_private *priv, - struct agere_ext_scan_info *bss, - size_t len) -{ - struct wiphy *wiphy = priv_to_wiphy(priv); - struct ieee80211_channel *channel; - struct cfg80211_bss *cbss; - const u8 *ie; - u64 timestamp; - s32 signal; - u16 capability; - u16 beacon_interval; - size_t ie_len; - int chan, freq; - - ie_len = len - sizeof(*bss); - ie = cfg80211_find_ie(WLAN_EID_DS_PARAMS, bss->data, ie_len); - chan = ie ? ie[2] : 0; - freq = ieee80211_channel_to_frequency(chan, NL80211_BAND_2GHZ); - channel = ieee80211_get_channel(wiphy, freq); - - timestamp = le64_to_cpu(bss->timestamp); - capability = le16_to_cpu(bss->capabilities); - beacon_interval = le16_to_cpu(bss->beacon_interval); - ie = bss->data; - signal = SIGNAL_TO_MBM(bss->level); - - cbss = cfg80211_inform_bss(wiphy, channel, CFG80211_BSS_FTYPE_UNKNOWN, - bss->bssid, timestamp, capability, - beacon_interval, ie, ie_len, signal, - GFP_KERNEL); - cfg80211_put_bss(wiphy, cbss); -} - -void orinoco_add_hostscan_results(struct orinoco_private *priv, - unsigned char *buf, - size_t len) -{ - int offset; /* In the scan data */ - size_t atom_len; - bool abort = false; - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: - atom_len = sizeof(struct agere_scan_apinfo); - offset = 0; - break; - - case FIRMWARE_TYPE_SYMBOL: - /* Lack of documentation necessitates this hack. - * Different firmwares have 68 or 76 byte long atoms. - * We try modulo first. If the length divides by both, - * we check what would be the channel in the second - * frame for a 68-byte atom. 76-byte atoms have 0 there. - * Valid channel cannot be 0. */ - if (len % 76) - atom_len = 68; - else if (len % 68) - atom_len = 76; - else if (len >= 1292 && buf[68] == 0) - atom_len = 76; - else - atom_len = 68; - offset = 0; - break; - - case FIRMWARE_TYPE_INTERSIL: - offset = 4; - if (priv->has_hostscan) { - atom_len = le16_to_cpup((__le16 *)buf); - /* Sanity check for atom_len */ - if (atom_len < sizeof(struct prism2_scan_apinfo)) { - printk(KERN_ERR "%s: Invalid atom_len in scan " - "data: %zu\n", priv->ndev->name, - atom_len); - abort = true; - goto scan_abort; - } - } else - atom_len = offsetof(struct prism2_scan_apinfo, atim); - break; - - default: - abort = true; - goto scan_abort; - } - - /* Check that we got an whole number of atoms */ - if ((len - offset) % atom_len) { - printk(KERN_ERR "%s: Unexpected scan data length %zu, " - "atom_len %zu, offset %d\n", priv->ndev->name, len, - atom_len, offset); - abort = true; - goto scan_abort; - } - - /* Process the entries one by one */ - for (; offset + atom_len <= len; offset += atom_len) { - union hermes_scan_info *atom; - - atom = (union hermes_scan_info *) (buf + offset); - - orinoco_add_hostscan_result(priv, atom); - } - - scan_abort: - if (priv->scan_request) { - struct cfg80211_scan_info info = { - .aborted = abort, - }; - - cfg80211_scan_done(priv->scan_request, &info); - priv->scan_request = NULL; - } -} - -void orinoco_scan_done(struct orinoco_private *priv, bool abort) -{ - if (priv->scan_request) { - struct cfg80211_scan_info info = { - .aborted = abort, - }; - - cfg80211_scan_done(priv->scan_request, &info); - priv->scan_request = NULL; - } -} diff --git a/drivers/net/wireless/intersil/orinoco/scan.h b/drivers/net/wireless/intersil/orinoco/scan.h deleted file mode 100644 index 27281fb0a6dc0..0000000000000 --- a/drivers/net/wireless/intersil/orinoco/scan.h +++ /dev/null @@ -1,21 +0,0 @@ -/* Helpers for managing scan queues - * - * See copyright notice in main.c - */ -#ifndef _ORINOCO_SCAN_H_ -#define _ORINOCO_SCAN_H_ - -/* Forward declarations */ -struct orinoco_private; -struct agere_ext_scan_info; - -/* Add scan results */ -void orinoco_add_extscan_result(struct orinoco_private *priv, - struct agere_ext_scan_info *atom, - size_t len); -void orinoco_add_hostscan_results(struct orinoco_private *dev, - unsigned char *buf, - size_t len); -void orinoco_scan_done(struct orinoco_private *priv, bool abort); - -#endif /* _ORINOCO_SCAN_H_ */ diff --git a/drivers/net/wireless/intersil/orinoco/spectrum_cs.c b/drivers/net/wireless/intersil/orinoco/spectrum_cs.c deleted file mode 100644 index 841d623c621ac..0000000000000 --- a/drivers/net/wireless/intersil/orinoco/spectrum_cs.c +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Driver for 802.11b cards using RAM-loadable Symbol firmware, such as - * Symbol Wireless Networker LA4137, CompactFlash cards by Socket - * Communications and Intel PRO/Wireless 2011B. - * - * The driver implements Symbol firmware download. The rest is handled - * in hermes.c and main.c. - * - * Utilities for downloading the Symbol firmware are available at - * http://sourceforge.net/projects/orinoco/ - * - * Copyright (C) 2002-2005 Pavel Roskin - * Portions based on orinoco_cs.c: - * Copyright (C) David Gibson, Linuxcare Australia - * Portions based on Spectrum24tDnld.c from original spectrum24 driver: - * Copyright (C) Symbol Technologies. - * - * See copyright notice in file main.c. - */ - -#define DRIVER_NAME "spectrum_cs" -#define PFX DRIVER_NAME ": " - -#include -#include -#include -#include -#include -#include - -#include "orinoco.h" - -/********************************************************************/ -/* Module stuff */ -/********************************************************************/ - -MODULE_AUTHOR("Pavel Roskin "); -MODULE_DESCRIPTION("Driver for Symbol Spectrum24 Trilogy cards with firmware downloader"); -MODULE_LICENSE("Dual MPL/GPL"); - -/* Module parameters */ - -/* Some D-Link cards have buggy CIS. They do work at 5v properly, but - * don't have any CIS entry for it. This workaround it... */ -static int ignore_cis_vcc; /* = 0 */ -module_param(ignore_cis_vcc, int, 0); -MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket"); - -/********************************************************************/ -/* Data structures */ -/********************************************************************/ - -/* PCMCIA specific device information (goes in the card field of - * struct orinoco_private */ -struct orinoco_pccard { - struct pcmcia_device *p_dev; -}; - -/********************************************************************/ -/* Function prototypes */ -/********************************************************************/ - -static int spectrum_cs_config(struct pcmcia_device *link); -static void spectrum_cs_release(struct pcmcia_device *link); - -/* Constants for the CISREG_CCSR register */ -#define HCR_RUN 0x07 /* run firmware after reset */ -#define HCR_IDLE 0x0E /* don't run firmware after reset */ -#define HCR_MEM16 0x10 /* memory width bit, should be preserved */ - - -/* - * Reset the card using configuration registers COR and CCSR. - * If IDLE is 1, stop the firmware, so that it can be safely rewritten. - */ -static int -spectrum_reset(struct pcmcia_device *link, int idle) -{ - int ret; - u8 save_cor; - u8 ccsr; - - /* Doing it if hardware is gone is guaranteed crash */ - if (!pcmcia_dev_present(link)) - return -ENODEV; - - /* Save original COR value */ - ret = pcmcia_read_config_byte(link, CISREG_COR, &save_cor); - if (ret) - goto failed; - - /* Soft-Reset card */ - ret = pcmcia_write_config_byte(link, CISREG_COR, - (save_cor | COR_SOFT_RESET)); - if (ret) - goto failed; - udelay(1000); - - /* Read CCSR */ - ret = pcmcia_read_config_byte(link, CISREG_CCSR, &ccsr); - if (ret) - goto failed; - - /* - * Start or stop the firmware. Memory width bit should be - * preserved from the value we've just read. - */ - ccsr = (idle ? HCR_IDLE : HCR_RUN) | (ccsr & HCR_MEM16); - ret = pcmcia_write_config_byte(link, CISREG_CCSR, ccsr); - if (ret) - goto failed; - udelay(1000); - - /* Restore original COR configuration index */ - ret = pcmcia_write_config_byte(link, CISREG_COR, - (save_cor & ~COR_SOFT_RESET)); - if (ret) - goto failed; - udelay(1000); - return 0; - -failed: - return -ENODEV; -} - -/********************************************************************/ -/* Device methods */ -/********************************************************************/ - -static int -spectrum_cs_hard_reset(struct orinoco_private *priv) -{ - struct orinoco_pccard *card = priv->card; - struct pcmcia_device *link = card->p_dev; - - /* Soft reset using COR and HCR */ - spectrum_reset(link, 0); - - return 0; -} - -static int -spectrum_cs_stop_firmware(struct orinoco_private *priv, int idle) -{ - struct orinoco_pccard *card = priv->card; - struct pcmcia_device *link = card->p_dev; - - return spectrum_reset(link, idle); -} - -/********************************************************************/ -/* PCMCIA stuff */ -/********************************************************************/ - -static int -spectrum_cs_probe(struct pcmcia_device *link) -{ - struct orinoco_private *priv; - struct orinoco_pccard *card; - int ret; - - priv = alloc_orinocodev(sizeof(*card), &link->dev, - spectrum_cs_hard_reset, - spectrum_cs_stop_firmware); - if (!priv) - return -ENOMEM; - card = priv->card; - - /* Link both structures together */ - card->p_dev = link; - link->priv = priv; - - ret = spectrum_cs_config(link); - if (ret) - goto err_free_orinocodev; - - return 0; - -err_free_orinocodev: - free_orinocodev(priv); - return ret; -} - -static void spectrum_cs_detach(struct pcmcia_device *link) -{ - struct orinoco_private *priv = link->priv; - - orinoco_if_del(priv); - - spectrum_cs_release(link); - - free_orinocodev(priv); -} /* spectrum_cs_detach */ - -static int spectrum_cs_config_check(struct pcmcia_device *p_dev, - void *priv_data) -{ - if (p_dev->config_index == 0) - return -EINVAL; - - return pcmcia_request_io(p_dev); -}; - -static int -spectrum_cs_config(struct pcmcia_device *link) -{ - struct orinoco_private *priv = link->priv; - struct hermes *hw = &priv->hw; - int ret; - void __iomem *mem; - - link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC | - CONF_AUTO_SET_IO | CONF_ENABLE_IRQ; - if (ignore_cis_vcc) - link->config_flags &= ~CONF_AUTO_CHECK_VCC; - ret = pcmcia_loop_config(link, spectrum_cs_config_check, NULL); - if (ret) { - if (!ignore_cis_vcc) - printk(KERN_ERR PFX "GetNextTuple(): No matching " - "CIS configuration. Maybe you need the " - "ignore_cis_vcc=1 parameter.\n"); - goto failed; - } - - mem = ioport_map(link->resource[0]->start, - resource_size(link->resource[0])); - if (!mem) - goto failed; - - /* We initialize the hermes structure before completing PCMCIA - * configuration just in case the interrupt handler gets - * called. */ - hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING); - hw->eeprom_pda = true; - - ret = pcmcia_request_irq(link, orinoco_interrupt); - if (ret) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - /* Reset card */ - if (spectrum_cs_hard_reset(priv) != 0) - goto failed; - - /* Initialise the main driver */ - if (orinoco_init(priv) != 0) { - printk(KERN_ERR PFX "orinoco_init() failed\n"); - goto failed; - } - - /* Register an interface with the stack */ - if (orinoco_if_add(priv, link->resource[0]->start, - link->irq, NULL) != 0) { - printk(KERN_ERR PFX "orinoco_if_add() failed\n"); - goto failed; - } - - return 0; - - failed: - spectrum_cs_release(link); - return -ENODEV; -} /* spectrum_cs_config */ - -static void -spectrum_cs_release(struct pcmcia_device *link) -{ - struct orinoco_private *priv = link->priv; - unsigned long flags; - - /* We're committed to taking the device away now, so mark the - * hardware as unavailable */ - priv->hw.ops->lock_irqsave(&priv->lock, &flags); - priv->hw_unavailable++; - priv->hw.ops->unlock_irqrestore(&priv->lock, &flags); - - pcmcia_disable_device(link); - if (priv->hw.iobase) - ioport_unmap(priv->hw.iobase); -} /* spectrum_cs_release */ - - -static int -spectrum_cs_suspend(struct pcmcia_device *link) -{ - struct orinoco_private *priv = link->priv; - - /* Mark the device as stopped, to block IO until later */ - orinoco_down(priv); - - return 0; -} - -static int -spectrum_cs_resume(struct pcmcia_device *link) -{ - struct orinoco_private *priv = link->priv; - int err = orinoco_up(priv); - - return err; -} - - -/********************************************************************/ -/* Module initialization */ -/********************************************************************/ - -static const struct pcmcia_device_id spectrum_cs_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0x026c, 0x0001), /* Symbol Spectrum24 LA4137 */ - PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0001), /* Socket Communications CF */ - PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless LAN PC Card", 0x816cc815, 0x6fbf459a), /* 2011B, not 2011 */ - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, spectrum_cs_ids); - -static struct pcmcia_driver orinoco_driver = { - .owner = THIS_MODULE, - .name = DRIVER_NAME, - .probe = spectrum_cs_probe, - .remove = spectrum_cs_detach, - .suspend = spectrum_cs_suspend, - .resume = spectrum_cs_resume, - .id_table = spectrum_cs_ids, -}; -module_pcmcia_driver(orinoco_driver); diff --git a/drivers/net/wireless/intersil/orinoco/wext.c b/drivers/net/wireless/intersil/orinoco/wext.c deleted file mode 100644 index dea1ff044342d..0000000000000 --- a/drivers/net/wireless/intersil/orinoco/wext.c +++ /dev/null @@ -1,1428 +0,0 @@ -/* Wireless extensions support. - * - * See copyright notice in main.c - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "hermes.h" -#include "hermes_rid.h" -#include "orinoco.h" - -#include "hw.h" -#include "mic.h" -#include "scan.h" -#include "main.h" - -#include "wext.h" - -#define MAX_RID_LEN 1024 - -/* Helper routine to record keys - * It is called under orinoco_lock so it may not sleep */ -static int orinoco_set_key(struct orinoco_private *priv, int index, - enum orinoco_alg alg, const u8 *key, int key_len, - const u8 *seq, int seq_len) -{ - kfree_sensitive(priv->keys[index].key); - kfree_sensitive(priv->keys[index].seq); - - if (key_len) { - priv->keys[index].key = kzalloc(key_len, GFP_ATOMIC); - if (!priv->keys[index].key) - goto nomem; - } else - priv->keys[index].key = NULL; - - if (seq_len) { - priv->keys[index].seq = kzalloc(seq_len, GFP_ATOMIC); - if (!priv->keys[index].seq) - goto free_key; - } else - priv->keys[index].seq = NULL; - - priv->keys[index].key_len = key_len; - priv->keys[index].seq_len = seq_len; - - if (key_len) - memcpy((void *)priv->keys[index].key, key, key_len); - if (seq_len) - memcpy((void *)priv->keys[index].seq, seq, seq_len); - - switch (alg) { - case ORINOCO_ALG_TKIP: - priv->keys[index].cipher = WLAN_CIPHER_SUITE_TKIP; - break; - - case ORINOCO_ALG_WEP: - priv->keys[index].cipher = (key_len > SMALL_KEY_SIZE) ? - WLAN_CIPHER_SUITE_WEP104 : WLAN_CIPHER_SUITE_WEP40; - break; - - case ORINOCO_ALG_NONE: - default: - priv->keys[index].cipher = 0; - break; - } - - return 0; - -free_key: - kfree(priv->keys[index].key); - priv->keys[index].key = NULL; - -nomem: - priv->keys[index].key_len = 0; - priv->keys[index].seq_len = 0; - priv->keys[index].cipher = 0; - - return -ENOMEM; -} - -static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) -{ - struct orinoco_private *priv = ndev_priv(dev); - struct hermes *hw = &priv->hw; - struct iw_statistics *wstats = &priv->wstats; - int err; - unsigned long flags; - - if (!netif_device_present(dev)) { - printk(KERN_WARNING "%s: get_wireless_stats() called while device not present\n", - dev->name); - return NULL; /* FIXME: Can we do better than this? */ - } - - /* If busy, return the old stats. Returning NULL may cause - * the interface to disappear from /proc/net/wireless */ - if (orinoco_lock(priv, &flags) != 0) - return wstats; - - /* We can't really wait for the tallies inquiry command to - * complete, so we just use the previous results and trigger - * a new tallies inquiry command for next time - Jean II */ - /* FIXME: Really we should wait for the inquiry to come back - - * as it is the stats we give don't make a whole lot of sense. - * Unfortunately, it's not clear how to do that within the - * wireless extensions framework: I think we're in user - * context, but a lock seems to be held by the time we get in - * here so we're not safe to sleep here. */ - hermes_inquire(hw, HERMES_INQ_TALLIES); - - if (priv->iw_mode == NL80211_IFTYPE_ADHOC) { - memset(&wstats->qual, 0, sizeof(wstats->qual)); - /* If a spy address is defined, we report stats of the - * first spy address - Jean II */ - if (SPY_NUMBER(priv)) { - wstats->qual.qual = priv->spy_data.spy_stat[0].qual; - wstats->qual.level = priv->spy_data.spy_stat[0].level; - wstats->qual.noise = priv->spy_data.spy_stat[0].noise; - wstats->qual.updated = - priv->spy_data.spy_stat[0].updated; - } - } else { - struct { - __le16 qual, signal, noise, unused; - } __packed cq; - - err = HERMES_READ_RECORD(hw, USER_BAP, - HERMES_RID_COMMSQUALITY, &cq); - - if (!err) { - wstats->qual.qual = (int)le16_to_cpu(cq.qual); - wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95; - wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95; - wstats->qual.updated = - IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; - } - } - - orinoco_unlock(priv, &flags); - return wstats; -} - -/********************************************************************/ -/* Wireless extensions */ -/********************************************************************/ - -static int orinoco_ioctl_setwap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct sockaddr *ap_addr = &wrqu->ap_addr; - struct orinoco_private *priv = ndev_priv(dev); - int err = -EINPROGRESS; /* Call commit handler */ - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - /* Enable automatic roaming - no sanity checks are needed */ - if (is_zero_ether_addr(ap_addr->sa_data) || - is_broadcast_ether_addr(ap_addr->sa_data)) { - priv->bssid_fixed = 0; - eth_zero_addr(priv->desired_bssid); - - /* "off" means keep existing connection */ - if (ap_addr->sa_data[0] == 0) { - __orinoco_hw_set_wap(priv); - err = 0; - } - goto out; - } - - if (priv->firmware_type == FIRMWARE_TYPE_AGERE) { - printk(KERN_WARNING "%s: Lucent/Agere firmware doesn't " - "support manual roaming\n", - dev->name); - err = -EOPNOTSUPP; - goto out; - } - - if (priv->iw_mode != NL80211_IFTYPE_STATION) { - printk(KERN_WARNING "%s: Manual roaming supported only in " - "managed mode\n", dev->name); - err = -EOPNOTSUPP; - goto out; - } - - /* Intersil firmware hangs without Desired ESSID */ - if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL && - strlen(priv->desired_essid) == 0) { - printk(KERN_WARNING "%s: Desired ESSID must be set for " - "manual roaming\n", dev->name); - err = -EOPNOTSUPP; - goto out; - } - - /* Finally, enable manual roaming */ - priv->bssid_fixed = 1; - memcpy(priv->desired_bssid, &ap_addr->sa_data, ETH_ALEN); - - out: - orinoco_unlock(priv, &flags); - return err; -} - -static int orinoco_ioctl_getwap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct sockaddr *ap_addr = &wrqu->ap_addr; - struct orinoco_private *priv = ndev_priv(dev); - - int err = 0; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - ap_addr->sa_family = ARPHRD_ETHER; - err = orinoco_hw_get_current_bssid(priv, ap_addr->sa_data); - - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_setiwencode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *keybuf) -{ - struct iw_point *erq = &wrqu->encoding; - struct orinoco_private *priv = ndev_priv(dev); - int index = (erq->flags & IW_ENCODE_INDEX) - 1; - int setindex = priv->tx_key; - enum orinoco_alg encode_alg = priv->encode_alg; - int restricted = priv->wep_restrict; - int err = -EINPROGRESS; /* Call commit handler */ - unsigned long flags; - - if (!priv->has_wep) - return -EOPNOTSUPP; - - if (erq->pointer) { - /* We actually have a key to set - check its length */ - if (erq->length > LARGE_KEY_SIZE) - return -E2BIG; - - if ((erq->length > SMALL_KEY_SIZE) && !priv->has_big_wep) - return -E2BIG; - } - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - /* Clear any TKIP key we have */ - if ((priv->has_wpa) && (priv->encode_alg == ORINOCO_ALG_TKIP)) - (void) orinoco_clear_tkip_key(priv, setindex); - - if (erq->length > 0) { - if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) - index = priv->tx_key; - - /* Switch on WEP if off */ - if (encode_alg != ORINOCO_ALG_WEP) { - setindex = index; - encode_alg = ORINOCO_ALG_WEP; - } - } else { - /* Important note : if the user do "iwconfig eth0 enc off", - * we will arrive there with an index of -1. This is valid - * but need to be taken care off... Jean II */ - if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) { - if ((index != -1) || (erq->flags == 0)) { - err = -EINVAL; - goto out; - } - } else { - /* Set the index : Check that the key is valid */ - if (priv->keys[index].key_len == 0) { - err = -EINVAL; - goto out; - } - setindex = index; - } - } - - if (erq->flags & IW_ENCODE_DISABLED) - encode_alg = ORINOCO_ALG_NONE; - if (erq->flags & IW_ENCODE_OPEN) - restricted = 0; - if (erq->flags & IW_ENCODE_RESTRICTED) - restricted = 1; - - if (erq->pointer && erq->length > 0) { - err = orinoco_set_key(priv, index, ORINOCO_ALG_WEP, keybuf, - erq->length, NULL, 0); - } - priv->tx_key = setindex; - - /* Try fast key change if connected and only keys are changed */ - if ((priv->encode_alg == encode_alg) && - (priv->wep_restrict == restricted) && - netif_carrier_ok(dev)) { - err = __orinoco_hw_setup_wepkeys(priv); - /* No need to commit if successful */ - goto out; - } - - priv->encode_alg = encode_alg; - priv->wep_restrict = restricted; - - out: - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_getiwencode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *keybuf) -{ - struct iw_point *erq = &wrqu->encoding; - struct orinoco_private *priv = ndev_priv(dev); - int index = (erq->flags & IW_ENCODE_INDEX) - 1; - unsigned long flags; - - if (!priv->has_wep) - return -EOPNOTSUPP; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) - index = priv->tx_key; - - erq->flags = 0; - if (!priv->encode_alg) - erq->flags |= IW_ENCODE_DISABLED; - erq->flags |= index + 1; - - if (priv->wep_restrict) - erq->flags |= IW_ENCODE_RESTRICTED; - else - erq->flags |= IW_ENCODE_OPEN; - - erq->length = priv->keys[index].key_len; - - memcpy(keybuf, priv->keys[index].key, erq->length); - - orinoco_unlock(priv, &flags); - return 0; -} - -static int orinoco_ioctl_setessid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *essidbuf) -{ - struct iw_point *erq = &wrqu->essid; - struct orinoco_private *priv = ndev_priv(dev); - unsigned long flags; - - /* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it - * anyway... - Jean II */ - - /* Hum... Should not use Wireless Extension constant (may change), - * should use our own... - Jean II */ - if (erq->length > IW_ESSID_MAX_SIZE) - return -E2BIG; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - /* NULL the string (for NULL termination & ESSID = ANY) - Jean II */ - memset(priv->desired_essid, 0, sizeof(priv->desired_essid)); - - /* If not ANY, get the new ESSID */ - if (erq->flags) - memcpy(priv->desired_essid, essidbuf, erq->length); - - orinoco_unlock(priv, &flags); - - return -EINPROGRESS; /* Call commit handler */ -} - -static int orinoco_ioctl_getessid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *essidbuf) -{ - struct iw_point *erq = &wrqu->essid; - struct orinoco_private *priv = ndev_priv(dev); - int active; - int err = 0; - unsigned long flags; - - if (netif_running(dev)) { - err = orinoco_hw_get_essid(priv, &active, essidbuf); - if (err < 0) - return err; - erq->length = err; - } else { - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - memcpy(essidbuf, priv->desired_essid, IW_ESSID_MAX_SIZE); - erq->length = strlen(priv->desired_essid); - orinoco_unlock(priv, &flags); - } - - erq->flags = 1; - - return 0; -} - -static int orinoco_ioctl_setfreq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_freq *frq = &wrqu->freq; - struct orinoco_private *priv = ndev_priv(dev); - int chan = -1; - unsigned long flags; - int err = -EINPROGRESS; /* Call commit handler */ - - /* In infrastructure mode the AP sets the channel */ - if (priv->iw_mode == NL80211_IFTYPE_STATION) - return -EBUSY; - - if ((frq->e == 0) && (frq->m <= 1000)) { - /* Setting by channel number */ - chan = frq->m; - } else { - /* Setting by frequency */ - int denom = 1; - int i; - - /* Calculate denominator to rescale to MHz */ - for (i = 0; i < (6 - frq->e); i++) - denom *= 10; - - chan = ieee80211_frequency_to_channel(frq->m / denom); - } - - if ((chan < 1) || (chan > NUM_CHANNELS) || - !(priv->channel_mask & (1 << (chan - 1)))) - return -EINVAL; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - priv->channel = chan; - if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { - /* Fast channel change - no commit if successful */ - struct hermes *hw = &priv->hw; - err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST | - HERMES_TEST_SET_CHANNEL, - chan, NULL); - } - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_getfreq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_freq *frq = &wrqu->freq; - struct orinoco_private *priv = ndev_priv(dev); - int tmp; - - /* Locking done in there */ - tmp = orinoco_hw_get_freq(priv); - if (tmp < 0) - return tmp; - - frq->m = tmp * 100000; - frq->e = 1; - - return 0; -} - -static int orinoco_ioctl_getsens(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *srq = &wrqu->sens; - struct orinoco_private *priv = ndev_priv(dev); - struct hermes *hw = &priv->hw; - u16 val; - int err; - unsigned long flags; - - if (!priv->has_sensitivity) - return -EOPNOTSUPP; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CNFSYSTEMSCALE, &val); - orinoco_unlock(priv, &flags); - - if (err) - return err; - - srq->value = val; - srq->fixed = 0; /* auto */ - - return 0; -} - -static int orinoco_ioctl_setsens(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *srq = &wrqu->sens; - struct orinoco_private *priv = ndev_priv(dev); - int val = srq->value; - unsigned long flags; - - if (!priv->has_sensitivity) - return -EOPNOTSUPP; - - if ((val < 1) || (val > 3)) - return -EINVAL; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - priv->ap_density = val; - orinoco_unlock(priv, &flags); - - return -EINPROGRESS; /* Call commit handler */ -} - -static int orinoco_ioctl_setrate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *rrq = &wrqu->bitrate; - struct orinoco_private *priv = ndev_priv(dev); - int ratemode; - int bitrate; /* 100s of kilobits */ - unsigned long flags; - - /* As the user space doesn't know our highest rate, it uses -1 - * to ask us to set the highest rate. Test it using "iwconfig - * ethX rate auto" - Jean II */ - if (rrq->value == -1) - bitrate = 110; - else { - if (rrq->value % 100000) - return -EINVAL; - bitrate = rrq->value / 100000; - } - - ratemode = orinoco_get_bitratemode(bitrate, !rrq->fixed); - - if (ratemode == -1) - return -EINVAL; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - priv->bitratemode = ratemode; - orinoco_unlock(priv, &flags); - - return -EINPROGRESS; -} - -static int orinoco_ioctl_getrate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *rrq = &wrqu->bitrate; - struct orinoco_private *priv = ndev_priv(dev); - int err = 0; - int bitrate, automatic; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - orinoco_get_ratemode_cfg(priv->bitratemode, &bitrate, &automatic); - - /* If the interface is running we try to find more about the - current mode */ - if (netif_running(dev)) { - int act_bitrate; - int lerr; - - /* Ignore errors if we can't get the actual bitrate */ - lerr = orinoco_hw_get_act_bitrate(priv, &act_bitrate); - if (!lerr) - bitrate = act_bitrate; - } - - orinoco_unlock(priv, &flags); - - rrq->value = bitrate; - rrq->fixed = !automatic; - rrq->disabled = 0; - - return err; -} - -static int orinoco_ioctl_setpower(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *prq = &wrqu->power; - struct orinoco_private *priv = ndev_priv(dev); - int err = -EINPROGRESS; /* Call commit handler */ - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - if (prq->disabled) { - priv->pm_on = 0; - } else { - switch (prq->flags & IW_POWER_MODE) { - case IW_POWER_UNICAST_R: - priv->pm_mcast = 0; - priv->pm_on = 1; - break; - case IW_POWER_ALL_R: - priv->pm_mcast = 1; - priv->pm_on = 1; - break; - case IW_POWER_ON: - /* No flags : but we may have a value - Jean II */ - break; - default: - err = -EINVAL; - goto out; - } - - if (prq->flags & IW_POWER_TIMEOUT) { - priv->pm_on = 1; - priv->pm_timeout = prq->value / 1000; - } - if (prq->flags & IW_POWER_PERIOD) { - priv->pm_on = 1; - priv->pm_period = prq->value / 1000; - } - /* It's valid to not have a value if we are just toggling - * the flags... Jean II */ - if (!priv->pm_on) { - err = -EINVAL; - goto out; - } - } - - out: - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_getpower(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *prq = &wrqu->power; - struct orinoco_private *priv = ndev_priv(dev); - struct hermes *hw = &priv->hw; - int err = 0; - u16 enable, period, timeout, mcast; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CNFPMENABLED, &enable); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CNFMAXSLEEPDURATION, &period); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CNFPMHOLDOVERDURATION, &timeout); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CNFMULTICASTRECEIVE, &mcast); - if (err) - goto out; - - prq->disabled = !enable; - /* Note : by default, display the period */ - if ((prq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { - prq->flags = IW_POWER_TIMEOUT; - prq->value = timeout * 1000; - } else { - prq->flags = IW_POWER_PERIOD; - prq->value = period * 1000; - } - if (mcast) - prq->flags |= IW_POWER_ALL_R; - else - prq->flags |= IW_POWER_UNICAST_R; - - out: - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_set_encodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - struct iw_point *encoding = &wrqu->encoding; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - int idx, alg = ext->alg, set_key = 1; - unsigned long flags; - int err = -EINVAL; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - /* Determine and validate the key index */ - idx = encoding->flags & IW_ENCODE_INDEX; - if (idx) { - if ((idx < 1) || (idx > 4)) - goto out; - idx--; - } else - idx = priv->tx_key; - - if (encoding->flags & IW_ENCODE_DISABLED) - alg = IW_ENCODE_ALG_NONE; - - if (priv->has_wpa && (alg != IW_ENCODE_ALG_TKIP)) { - /* Clear any TKIP TX key we had */ - (void) orinoco_clear_tkip_key(priv, priv->tx_key); - } - - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { - priv->tx_key = idx; - set_key = ((alg == IW_ENCODE_ALG_TKIP) || - (ext->key_len > 0)) ? 1 : 0; - } - - if (set_key) { - /* Set the requested key first */ - switch (alg) { - case IW_ENCODE_ALG_NONE: - priv->encode_alg = ORINOCO_ALG_NONE; - err = orinoco_set_key(priv, idx, ORINOCO_ALG_NONE, - NULL, 0, NULL, 0); - break; - - case IW_ENCODE_ALG_WEP: - if (ext->key_len <= 0) - goto out; - - priv->encode_alg = ORINOCO_ALG_WEP; - err = orinoco_set_key(priv, idx, ORINOCO_ALG_WEP, - ext->key, ext->key_len, NULL, 0); - break; - - case IW_ENCODE_ALG_TKIP: - { - u8 *tkip_iv = NULL; - - if (!priv->has_wpa || - (ext->key_len > sizeof(struct orinoco_tkip_key))) - goto out; - - priv->encode_alg = ORINOCO_ALG_TKIP; - - if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) - tkip_iv = &ext->rx_seq[0]; - - err = orinoco_set_key(priv, idx, ORINOCO_ALG_TKIP, - ext->key, ext->key_len, tkip_iv, - ORINOCO_SEQ_LEN); - - err = __orinoco_hw_set_tkip_key(priv, idx, - ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, - priv->keys[idx].key, priv->keys[idx].key_len, - tkip_iv, ORINOCO_SEQ_LEN, NULL, 0); - if (err) - printk(KERN_ERR "%s: Error %d setting TKIP key" - "\n", dev->name, err); - - goto out; - } - default: - goto out; - } - } - err = -EINPROGRESS; - out: - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_get_encodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - struct iw_point *encoding = &wrqu->encoding; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - int idx, max_key_len; - unsigned long flags; - int err; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - err = -EINVAL; - max_key_len = encoding->length - sizeof(*ext); - if (max_key_len < 0) - goto out; - - idx = encoding->flags & IW_ENCODE_INDEX; - if (idx) { - if ((idx < 1) || (idx > 4)) - goto out; - idx--; - } else - idx = priv->tx_key; - - encoding->flags = idx + 1; - memset(ext, 0, sizeof(*ext)); - - switch (priv->encode_alg) { - case ORINOCO_ALG_NONE: - ext->alg = IW_ENCODE_ALG_NONE; - ext->key_len = 0; - encoding->flags |= IW_ENCODE_DISABLED; - break; - case ORINOCO_ALG_WEP: - ext->alg = IW_ENCODE_ALG_WEP; - ext->key_len = min(priv->keys[idx].key_len, max_key_len); - memcpy(ext->key, priv->keys[idx].key, ext->key_len); - encoding->flags |= IW_ENCODE_ENABLED; - break; - case ORINOCO_ALG_TKIP: - ext->alg = IW_ENCODE_ALG_TKIP; - ext->key_len = min(priv->keys[idx].key_len, max_key_len); - memcpy(ext->key, priv->keys[idx].key, ext->key_len); - encoding->flags |= IW_ENCODE_ENABLED; - break; - } - - err = 0; - out: - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_set_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - struct hermes *hw = &priv->hw; - struct iw_param *param = &wrqu->param; - unsigned long flags; - int ret = -EINPROGRESS; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - case IW_AUTH_CIPHER_PAIRWISE: - case IW_AUTH_CIPHER_GROUP: - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - case IW_AUTH_PRIVACY_INVOKED: - case IW_AUTH_DROP_UNENCRYPTED: - /* - * orinoco does not use these parameters - */ - break; - - case IW_AUTH_MFP: - /* Management Frame Protection not supported. - * Only fail if set to required. - */ - if (param->value == IW_AUTH_MFP_REQUIRED) - ret = -EINVAL; - break; - - case IW_AUTH_KEY_MGMT: - /* wl_lkm implies value 2 == PSK for Hermes I - * which ties in with WEXT - * no other hints tho :( - */ - priv->key_mgmt = param->value; - break; - - case IW_AUTH_TKIP_COUNTERMEASURES: - /* When countermeasures are enabled, shut down the - * card; when disabled, re-enable the card. This must - * take effect immediately. - * - * TODO: Make sure that the EAPOL message is getting - * out before card disabled - */ - if (param->value) { - priv->tkip_cm_active = 1; - ret = hermes_disable_port(hw, 0); - } else { - priv->tkip_cm_active = 0; - ret = hermes_enable_port(hw, 0); - } - break; - - case IW_AUTH_80211_AUTH_ALG: - if (param->value & IW_AUTH_ALG_SHARED_KEY) - priv->wep_restrict = 1; - else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) - priv->wep_restrict = 0; - else - ret = -EINVAL; - break; - - case IW_AUTH_WPA_ENABLED: - if (priv->has_wpa) { - priv->wpa_enabled = param->value ? 1 : 0; - } else { - if (param->value) - ret = -EOPNOTSUPP; - /* else silently accept disable of WPA */ - priv->wpa_enabled = 0; - } - break; - - default: - ret = -EOPNOTSUPP; - } - - orinoco_unlock(priv, &flags); - return ret; -} - -static int orinoco_ioctl_get_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - struct iw_param *param = &wrqu->param; - unsigned long flags; - int ret = 0; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_KEY_MGMT: - param->value = priv->key_mgmt; - break; - - case IW_AUTH_TKIP_COUNTERMEASURES: - param->value = priv->tkip_cm_active; - break; - - case IW_AUTH_80211_AUTH_ALG: - if (priv->wep_restrict) - param->value = IW_AUTH_ALG_SHARED_KEY; - else - param->value = IW_AUTH_ALG_OPEN_SYSTEM; - break; - - case IW_AUTH_WPA_ENABLED: - param->value = priv->wpa_enabled; - break; - - default: - ret = -EOPNOTSUPP; - } - - orinoco_unlock(priv, &flags); - return ret; -} - -static int orinoco_ioctl_set_genie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - u8 *buf; - unsigned long flags; - - /* cut off at IEEE80211_MAX_DATA_LEN */ - if ((wrqu->data.length > IEEE80211_MAX_DATA_LEN) || - (wrqu->data.length && (extra == NULL))) - return -EINVAL; - - if (wrqu->data.length) { - buf = kmemdup(extra, wrqu->data.length, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - } else - buf = NULL; - - if (orinoco_lock(priv, &flags) != 0) { - kfree(buf); - return -EBUSY; - } - - kfree(priv->wpa_ie); - priv->wpa_ie = buf; - priv->wpa_ie_len = wrqu->data.length; - - if (priv->wpa_ie) { - /* Looks like wl_lkm wants to check the auth alg, and - * somehow pass it to the firmware. - * Instead it just calls the key mgmt rid - * - we do this in set auth. - */ - } - - orinoco_unlock(priv, &flags); - return 0; -} - -static int orinoco_ioctl_get_genie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - unsigned long flags; - int err = 0; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - if ((priv->wpa_ie_len == 0) || (priv->wpa_ie == NULL)) { - wrqu->data.length = 0; - goto out; - } - - if (wrqu->data.length < priv->wpa_ie_len) { - err = -E2BIG; - goto out; - } - - wrqu->data.length = priv->wpa_ie_len; - memcpy(extra, priv->wpa_ie, priv->wpa_ie_len); - -out: - orinoco_unlock(priv, &flags); - return err; -} - -static int orinoco_ioctl_set_mlme(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - struct iw_mlme *mlme = (struct iw_mlme *)extra; - unsigned long flags; - int ret = 0; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - switch (mlme->cmd) { - case IW_MLME_DEAUTH: - /* silently ignore */ - break; - - case IW_MLME_DISASSOC: - - ret = orinoco_hw_disassociate(priv, mlme->addr.sa_data, - mlme->reason_code); - break; - - default: - ret = -EOPNOTSUPP; - } - - orinoco_unlock(priv, &flags); - return ret; -} - -static int orinoco_ioctl_reset(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - if (info->cmd == (SIOCIWFIRSTPRIV + 0x1)) { - printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name); - - /* Firmware reset */ - orinoco_reset(&priv->reset_work); - } else { - printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name); - - schedule_work(&priv->reset_work); - } - - return 0; -} - -static int orinoco_ioctl_setibssport(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) - -{ - struct orinoco_private *priv = ndev_priv(dev); - int val = *((int *) extra); - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - priv->ibss_port = val; - - /* Actually update the mode we are using */ - set_port_type(priv); - - orinoco_unlock(priv, &flags); - return -EINPROGRESS; /* Call commit handler */ -} - -static int orinoco_ioctl_getibssport(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - int *val = (int *) extra; - - *val = priv->ibss_port; - return 0; -} - -static int orinoco_ioctl_setport3(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - int val = *((int *) extra); - int err = 0; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - switch (val) { - case 0: /* Try to do IEEE ad-hoc mode */ - if (!priv->has_ibss) { - err = -EINVAL; - break; - } - priv->prefer_port3 = 0; - - break; - - case 1: /* Try to do Lucent proprietary ad-hoc mode */ - if (!priv->has_port3) { - err = -EINVAL; - break; - } - priv->prefer_port3 = 1; - break; - - default: - err = -EINVAL; - } - - if (!err) { - /* Actually update the mode we are using */ - set_port_type(priv); - err = -EINPROGRESS; - } - - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_getport3(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - int *val = (int *) extra; - - *val = priv->prefer_port3; - return 0; -} - -static int orinoco_ioctl_setpreamble(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - unsigned long flags; - int val; - - if (!priv->has_preamble) - return -EOPNOTSUPP; - - /* 802.11b has recently defined some short preamble. - * Basically, the Phy header has been reduced in size. - * This increase performance, especially at high rates - * (the preamble is transmitted at 1Mb/s), unfortunately - * this give compatibility troubles... - Jean II */ - val = *((int *) extra); - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - if (val) - priv->preamble = 1; - else - priv->preamble = 0; - - orinoco_unlock(priv, &flags); - - return -EINPROGRESS; /* Call commit handler */ -} - -static int orinoco_ioctl_getpreamble(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - int *val = (int *) extra; - - if (!priv->has_preamble) - return -EOPNOTSUPP; - - *val = priv->preamble; - return 0; -} - -/* ioctl interface to hermes_read_ltv() - * To use with iwpriv, pass the RID as the token argument, e.g. - * iwpriv get_rid [0xfc00] - * At least Wireless Tools 25 is required to use iwpriv. - * For Wireless Tools 25 and 26 append "dummy" are the end. */ -static int orinoco_ioctl_getrid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *data = &wrqu->data; - struct orinoco_private *priv = ndev_priv(dev); - struct hermes *hw = &priv->hw; - int rid = data->flags; - u16 length; - int err; - unsigned long flags; - - /* It's a "get" function, but we don't want users to access the - * WEP key and other raw firmware data */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - if (rid < 0xfc00 || rid > 0xffff) - return -EINVAL; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - err = hw->ops->read_ltv(hw, USER_BAP, rid, MAX_RID_LEN, &length, - extra); - if (err) - goto out; - - data->length = min_t(u16, HERMES_RECLEN_TO_BYTES(length), - MAX_RID_LEN); - - out: - orinoco_unlock(priv, &flags); - return err; -} - - -/* Commit handler, called after set operations */ -static int orinoco_ioctl_commit(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - unsigned long flags; - int err = 0; - - if (!priv->open) - return 0; - - if (orinoco_lock(priv, &flags) != 0) - return err; - - err = orinoco_commit(priv); - - orinoco_unlock(priv, &flags); - return err; -} - -static const struct iw_priv_args orinoco_privtab[] = { - { SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" }, - { SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" }, - { SIOCIWFIRSTPRIV + 0x2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - 0, "set_port3" }, - { SIOCIWFIRSTPRIV + 0x3, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "get_port3" }, - { SIOCIWFIRSTPRIV + 0x4, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - 0, "set_preamble" }, - { SIOCIWFIRSTPRIV + 0x5, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "get_preamble" }, - { SIOCIWFIRSTPRIV + 0x6, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - 0, "set_ibssport" }, - { SIOCIWFIRSTPRIV + 0x7, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "get_ibssport" }, - { SIOCIWFIRSTPRIV + 0x9, 0, IW_PRIV_TYPE_BYTE | MAX_RID_LEN, - "get_rid" }, -}; - - -/* - * Structures to export the Wireless Handlers - */ - -static const iw_handler orinoco_handler[] = { - IW_HANDLER(SIOCSIWCOMMIT, orinoco_ioctl_commit), - IW_HANDLER(SIOCGIWNAME, cfg80211_wext_giwname), - IW_HANDLER(SIOCSIWFREQ, orinoco_ioctl_setfreq), - IW_HANDLER(SIOCGIWFREQ, orinoco_ioctl_getfreq), - IW_HANDLER(SIOCSIWMODE, cfg80211_wext_siwmode), - IW_HANDLER(SIOCGIWMODE, cfg80211_wext_giwmode), - IW_HANDLER(SIOCSIWSENS, orinoco_ioctl_setsens), - IW_HANDLER(SIOCGIWSENS, orinoco_ioctl_getsens), - IW_HANDLER(SIOCGIWRANGE, cfg80211_wext_giwrange), - IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy), - IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy), - IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy), - IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy), - IW_HANDLER(SIOCSIWAP, orinoco_ioctl_setwap), - IW_HANDLER(SIOCGIWAP, orinoco_ioctl_getwap), - IW_HANDLER(SIOCSIWSCAN, cfg80211_wext_siwscan), - IW_HANDLER(SIOCGIWSCAN, cfg80211_wext_giwscan), - IW_HANDLER(SIOCSIWESSID, orinoco_ioctl_setessid), - IW_HANDLER(SIOCGIWESSID, orinoco_ioctl_getessid), - IW_HANDLER(SIOCSIWRATE, orinoco_ioctl_setrate), - IW_HANDLER(SIOCGIWRATE, orinoco_ioctl_getrate), - IW_HANDLER(SIOCSIWRTS, cfg80211_wext_siwrts), - IW_HANDLER(SIOCGIWRTS, cfg80211_wext_giwrts), - IW_HANDLER(SIOCSIWFRAG, cfg80211_wext_siwfrag), - IW_HANDLER(SIOCGIWFRAG, cfg80211_wext_giwfrag), - IW_HANDLER(SIOCGIWRETRY, cfg80211_wext_giwretry), - IW_HANDLER(SIOCSIWENCODE, orinoco_ioctl_setiwencode), - IW_HANDLER(SIOCGIWENCODE, orinoco_ioctl_getiwencode), - IW_HANDLER(SIOCSIWPOWER, orinoco_ioctl_setpower), - IW_HANDLER(SIOCGIWPOWER, orinoco_ioctl_getpower), - IW_HANDLER(SIOCSIWGENIE, orinoco_ioctl_set_genie), - IW_HANDLER(SIOCGIWGENIE, orinoco_ioctl_get_genie), - IW_HANDLER(SIOCSIWMLME, orinoco_ioctl_set_mlme), - IW_HANDLER(SIOCSIWAUTH, orinoco_ioctl_set_auth), - IW_HANDLER(SIOCGIWAUTH, orinoco_ioctl_get_auth), - IW_HANDLER(SIOCSIWENCODEEXT, orinoco_ioctl_set_encodeext), - IW_HANDLER(SIOCGIWENCODEEXT, orinoco_ioctl_get_encodeext), -}; - - -/* - Added typecasting since we no longer use iwreq_data -- Moustafa - */ -static const iw_handler orinoco_private_handler[] = { - [0] = orinoco_ioctl_reset, - [1] = orinoco_ioctl_reset, - [2] = orinoco_ioctl_setport3, - [3] = orinoco_ioctl_getport3, - [4] = orinoco_ioctl_setpreamble, - [5] = orinoco_ioctl_getpreamble, - [6] = orinoco_ioctl_setibssport, - [7] = orinoco_ioctl_getibssport, - [9] = orinoco_ioctl_getrid, -}; - -const struct iw_handler_def orinoco_handler_def = { - .num_standard = ARRAY_SIZE(orinoco_handler), - .num_private = ARRAY_SIZE(orinoco_private_handler), - .num_private_args = ARRAY_SIZE(orinoco_privtab), - .standard = orinoco_handler, - .private = orinoco_private_handler, - .private_args = orinoco_privtab, - .get_wireless_stats = orinoco_get_wireless_stats, -}; diff --git a/drivers/net/wireless/intersil/orinoco/wext.h b/drivers/net/wireless/intersil/orinoco/wext.h deleted file mode 100644 index 1479f4e26ddee..0000000000000 --- a/drivers/net/wireless/intersil/orinoco/wext.h +++ /dev/null @@ -1,13 +0,0 @@ -/* Wireless extensions support. - * - * See copyright notice in main.c - */ -#ifndef _ORINOCO_WEXT_H_ -#define _ORINOCO_WEXT_H_ - -#include - -/* Structure defining all our WEXT handlers */ -extern const struct iw_handler_def orinoco_handler_def; - -#endif /* _ORINOCO_WEXT_H_ */ diff --git a/drivers/net/wireless/legacy/Kconfig b/drivers/net/wireless/legacy/Kconfig deleted file mode 100644 index 3a5275941212d..0000000000000 --- a/drivers/net/wireless/legacy/Kconfig +++ /dev/null @@ -1,55 +0,0 @@ -config PCMCIA_RAYCS - tristate "Aviator/Raytheon 2.4GHz wireless support" - depends on PCMCIA - select WIRELESS_EXT - select WEXT_SPY - select WEXT_PRIV - help - Say Y here if you intend to attach an Aviator/Raytheon PCMCIA - (PC-card) wireless Ethernet networking card to your computer. - Please read the file - for - details. - - To compile this driver as a module, choose M here: the module will be - called ray_cs. If unsure, say N. - -config PCMCIA_WL3501 - tristate "Planet WL3501 PCMCIA cards" - depends on CFG80211 && PCMCIA - select WIRELESS_EXT - select WEXT_SPY - help - A driver for WL3501 PCMCIA 802.11 wireless cards made by Planet. - It has basic support for Linux wireless extensions and initial - micro support for ethtool. - -config USB_NET_RNDIS_WLAN - tristate "Wireless RNDIS USB support" - depends on USB - depends on CFG80211 - select USB_NET_DRIVERS - select USB_USBNET - select USB_NET_CDCETHER - select USB_NET_RNDIS_HOST - help - This is a driver for wireless RNDIS devices. - These are USB based adapters found in devices such as: - - Buffalo WLI-U2-KG125S - U.S. Robotics USR5421 - Belkin F5D7051 - Linksys WUSB54GSv2 - Linksys WUSB54GSC - Asus WL169gE - Eminent EM4045 - BT Voyager 1055 - Linksys WUSB54GSv1 - U.S. Robotics USR5420 - BUFFALO WLI-USB-G54 - - All of these devices are based on Broadcom 4320 chip which is the - only wireless RNDIS chip known to date. - - If you choose to build a module, it'll be called rndis_wlan. - diff --git a/drivers/net/wireless/legacy/Makefile b/drivers/net/wireless/legacy/Makefile deleted file mode 100644 index 36878f080bfc5..0000000000000 --- a/drivers/net/wireless/legacy/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# 16-bit wireless PCMCIA client drivers -obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o -obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o - -obj-$(CONFIG_USB_NET_RNDIS_WLAN) += rndis_wlan.o - diff --git a/drivers/net/wireless/legacy/ray_cs.c b/drivers/net/wireless/legacy/ray_cs.c deleted file mode 100644 index c95a79e01cd0f..0000000000000 --- a/drivers/net/wireless/legacy/ray_cs.c +++ /dev/null @@ -1,2824 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/*============================================================================= - * - * A PCMCIA client driver for the Raylink wireless LAN card. - * The starting point for this module was the skeleton.c in the - * PCMCIA 2.9.12 package written by David Hinds, dahinds@users.sourceforge.net - * - * Copyright (c) 1998 Corey Thomas (corey@world.std.com) - * - * Changes: - * Arnaldo Carvalho de Melo - 08/08/2000 - * - reorganize kmallocs in ray_attach, checking all for failure - * and releasing the previous allocations if one fails - * - * Daniele Bellucci - 07/10/2003 - * - Audit copy_to_user in ioctl(SIOCGIWESSID) - * -=============================================================================*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include -#include -#include - -/* Warning : these stuff will slow down the driver... */ -#define WIRELESS_SPY /* Enable spying addresses */ -/* Definitions we need for spy */ -typedef struct iw_statistics iw_stats; -typedef u_char mac_addr[ETH_ALEN]; /* Hardware address */ - -#include "rayctl.h" -#include "ray_cs.h" - - -/** Prototypes based on PCMCIA skeleton driver *******************************/ -static int ray_config(struct pcmcia_device *link); -static void ray_release(struct pcmcia_device *link); -static void ray_detach(struct pcmcia_device *p_dev); - -/***** Prototypes indicated by device structure ******************************/ -static int ray_dev_close(struct net_device *dev); -static int ray_dev_config(struct net_device *dev, struct ifmap *map); -static struct net_device_stats *ray_get_stats(struct net_device *dev); -static int ray_dev_init(struct net_device *dev); - -static int ray_open(struct net_device *dev); -static netdev_tx_t ray_dev_start_xmit(struct sk_buff *skb, - struct net_device *dev); -static void set_multicast_list(struct net_device *dev); -static void ray_update_multi_list(struct net_device *dev, int all); -static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx, - unsigned char *data, int len); -static void ray_build_header(ray_dev_t *local, struct tx_msg __iomem *ptx, - UCHAR msg_type, unsigned char *data); -static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len); -static iw_stats *ray_get_wireless_stats(struct net_device *dev); -static const struct iw_handler_def ray_handler_def; - -/***** Prototypes for raylink functions **************************************/ -static void authenticate(ray_dev_t *local); -static int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type); -static void authenticate_timeout(struct timer_list *t); -static int get_free_ccs(ray_dev_t *local); -static int get_free_tx_ccs(ray_dev_t *local); -static void init_startup_params(ray_dev_t *local); -static int parse_addr(char *in_str, UCHAR *out); -static int ray_hw_xmit(unsigned char *data, int len, struct net_device *dev, UCHAR type); -static int ray_init(struct net_device *dev); -static int interrupt_ecf(ray_dev_t *local, int ccs); -static void ray_reset(struct net_device *dev); -static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, int len); -static void verify_dl_startup(struct timer_list *t); - -/* Prototypes for interrpt time functions **********************************/ -static irqreturn_t ray_interrupt(int reg, void *dev_id); -static void clear_interrupt(ray_dev_t *local); -static void rx_deauthenticate(ray_dev_t *local, struct rcs __iomem *prcs, - unsigned int pkt_addr, int rx_len); -static int copy_from_rx_buff(ray_dev_t *local, UCHAR *dest, int pkt_addr, int len); -static void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs __iomem *prcs); -static void release_frag_chain(ray_dev_t *local, struct rcs __iomem *prcs); -static void rx_authenticate(ray_dev_t *local, struct rcs __iomem *prcs, - unsigned int pkt_addr, int rx_len); -static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, - unsigned int pkt_addr, int rx_len); -static void associate(ray_dev_t *local); - -/* Card command functions */ -static int dl_startup_params(struct net_device *dev); -static void join_net(struct timer_list *t); -static void start_net(struct timer_list *t); - -/*===========================================================================*/ -/* Parameters that can be set with 'insmod' */ - -/* ADHOC=0, Infrastructure=1 */ -static int net_type = ADHOC; - -/* Hop dwell time in Kus (1024 us units defined by 802.11) */ -static int hop_dwell = 128; - -/* Beacon period in Kus */ -static int beacon_period = 256; - -/* power save mode (0 = off, 1 = save power) */ -static int psm; - -/* String for network's Extended Service Set ID. 32 Characters max */ -static char *essid; - -/* Default to encapsulation unless translation requested */ -static bool translate = true; - -static int country = USA; - -static int sniffer; - -static int bc; - -/* 48 bit physical card address if overriding card's real physical - * address is required. Since IEEE 802.11 addresses are 48 bits - * like ethernet, an int can't be used, so a string is used. To - * allow use of addresses starting with a decimal digit, the first - * character must be a letter and will be ignored. This letter is - * followed by up to 12 hex digits which are the address. If less - * than 12 digits are used, the address will be left filled with 0's. - * Note that bit 0 of the first byte is the broadcast bit, and evil - * things will happen if it is not 0 in a card address. - */ -static char *phy_addr = NULL; - -static unsigned int ray_mem_speed = 500; - -/* WARNING: THIS DRIVER IS NOT CAPABLE OF HANDLING MULTIPLE DEVICES! */ -static struct pcmcia_device *this_device = NULL; - -MODULE_AUTHOR("Corey Thomas "); -MODULE_DESCRIPTION("Raylink/WebGear wireless LAN driver"); -MODULE_LICENSE("GPL"); - -module_param(net_type, int, 0); -module_param(hop_dwell, int, 0); -module_param(beacon_period, int, 0); -module_param(psm, int, 0); -module_param(essid, charp, 0); -module_param(translate, bool, 0); -module_param(country, int, 0); -module_param(sniffer, int, 0); -module_param(bc, int, 0); -module_param(phy_addr, charp, 0); -module_param(ray_mem_speed, int, 0); - -static const UCHAR b5_default_startup_parms[] = { - 0, 0, /* Adhoc station */ - 'L', 'I', 'N', 'U', 'X', 0, 0, 0, /* 32 char ESSID */ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 1, 0, /* Active scan, CA Mode */ - 0, 0, 0, 0, 0, 0, /* No default MAC addr */ - 0x7f, 0xff, /* Frag threshold */ - 0x00, 0x80, /* Hop time 128 Kus */ - 0x01, 0x00, /* Beacon period 256 Kus */ - 0x01, 0x07, 0xa3, /* DTIM, retries, ack timeout */ - 0x1d, 0x82, 0x4e, /* SIFS, DIFS, PIFS */ - 0x7f, 0xff, /* RTS threshold */ - 0x04, 0xe2, 0x38, 0xA4, /* scan_dwell, max_scan_dwell */ - 0x05, /* assoc resp timeout thresh */ - 0x08, 0x02, 0x08, /* adhoc, infra, super cycle max */ - 0, /* Promiscuous mode */ - 0x0c, 0x0bd, /* Unique word */ - 0x32, /* Slot time */ - 0xff, 0xff, /* roam-low snr, low snr count */ - 0x05, 0xff, /* Infra, adhoc missed bcn thresh */ - 0x01, 0x0b, 0x4f, /* USA, hop pattern, hop pat length */ -/* b4 - b5 differences start here */ - 0x00, 0x3f, /* CW max */ - 0x00, 0x0f, /* CW min */ - 0x04, 0x08, /* Noise gain, limit offset */ - 0x28, 0x28, /* det rssi, med busy offsets */ - 7, /* det sync thresh */ - 0, 2, 2, /* test mode, min, max */ - 0, /* allow broadcast SSID probe resp */ - 0, 0, /* privacy must start, can join */ - 2, 0, 0, 0, 0, 0, 0, 0 /* basic rate set */ -}; - -static const UCHAR b4_default_startup_parms[] = { - 0, 0, /* Adhoc station */ - 'L', 'I', 'N', 'U', 'X', 0, 0, 0, /* 32 char ESSID */ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 1, 0, /* Active scan, CA Mode */ - 0, 0, 0, 0, 0, 0, /* No default MAC addr */ - 0x7f, 0xff, /* Frag threshold */ - 0x02, 0x00, /* Hop time */ - 0x00, 0x01, /* Beacon period */ - 0x01, 0x07, 0xa3, /* DTIM, retries, ack timeout */ - 0x1d, 0x82, 0xce, /* SIFS, DIFS, PIFS */ - 0x7f, 0xff, /* RTS threshold */ - 0xfb, 0x1e, 0xc7, 0x5c, /* scan_dwell, max_scan_dwell */ - 0x05, /* assoc resp timeout thresh */ - 0x04, 0x02, 0x4, /* adhoc, infra, super cycle max */ - 0, /* Promiscuous mode */ - 0x0c, 0x0bd, /* Unique word */ - 0x4e, /* Slot time (TBD seems wrong) */ - 0xff, 0xff, /* roam-low snr, low snr count */ - 0x05, 0xff, /* Infra, adhoc missed bcn thresh */ - 0x01, 0x0b, 0x4e, /* USA, hop pattern, hop pat length */ -/* b4 - b5 differences start here */ - 0x3f, 0x0f, /* CW max, min */ - 0x04, 0x08, /* Noise gain, limit offset */ - 0x28, 0x28, /* det rssi, med busy offsets */ - 7, /* det sync thresh */ - 0, 2, 2, /* test mode, min, max */ - 0, /* rx/tx delay */ - 0, 0, 0, 0, 0, 0, /* current BSS id */ - 0 /* hop set */ -}; - -/*===========================================================================*/ -static const u8 eth2_llc[] = { 0xaa, 0xaa, 3, 0, 0, 0 }; - -static const char hop_pattern_length[] = { 1, - USA_HOP_MOD, EUROPE_HOP_MOD, - JAPAN_HOP_MOD, KOREA_HOP_MOD, - SPAIN_HOP_MOD, FRANCE_HOP_MOD, - ISRAEL_HOP_MOD, AUSTRALIA_HOP_MOD, - JAPAN_TEST_HOP_MOD -}; - -static const char rcsid[] = - "Raylink/WebGear wireless LAN - Corey "; - -static const struct net_device_ops ray_netdev_ops = { - .ndo_init = ray_dev_init, - .ndo_open = ray_open, - .ndo_stop = ray_dev_close, - .ndo_start_xmit = ray_dev_start_xmit, - .ndo_set_config = ray_dev_config, - .ndo_get_stats = ray_get_stats, - .ndo_set_rx_mode = set_multicast_list, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -static int ray_probe(struct pcmcia_device *p_dev) -{ - ray_dev_t *local; - struct net_device *dev; - int ret; - - dev_dbg(&p_dev->dev, "ray_attach()\n"); - - /* Allocate space for private device-specific data */ - dev = alloc_etherdev(sizeof(ray_dev_t)); - if (!dev) - return -ENOMEM; - - local = netdev_priv(dev); - local->finder = p_dev; - - /* The io structure describes IO port mapping. None used here */ - p_dev->resource[0]->end = 0; - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - - /* General socket configuration */ - p_dev->config_flags |= CONF_ENABLE_IRQ; - p_dev->config_index = 1; - - p_dev->priv = dev; - - local->finder = p_dev; - local->card_status = CARD_INSERTED; - local->authentication_state = UNAUTHENTICATED; - local->num_multi = 0; - dev_dbg(&p_dev->dev, "ray_attach p_dev = %p, dev = %p, local = %p, intr = %p\n", - p_dev, dev, local, &ray_interrupt); - - /* Raylink entries in the device structure */ - dev->netdev_ops = &ray_netdev_ops; - dev->wireless_handlers = &ray_handler_def; -#ifdef WIRELESS_SPY - local->wireless_data.spy_data = &local->spy_data; - dev->wireless_data = &local->wireless_data; -#endif /* WIRELESS_SPY */ - - - dev_dbg(&p_dev->dev, "ray_cs ray_attach calling ether_setup.)\n"); - netif_stop_queue(dev); - - timer_setup(&local->timer, NULL, 0); - - this_device = p_dev; - ret = ray_config(p_dev); - if (ret) - goto err_free_dev; - - return 0; - -err_free_dev: - free_netdev(dev); - return ret; -} - -static void ray_detach(struct pcmcia_device *link) -{ - struct net_device *dev; - - dev_dbg(&link->dev, "ray_detach\n"); - - this_device = NULL; - dev = link->priv; - - ray_release(link); - - if (link->priv) { - unregister_netdev(dev); - free_netdev(dev); - } - dev_dbg(&link->dev, "ray_cs ray_detach ending\n"); -} /* ray_detach */ - -#define MAX_TUPLE_SIZE 128 -static int ray_config(struct pcmcia_device *link) -{ - int ret = 0; - int i; - struct net_device *dev = link->priv; - ray_dev_t *local = netdev_priv(dev); - - dev_dbg(&link->dev, "ray_config\n"); - - /* Determine card type and firmware version */ - printk(KERN_INFO "ray_cs Detected: %s%s%s%s\n", - link->prod_id[0] ? link->prod_id[0] : " ", - link->prod_id[1] ? link->prod_id[1] : " ", - link->prod_id[2] ? link->prod_id[2] : " ", - link->prod_id[3] ? link->prod_id[3] : " "); - - /* Now allocate an interrupt line. Note that this does not - actually assign a handler to the interrupt. - */ - ret = pcmcia_request_irq(link, ray_interrupt); - if (ret) - goto failed; - dev->irq = link->irq; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - -/*** Set up 32k window for shared memory (transmit and control) ************/ - link->resource[2]->flags |= WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT; - link->resource[2]->start = 0; - link->resource[2]->end = 0x8000; - ret = pcmcia_request_window(link, link->resource[2], ray_mem_speed); - if (ret) - goto failed; - ret = pcmcia_map_mem_page(link, link->resource[2], 0); - if (ret) - goto failed; - local->sram = ioremap(link->resource[2]->start, - resource_size(link->resource[2])); - if (!local->sram) - goto failed; - -/*** Set up 16k window for shared memory (receive buffer) ***************/ - link->resource[3]->flags |= - WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT; - link->resource[3]->start = 0; - link->resource[3]->end = 0x4000; - ret = pcmcia_request_window(link, link->resource[3], ray_mem_speed); - if (ret) - goto failed; - ret = pcmcia_map_mem_page(link, link->resource[3], 0x8000); - if (ret) - goto failed; - local->rmem = ioremap(link->resource[3]->start, - resource_size(link->resource[3])); - if (!local->rmem) - goto failed; - -/*** Set up window for attribute memory ***********************************/ - link->resource[4]->flags |= - WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_AM | WIN_ENABLE | WIN_USE_WAIT; - link->resource[4]->start = 0; - link->resource[4]->end = 0x1000; - ret = pcmcia_request_window(link, link->resource[4], ray_mem_speed); - if (ret) - goto failed; - ret = pcmcia_map_mem_page(link, link->resource[4], 0); - if (ret) - goto failed; - local->amem = ioremap(link->resource[4]->start, - resource_size(link->resource[4])); - if (!local->amem) - goto failed; - - dev_dbg(&link->dev, "ray_config sram=%p\n", local->sram); - dev_dbg(&link->dev, "ray_config rmem=%p\n", local->rmem); - dev_dbg(&link->dev, "ray_config amem=%p\n", local->amem); - if (ray_init(dev) < 0) { - ray_release(link); - return -ENODEV; - } - - SET_NETDEV_DEV(dev, &link->dev); - i = register_netdev(dev); - if (i != 0) { - printk("ray_config register_netdev() failed\n"); - ray_release(link); - return i; - } - - printk(KERN_INFO "%s: RayLink, irq %d, hw_addr %pM\n", - dev->name, dev->irq, dev->dev_addr); - - return 0; - -failed: - ray_release(link); - return -ENODEV; -} /* ray_config */ - -static inline struct ccs __iomem *ccs_base(ray_dev_t *dev) -{ - return dev->sram + CCS_BASE; -} - -static inline struct rcs __iomem *rcs_base(ray_dev_t *dev) -{ - /* - * This looks nonsensical, since there is a separate - * RCS_BASE. But the difference between a "struct rcs" - * and a "struct ccs" ends up being in the _index_ off - * the base, so the base pointer is the same for both - * ccs/rcs. - */ - return dev->sram + CCS_BASE; -} - -/*===========================================================================*/ -static int ray_init(struct net_device *dev) -{ - int i; - struct ccs __iomem *pccs; - ray_dev_t *local = netdev_priv(dev); - struct pcmcia_device *link = local->finder; - dev_dbg(&link->dev, "ray_init(0x%p)\n", dev); - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_init - device not present\n"); - return -1; - } - - local->net_type = net_type; - local->sta_type = TYPE_STA; - - /* Copy the startup results to local memory */ - memcpy_fromio(&local->startup_res, local->sram + ECF_TO_HOST_BASE, - sizeof(struct startup_res_6)); - - /* Check Power up test status and get mac address from card */ - if (local->startup_res.startup_word != 0x80) { - printk(KERN_INFO "ray_init ERROR card status = %2x\n", - local->startup_res.startup_word); - local->card_status = CARD_INIT_ERROR; - return -1; - } - - local->fw_ver = local->startup_res.firmware_version[0]; - local->fw_bld = local->startup_res.firmware_version[1]; - local->fw_var = local->startup_res.firmware_version[2]; - dev_dbg(&link->dev, "ray_init firmware version %d.%d\n", local->fw_ver, - local->fw_bld); - - local->tib_length = 0x20; - if ((local->fw_ver == 5) && (local->fw_bld >= 30)) - local->tib_length = local->startup_res.tib_length; - dev_dbg(&link->dev, "ray_init tib_length = 0x%02x\n", local->tib_length); - /* Initialize CCS's to buffer free state */ - pccs = ccs_base(local); - for (i = 0; i < NUMBER_OF_CCS; i++) { - writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); - } - init_startup_params(local); - - /* copy mac address to startup parameters */ - if (!parse_addr(phy_addr, local->sparm.b4.a_mac_addr)) { - memcpy(&local->sparm.b4.a_mac_addr, - &local->startup_res.station_addr, ADDRLEN); - } - - clear_interrupt(local); /* Clear any interrupt from the card */ - local->card_status = CARD_AWAITING_PARAM; - dev_dbg(&link->dev, "ray_init ending\n"); - return 0; -} /* ray_init */ - -/*===========================================================================*/ -/* Download startup parameters to the card and command it to read them */ -static int dl_startup_params(struct net_device *dev) -{ - int ccsindex; - ray_dev_t *local = netdev_priv(dev); - struct ccs __iomem *pccs; - struct pcmcia_device *link = local->finder; - - dev_dbg(&link->dev, "dl_startup_params entered\n"); - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_cs dl_startup_params - device not present\n"); - return -1; - } - - /* Copy parameters to host to ECF area */ - if (local->fw_ver == 0x55) - memcpy_toio(local->sram + HOST_TO_ECF_BASE, &local->sparm.b4, - sizeof(struct b4_startup_params)); - else - memcpy_toio(local->sram + HOST_TO_ECF_BASE, &local->sparm.b5, - sizeof(struct b5_startup_params)); - - /* Fill in the CCS fields for the ECF */ - if ((ccsindex = get_free_ccs(local)) < 0) - return -1; - local->dl_param_ccs = ccsindex; - pccs = ccs_base(local) + ccsindex; - writeb(CCS_DOWNLOAD_STARTUP_PARAMS, &pccs->cmd); - dev_dbg(&link->dev, "dl_startup_params start ccsindex = %d\n", - local->dl_param_ccs); - /* Interrupt the firmware to process the command */ - if (interrupt_ecf(local, ccsindex)) { - printk(KERN_INFO "ray dl_startup_params failed - " - "ECF not ready for intr\n"); - local->card_status = CARD_DL_PARAM_ERROR; - writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); - return -2; - } - local->card_status = CARD_DL_PARAM; - /* Start kernel timer to wait for dl startup to complete. */ - local->timer.expires = jiffies + HZ / 2; - local->timer.function = verify_dl_startup; - add_timer(&local->timer); - dev_dbg(&link->dev, - "ray_cs dl_startup_params started timer for verify_dl_startup\n"); - return 0; -} /* dl_startup_params */ - -/*===========================================================================*/ -static void init_startup_params(ray_dev_t *local) -{ - int i; - - if (country > JAPAN_TEST) - country = USA; - else if (country < USA) - country = USA; - /* structure for hop time and beacon period is defined here using - * New 802.11D6.1 format. Card firmware is still using old format - * until version 6. - * Before After - * a_hop_time ms byte a_hop_time ms byte - * a_hop_time 2s byte a_hop_time ls byte - * a_hop_time ls byte a_beacon_period ms byte - * a_beacon_period a_beacon_period ls byte - * - * a_hop_time = uS a_hop_time = KuS - * a_beacon_period = hops a_beacon_period = KuS - *//* 64ms = 010000 */ - if (local->fw_ver == 0x55) { - memcpy(&local->sparm.b4, b4_default_startup_parms, - sizeof(struct b4_startup_params)); - /* Translate sane kus input values to old build 4/5 format */ - /* i = hop time in uS truncated to 3 bytes */ - i = (hop_dwell * 1024) & 0xffffff; - local->sparm.b4.a_hop_time[0] = (i >> 16) & 0xff; - local->sparm.b4.a_hop_time[1] = (i >> 8) & 0xff; - local->sparm.b4.a_beacon_period[0] = 0; - local->sparm.b4.a_beacon_period[1] = - ((beacon_period / hop_dwell) - 1) & 0xff; - local->sparm.b4.a_curr_country_code = country; - local->sparm.b4.a_hop_pattern_length = - hop_pattern_length[(int)country] - 1; - if (bc) { - local->sparm.b4.a_ack_timeout = 0x50; - local->sparm.b4.a_sifs = 0x3f; - } - } else { /* Version 5 uses real kus values */ - memcpy((UCHAR *) &local->sparm.b5, b5_default_startup_parms, - sizeof(struct b5_startup_params)); - - local->sparm.b5.a_hop_time[0] = (hop_dwell >> 8) & 0xff; - local->sparm.b5.a_hop_time[1] = hop_dwell & 0xff; - local->sparm.b5.a_beacon_period[0] = - (beacon_period >> 8) & 0xff; - local->sparm.b5.a_beacon_period[1] = beacon_period & 0xff; - if (psm) - local->sparm.b5.a_power_mgt_state = 1; - local->sparm.b5.a_curr_country_code = country; - local->sparm.b5.a_hop_pattern_length = - hop_pattern_length[(int)country]; - } - - local->sparm.b4.a_network_type = net_type & 0x01; - local->sparm.b4.a_acting_as_ap_status = TYPE_STA; - - if (essid != NULL) - strscpy(local->sparm.b4.a_current_ess_id, essid, ESSID_SIZE); -} /* init_startup_params */ - -/*===========================================================================*/ -static void verify_dl_startup(struct timer_list *t) -{ - ray_dev_t *local = from_timer(local, t, timer); - struct ccs __iomem *pccs = ccs_base(local) + local->dl_param_ccs; - UCHAR status; - struct pcmcia_device *link = local->finder; - - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_cs verify_dl_startup - device not present\n"); - return; - } -#if 0 - { - int i; - printk(KERN_DEBUG - "verify_dl_startup parameters sent via ccs %d:\n", - local->dl_param_ccs); - for (i = 0; i < sizeof(struct b5_startup_params); i++) { - printk(" %2x", - (unsigned int)readb(local->sram + - HOST_TO_ECF_BASE + i)); - } - printk("\n"); - } -#endif - - status = readb(&pccs->buffer_status); - if (status != CCS_BUFFER_FREE) { - printk(KERN_INFO - "Download startup params failed. Status = %d\n", - status); - local->card_status = CARD_DL_PARAM_ERROR; - return; - } - if (local->sparm.b4.a_network_type == ADHOC) - start_net(&local->timer); - else - join_net(&local->timer); -} /* end verify_dl_startup */ - -/*===========================================================================*/ -/* Command card to start a network */ -static void start_net(struct timer_list *t) -{ - ray_dev_t *local = from_timer(local, t, timer); - struct ccs __iomem *pccs; - int ccsindex; - struct pcmcia_device *link = local->finder; - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_cs start_net - device not present\n"); - return; - } - /* Fill in the CCS fields for the ECF */ - if ((ccsindex = get_free_ccs(local)) < 0) - return; - pccs = ccs_base(local) + ccsindex; - writeb(CCS_START_NETWORK, &pccs->cmd); - writeb(0, &pccs->var.start_network.update_param); - /* Interrupt the firmware to process the command */ - if (interrupt_ecf(local, ccsindex)) { - dev_dbg(&link->dev, "ray start net failed - card not ready for intr\n"); - writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); - return; - } - local->card_status = CARD_DOING_ACQ; -} /* end start_net */ - -/*===========================================================================*/ -/* Command card to join a network */ -static void join_net(struct timer_list *t) -{ - ray_dev_t *local = from_timer(local, t, timer); - - struct ccs __iomem *pccs; - int ccsindex; - struct pcmcia_device *link = local->finder; - - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_cs join_net - device not present\n"); - return; - } - /* Fill in the CCS fields for the ECF */ - if ((ccsindex = get_free_ccs(local)) < 0) - return; - pccs = ccs_base(local) + ccsindex; - writeb(CCS_JOIN_NETWORK, &pccs->cmd); - writeb(0, &pccs->var.join_network.update_param); - writeb(0, &pccs->var.join_network.net_initiated); - /* Interrupt the firmware to process the command */ - if (interrupt_ecf(local, ccsindex)) { - dev_dbg(&link->dev, "ray join net failed - card not ready for intr\n"); - writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); - return; - } - local->card_status = CARD_DOING_ACQ; -} - - -static void ray_release(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - ray_dev_t *local = netdev_priv(dev); - - dev_dbg(&link->dev, "ray_release\n"); - - del_timer_sync(&local->timer); - - if (local->sram) - iounmap(local->sram); - if (local->rmem) - iounmap(local->rmem); - if (local->amem) - iounmap(local->amem); - pcmcia_disable_device(link); - - dev_dbg(&link->dev, "ray_release ending\n"); -} - -static int ray_suspend(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - if (link->open) - netif_device_detach(dev); - - return 0; -} - -static int ray_resume(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - if (link->open) { - ray_reset(dev); - netif_device_attach(dev); - } - - return 0; -} - -/*===========================================================================*/ -static int ray_dev_init(struct net_device *dev) -{ -#ifdef RAY_IMMEDIATE_INIT - int i; -#endif /* RAY_IMMEDIATE_INIT */ - ray_dev_t *local = netdev_priv(dev); - struct pcmcia_device *link = local->finder; - - dev_dbg(&link->dev, "ray_dev_init(dev=%p)\n", dev); - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_dev_init - device not present\n"); - return -1; - } -#ifdef RAY_IMMEDIATE_INIT - /* Download startup parameters */ - if ((i = dl_startup_params(dev)) < 0) { - printk(KERN_INFO "ray_dev_init dl_startup_params failed - " - "returns 0x%x\n", i); - return -1; - } -#else /* RAY_IMMEDIATE_INIT */ - /* Postpone the card init so that we can still configure the card, - * for example using the Wireless Extensions. The init will happen - * in ray_open() - Jean II */ - dev_dbg(&link->dev, - "ray_dev_init: postponing card init to ray_open() ; Status = %d\n", - local->card_status); -#endif /* RAY_IMMEDIATE_INIT */ - - /* copy mac and broadcast addresses to linux device */ - eth_hw_addr_set(dev, local->sparm.b4.a_mac_addr); - eth_broadcast_addr(dev->broadcast); - - dev_dbg(&link->dev, "ray_dev_init ending\n"); - return 0; -} - -/*===========================================================================*/ -static int ray_dev_config(struct net_device *dev, struct ifmap *map) -{ - ray_dev_t *local = netdev_priv(dev); - struct pcmcia_device *link = local->finder; - /* Dummy routine to satisfy device structure */ - dev_dbg(&link->dev, "ray_dev_config(dev=%p,ifmap=%p)\n", dev, map); - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_dev_config - device not present\n"); - return -1; - } - - return 0; -} - -/*===========================================================================*/ -static netdev_tx_t ray_dev_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - ray_dev_t *local = netdev_priv(dev); - struct pcmcia_device *link = local->finder; - short length = skb->len; - - if (!pcmcia_dev_present(link)) { - dev_dbg(&link->dev, "ray_dev_start_xmit - device not present\n"); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - - dev_dbg(&link->dev, "ray_dev_start_xmit(skb=%p, dev=%p)\n", skb, dev); - if (local->authentication_state == NEED_TO_AUTH) { - dev_dbg(&link->dev, "ray_cs Sending authentication request.\n"); - if (!build_auth_frame(local, local->auth_id, OPEN_AUTH_REQUEST)) { - local->authentication_state = AUTHENTICATED; - netif_stop_queue(dev); - return NETDEV_TX_BUSY; - } - } - - if (length < ETH_ZLEN) { - if (skb_padto(skb, ETH_ZLEN)) - return NETDEV_TX_OK; - length = ETH_ZLEN; - } - switch (ray_hw_xmit(skb->data, length, dev, DATA_TYPE)) { - case XMIT_NO_CCS: - case XMIT_NEED_AUTH: - netif_stop_queue(dev); - return NETDEV_TX_BUSY; - case XMIT_NO_INTR: - case XMIT_MSG_BAD: - case XMIT_OK: - default: - dev_kfree_skb(skb); - } - - return NETDEV_TX_OK; -} /* ray_dev_start_xmit */ - -/*===========================================================================*/ -static int ray_hw_xmit(unsigned char *data, int len, struct net_device *dev, - UCHAR msg_type) -{ - ray_dev_t *local = netdev_priv(dev); - struct ccs __iomem *pccs; - int ccsindex; - int offset; - struct tx_msg __iomem *ptx; /* Address of xmit buffer in PC space */ - short int addr; /* Address of xmit buffer in card space */ - - pr_debug("ray_hw_xmit(data=%p, len=%d, dev=%p)\n", data, len, dev); - if (len + TX_HEADER_LENGTH > TX_BUF_SIZE) { - printk(KERN_INFO "ray_hw_xmit packet too large: %d bytes\n", - len); - return XMIT_MSG_BAD; - } - switch (ccsindex = get_free_tx_ccs(local)) { - case ECCSBUSY: - pr_debug("ray_hw_xmit tx_ccs table busy\n"); - fallthrough; - case ECCSFULL: - pr_debug("ray_hw_xmit No free tx ccs\n"); - fallthrough; - case ECARDGONE: - netif_stop_queue(dev); - return XMIT_NO_CCS; - default: - break; - } - addr = TX_BUF_BASE + (ccsindex << 11); - - if (msg_type == DATA_TYPE) { - local->stats.tx_bytes += len; - local->stats.tx_packets++; - } - - ptx = local->sram + addr; - - ray_build_header(local, ptx, msg_type, data); - if (translate) { - offset = translate_frame(local, ptx, data, len); - } else { /* Encapsulate frame */ - /* TBD TIB length will move address of ptx->var */ - memcpy_toio(&ptx->var, data, len); - offset = 0; - } - - /* fill in the CCS */ - pccs = ccs_base(local) + ccsindex; - len += TX_HEADER_LENGTH + offset; - writeb(CCS_TX_REQUEST, &pccs->cmd); - writeb(addr >> 8, &pccs->var.tx_request.tx_data_ptr[0]); - writeb(local->tib_length, &pccs->var.tx_request.tx_data_ptr[1]); - writeb(len >> 8, &pccs->var.tx_request.tx_data_length[0]); - writeb(len & 0xff, &pccs->var.tx_request.tx_data_length[1]); -/* TBD still need psm_cam? */ - writeb(PSM_CAM, &pccs->var.tx_request.pow_sav_mode); - writeb(local->net_default_tx_rate, &pccs->var.tx_request.tx_rate); - writeb(0, &pccs->var.tx_request.antenna); - pr_debug("ray_hw_xmit default_tx_rate = 0x%x\n", - local->net_default_tx_rate); - - /* Interrupt the firmware to process the command */ - if (interrupt_ecf(local, ccsindex)) { - pr_debug("ray_hw_xmit failed - ECF not ready for intr\n"); -/* TBD very inefficient to copy packet to buffer, and then not - send it, but the alternative is to queue the messages and that - won't be done for a while. Maybe set tbusy until a CCS is free? -*/ - writeb(CCS_BUFFER_FREE, &pccs->buffer_status); - return XMIT_NO_INTR; - } - return XMIT_OK; -} /* end ray_hw_xmit */ - -/*===========================================================================*/ -static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx, - unsigned char *data, int len) -{ - __be16 proto = ((struct ethhdr *)data)->h_proto; - if (ntohs(proto) >= ETH_P_802_3_MIN) { /* DIX II ethernet frame */ - pr_debug("ray_cs translate_frame DIX II\n"); - /* Copy LLC header to card buffer */ - memcpy_toio(&ptx->var, eth2_llc, sizeof(eth2_llc)); - memcpy_toio(((void __iomem *)&ptx->var) + sizeof(eth2_llc), - (UCHAR *) &proto, 2); - if (proto == htons(ETH_P_AARP) || proto == htons(ETH_P_IPX)) { - /* This is the selective translation table, only 2 entries */ - writeb(0xf8, - &((struct snaphdr_t __iomem *)ptx->var)->org[2]); - } - /* Copy body of ethernet packet without ethernet header */ - memcpy_toio((void __iomem *)&ptx->var + - sizeof(struct snaphdr_t), data + ETH_HLEN, - len - ETH_HLEN); - return (int)sizeof(struct snaphdr_t) - ETH_HLEN; - } else { /* already 802 type, and proto is length */ - pr_debug("ray_cs translate_frame 802\n"); - if (proto == htons(0xffff)) { /* evil netware IPX 802.3 without LLC */ - pr_debug("ray_cs translate_frame evil IPX\n"); - memcpy_toio(&ptx->var, data + ETH_HLEN, len - ETH_HLEN); - return 0 - ETH_HLEN; - } - memcpy_toio(&ptx->var, data + ETH_HLEN, len - ETH_HLEN); - return 0 - ETH_HLEN; - } - /* TBD do other frame types */ -} /* end translate_frame */ - -/*===========================================================================*/ -static void ray_build_header(ray_dev_t *local, struct tx_msg __iomem *ptx, - UCHAR msg_type, unsigned char *data) -{ - writeb(PROTOCOL_VER | msg_type, &ptx->mac.frame_ctl_1); -/*** IEEE 802.11 Address field assignments ************* - TODS FROMDS addr_1 addr_2 addr_3 addr_4 -Adhoc 0 0 dest src (terminal) BSSID N/A -AP to Terminal 0 1 dest AP(BSSID) source N/A -Terminal to AP 1 0 AP(BSSID) src (terminal) dest N/A -AP to AP 1 1 dest AP src AP dest source -*******************************************************/ - if (local->net_type == ADHOC) { - writeb(0, &ptx->mac.frame_ctl_2); - memcpy_toio(ptx->mac.addr_1, ((struct ethhdr *)data)->h_dest, - ADDRLEN); - memcpy_toio(ptx->mac.addr_2, ((struct ethhdr *)data)->h_source, - ADDRLEN); - memcpy_toio(ptx->mac.addr_3, local->bss_id, ADDRLEN); - } else { /* infrastructure */ - - if (local->sparm.b4.a_acting_as_ap_status) { - writeb(FC2_FROM_DS, &ptx->mac.frame_ctl_2); - memcpy_toio(ptx->mac.addr_1, - ((struct ethhdr *)data)->h_dest, ADDRLEN); - memcpy_toio(ptx->mac.addr_2, local->bss_id, 6); - memcpy_toio(ptx->mac.addr_3, - ((struct ethhdr *)data)->h_source, ADDRLEN); - } else { /* Terminal */ - - writeb(FC2_TO_DS, &ptx->mac.frame_ctl_2); - memcpy_toio(ptx->mac.addr_1, local->bss_id, ADDRLEN); - memcpy_toio(ptx->mac.addr_2, - ((struct ethhdr *)data)->h_source, ADDRLEN); - memcpy_toio(ptx->mac.addr_3, - ((struct ethhdr *)data)->h_dest, ADDRLEN); - } - } -} /* end encapsulate_frame */ - -/*====================================================================*/ - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get protocol name - */ -static int ray_get_name(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - strcpy(wrqu->name, "IEEE 802.11-FH"); - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set frequency - */ -static int ray_set_freq(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - int err = -EINPROGRESS; /* Call commit handler */ - - /* Reject if card is already initialised */ - if (local->card_status != CARD_AWAITING_PARAM) - return -EBUSY; - - /* Setting by channel number */ - if ((wrqu->freq.m > USA_HOP_MOD) || (wrqu->freq.e > 0)) - err = -EOPNOTSUPP; - else - local->sparm.b5.a_hop_pattern = wrqu->freq.m; - - return err; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get frequency - */ -static int ray_get_freq(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - - wrqu->freq.m = local->sparm.b5.a_hop_pattern; - wrqu->freq.e = 0; - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set ESSID - */ -static int ray_set_essid(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - - /* Reject if card is already initialised */ - if (local->card_status != CARD_AWAITING_PARAM) - return -EBUSY; - - /* Check if we asked for `any' */ - if (wrqu->essid.flags == 0) - /* Corey : can you do that ? */ - return -EOPNOTSUPP; - - /* Check the size of the string */ - if (wrqu->essid.length > IW_ESSID_MAX_SIZE) - return -E2BIG; - - /* Set the ESSID in the card */ - memset(local->sparm.b5.a_current_ess_id, 0, IW_ESSID_MAX_SIZE); - memcpy(local->sparm.b5.a_current_ess_id, extra, wrqu->essid.length); - - return -EINPROGRESS; /* Call commit handler */ -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get ESSID - */ -static int ray_get_essid(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - UCHAR tmp[IW_ESSID_MAX_SIZE + 1]; - - /* Get the essid that was set */ - memcpy(extra, local->sparm.b5.a_current_ess_id, IW_ESSID_MAX_SIZE); - memcpy(tmp, local->sparm.b5.a_current_ess_id, IW_ESSID_MAX_SIZE); - tmp[IW_ESSID_MAX_SIZE] = '\0'; - - /* Push it out ! */ - wrqu->essid.length = strlen(tmp); - wrqu->essid.flags = 1; /* active */ - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get AP address - */ -static int ray_get_wap(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - - memcpy(wrqu->ap_addr.sa_data, local->bss_id, ETH_ALEN); - wrqu->ap_addr.sa_family = ARPHRD_ETHER; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Bit-Rate - */ -static int ray_set_rate(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - - /* Reject if card is already initialised */ - if (local->card_status != CARD_AWAITING_PARAM) - return -EBUSY; - - /* Check if rate is in range */ - if ((wrqu->bitrate.value != 1000000) && (wrqu->bitrate.value != 2000000)) - return -EINVAL; - - /* Hack for 1.5 Mb/s instead of 2 Mb/s */ - if ((local->fw_ver == 0x55) && /* Please check */ - (wrqu->bitrate.value == 2000000)) - local->net_default_tx_rate = 3; - else - local->net_default_tx_rate = wrqu->bitrate.value / 500000; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Bit-Rate - */ -static int ray_get_rate(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - - if (local->net_default_tx_rate == 3) - wrqu->bitrate.value = 2000000; /* Hum... */ - else - wrqu->bitrate.value = local->net_default_tx_rate * 500000; - wrqu->bitrate.fixed = 0; /* We are in auto mode */ - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set RTS threshold - */ -static int ray_set_rts(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - int rthr = wrqu->rts.value; - - /* Reject if card is already initialised */ - if (local->card_status != CARD_AWAITING_PARAM) - return -EBUSY; - - /* if(wrq->u.rts.fixed == 0) we should complain */ - if (wrqu->rts.disabled) - rthr = 32767; - else { - if ((rthr < 0) || (rthr > 2347)) /* What's the max packet size ??? */ - return -EINVAL; - } - local->sparm.b5.a_rts_threshold[0] = (rthr >> 8) & 0xFF; - local->sparm.b5.a_rts_threshold[1] = rthr & 0xFF; - - return -EINPROGRESS; /* Call commit handler */ -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get RTS threshold - */ -static int ray_get_rts(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - - wrqu->rts.value = (local->sparm.b5.a_rts_threshold[0] << 8) - + local->sparm.b5.a_rts_threshold[1]; - wrqu->rts.disabled = (wrqu->rts.value == 32767); - wrqu->rts.fixed = 1; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Fragmentation threshold - */ -static int ray_set_frag(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - int fthr = wrqu->frag.value; - - /* Reject if card is already initialised */ - if (local->card_status != CARD_AWAITING_PARAM) - return -EBUSY; - - /* if(wrq->u.frag.fixed == 0) should complain */ - if (wrqu->frag.disabled) - fthr = 32767; - else { - if ((fthr < 256) || (fthr > 2347)) /* To check out ! */ - return -EINVAL; - } - local->sparm.b5.a_frag_threshold[0] = (fthr >> 8) & 0xFF; - local->sparm.b5.a_frag_threshold[1] = fthr & 0xFF; - - return -EINPROGRESS; /* Call commit handler */ -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Fragmentation threshold - */ -static int ray_get_frag(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - - wrqu->frag.value = (local->sparm.b5.a_frag_threshold[0] << 8) - + local->sparm.b5.a_frag_threshold[1]; - wrqu->frag.disabled = (wrqu->frag.value == 32767); - wrqu->frag.fixed = 1; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Mode of Operation - */ -static int ray_set_mode(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - int err = -EINPROGRESS; /* Call commit handler */ - char card_mode = 1; - - /* Reject if card is already initialised */ - if (local->card_status != CARD_AWAITING_PARAM) - return -EBUSY; - - switch (wrqu->mode) { - case IW_MODE_ADHOC: - card_mode = 0; - fallthrough; - case IW_MODE_INFRA: - local->sparm.b5.a_network_type = card_mode; - break; - default: - err = -EINVAL; - } - - return err; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Mode of Operation - */ -static int ray_get_mode(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - - if (local->sparm.b5.a_network_type) - wrqu->mode = IW_MODE_INFRA; - else - wrqu->mode = IW_MODE_ADHOC; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get range info - */ -static int ray_get_range(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_range *range = (struct iw_range *)extra; - - memset(range, 0, sizeof(struct iw_range)); - - /* Set the length (very important for backward compatibility) */ - wrqu->data.length = sizeof(struct iw_range); - - /* Set the Wireless Extension versions */ - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 9; - - /* Set information in the range struct */ - range->throughput = 1.1 * 1000 * 1000; /* Put the right number here */ - range->num_channels = hop_pattern_length[(int)country]; - range->num_frequency = 0; - range->max_qual.qual = 0; - range->max_qual.level = 255; /* What's the correct value ? */ - range->max_qual.noise = 255; /* Idem */ - range->num_bitrates = 2; - range->bitrate[0] = 1000000; /* 1 Mb/s */ - range->bitrate[1] = 2000000; /* 2 Mb/s */ - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Private Handler : set framing mode - */ -static int ray_set_framing(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - translate = !!*(extra); /* Set framing mode */ - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Private Handler : get framing mode - */ -static int ray_get_framing(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - *(extra) = translate; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Private Handler : get country - */ -static int ray_get_country(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - *(extra) = country; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Commit handler : called after a bunch of SET operations - */ -static int ray_commit(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Stats handler : return Wireless Stats - */ -static iw_stats *ray_get_wireless_stats(struct net_device *dev) -{ - ray_dev_t *local = netdev_priv(dev); - struct pcmcia_device *link = local->finder; - struct status __iomem *p = local->sram + STATUS_BASE; - - local->wstats.status = local->card_status; -#ifdef WIRELESS_SPY - if ((local->spy_data.spy_number > 0) - && (local->sparm.b5.a_network_type == 0)) { - /* Get it from the first node in spy list */ - local->wstats.qual.qual = local->spy_data.spy_stat[0].qual; - local->wstats.qual.level = local->spy_data.spy_stat[0].level; - local->wstats.qual.noise = local->spy_data.spy_stat[0].noise; - local->wstats.qual.updated = - local->spy_data.spy_stat[0].updated; - } -#endif /* WIRELESS_SPY */ - - if (pcmcia_dev_present(link)) { - local->wstats.qual.noise = readb(&p->rxnoise); - local->wstats.qual.updated |= 4; - } - - return &local->wstats; -} /* end ray_get_wireless_stats */ - -/*------------------------------------------------------------------*/ -/* - * Structures to export the Wireless Handlers - */ - -static const iw_handler ray_handler[] = { - IW_HANDLER(SIOCSIWCOMMIT, ray_commit), - IW_HANDLER(SIOCGIWNAME, ray_get_name), - IW_HANDLER(SIOCSIWFREQ, ray_set_freq), - IW_HANDLER(SIOCGIWFREQ, ray_get_freq), - IW_HANDLER(SIOCSIWMODE, ray_set_mode), - IW_HANDLER(SIOCGIWMODE, ray_get_mode), - IW_HANDLER(SIOCGIWRANGE, ray_get_range), -#ifdef WIRELESS_SPY - IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy), - IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy), - IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy), - IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy), -#endif /* WIRELESS_SPY */ - IW_HANDLER(SIOCGIWAP, ray_get_wap), - IW_HANDLER(SIOCSIWESSID, ray_set_essid), - IW_HANDLER(SIOCGIWESSID, ray_get_essid), - IW_HANDLER(SIOCSIWRATE, ray_set_rate), - IW_HANDLER(SIOCGIWRATE, ray_get_rate), - IW_HANDLER(SIOCSIWRTS, ray_set_rts), - IW_HANDLER(SIOCGIWRTS, ray_get_rts), - IW_HANDLER(SIOCSIWFRAG, ray_set_frag), - IW_HANDLER(SIOCGIWFRAG, ray_get_frag), -}; - -#define SIOCSIPFRAMING SIOCIWFIRSTPRIV /* Set framing mode */ -#define SIOCGIPFRAMING SIOCIWFIRSTPRIV + 1 /* Get framing mode */ -#define SIOCGIPCOUNTRY SIOCIWFIRSTPRIV + 3 /* Get country code */ - -static const iw_handler ray_private_handler[] = { - [0] = ray_set_framing, - [1] = ray_get_framing, - [3] = ray_get_country, -}; - -static const struct iw_priv_args ray_private_args[] = { -/* cmd, set_args, get_args, name */ - {SIOCSIPFRAMING, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, - "set_framing"}, - {SIOCGIPFRAMING, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, - "get_framing"}, - {SIOCGIPCOUNTRY, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, - "get_country"}, -}; - -static const struct iw_handler_def ray_handler_def = { - .num_standard = ARRAY_SIZE(ray_handler), - .num_private = ARRAY_SIZE(ray_private_handler), - .num_private_args = ARRAY_SIZE(ray_private_args), - .standard = ray_handler, - .private = ray_private_handler, - .private_args = ray_private_args, - .get_wireless_stats = ray_get_wireless_stats, -}; - -/*===========================================================================*/ -static int ray_open(struct net_device *dev) -{ - ray_dev_t *local = netdev_priv(dev); - struct pcmcia_device *link; - link = local->finder; - - dev_dbg(&link->dev, "ray_open('%s')\n", dev->name); - - if (link->open == 0) - local->num_multi = 0; - link->open++; - - /* If the card is not started, time to start it ! - Jean II */ - if (local->card_status == CARD_AWAITING_PARAM) { - int i; - - dev_dbg(&link->dev, "ray_open: doing init now !\n"); - - /* Download startup parameters */ - if ((i = dl_startup_params(dev)) < 0) { - printk(KERN_INFO - "ray_dev_init dl_startup_params failed - " - "returns 0x%x\n", i); - return -1; - } - } - - if (sniffer) - netif_stop_queue(dev); - else - netif_start_queue(dev); - - dev_dbg(&link->dev, "ray_open ending\n"); - return 0; -} /* end ray_open */ - -/*===========================================================================*/ -static int ray_dev_close(struct net_device *dev) -{ - ray_dev_t *local = netdev_priv(dev); - struct pcmcia_device *link; - link = local->finder; - - dev_dbg(&link->dev, "ray_dev_close('%s')\n", dev->name); - - link->open--; - netif_stop_queue(dev); - - /* In here, we should stop the hardware (stop card from beeing active) - * and set local->card_status to CARD_AWAITING_PARAM, so that while the - * card is closed we can chage its configuration. - * Probably also need a COR reset to get sane state - Jean II */ - - return 0; -} /* end ray_dev_close */ - -/*===========================================================================*/ -static void ray_reset(struct net_device *dev) -{ - pr_debug("ray_reset entered\n"); -} - -/*===========================================================================*/ -/* Cause a firmware interrupt if it is ready for one */ -/* Return nonzero if not ready */ -static int interrupt_ecf(ray_dev_t *local, int ccs) -{ - int i = 50; - struct pcmcia_device *link = local->finder; - - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_cs interrupt_ecf - device not present\n"); - return -1; - } - dev_dbg(&link->dev, "interrupt_ecf(local=%p, ccs = 0x%x\n", local, ccs); - - while (i && - (readb(local->amem + CIS_OFFSET + ECF_INTR_OFFSET) & - ECF_INTR_SET)) - i--; - if (i == 0) { - dev_dbg(&link->dev, "ray_cs interrupt_ecf card not ready for interrupt\n"); - return -1; - } - /* Fill the mailbox, then kick the card */ - writeb(ccs, local->sram + SCB_BASE); - writeb(ECF_INTR_SET, local->amem + CIS_OFFSET + ECF_INTR_OFFSET); - return 0; -} /* interrupt_ecf */ - -/*===========================================================================*/ -/* Get next free transmit CCS */ -/* Return - index of current tx ccs */ -static int get_free_tx_ccs(ray_dev_t *local) -{ - int i; - struct ccs __iomem *pccs = ccs_base(local); - struct pcmcia_device *link = local->finder; - - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_cs get_free_tx_ccs - device not present\n"); - return ECARDGONE; - } - - if (test_and_set_bit(0, &local->tx_ccs_lock)) { - dev_dbg(&link->dev, "ray_cs tx_ccs_lock busy\n"); - return ECCSBUSY; - } - - for (i = 0; i < NUMBER_OF_TX_CCS; i++) { - if (readb(&(pccs + i)->buffer_status) == CCS_BUFFER_FREE) { - writeb(CCS_BUFFER_BUSY, &(pccs + i)->buffer_status); - writeb(CCS_END_LIST, &(pccs + i)->link); - local->tx_ccs_lock = 0; - return i; - } - } - local->tx_ccs_lock = 0; - dev_dbg(&link->dev, "ray_cs ERROR no free tx CCS for raylink card\n"); - return ECCSFULL; -} /* get_free_tx_ccs */ - -/*===========================================================================*/ -/* Get next free CCS */ -/* Return - index of current ccs */ -static int get_free_ccs(ray_dev_t *local) -{ - int i; - struct ccs __iomem *pccs = ccs_base(local); - struct pcmcia_device *link = local->finder; - - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_cs get_free_ccs - device not present\n"); - return ECARDGONE; - } - if (test_and_set_bit(0, &local->ccs_lock)) { - dev_dbg(&link->dev, "ray_cs ccs_lock busy\n"); - return ECCSBUSY; - } - - for (i = NUMBER_OF_TX_CCS; i < NUMBER_OF_CCS; i++) { - if (readb(&(pccs + i)->buffer_status) == CCS_BUFFER_FREE) { - writeb(CCS_BUFFER_BUSY, &(pccs + i)->buffer_status); - writeb(CCS_END_LIST, &(pccs + i)->link); - local->ccs_lock = 0; - return i; - } - } - local->ccs_lock = 0; - dev_dbg(&link->dev, "ray_cs ERROR no free CCS for raylink card\n"); - return ECCSFULL; -} /* get_free_ccs */ - -/*===========================================================================*/ -static void authenticate_timeout(struct timer_list *t) -{ - ray_dev_t *local = from_timer(local, t, timer); - del_timer(&local->timer); - printk(KERN_INFO "ray_cs Authentication with access point failed" - " - timeout\n"); - join_net(&local->timer); -} - -/*===========================================================================*/ -static int parse_addr(char *in_str, UCHAR *out) -{ - int i, k; - int len; - - if (in_str == NULL) - return 0; - len = strnlen(in_str, ADDRLEN * 2 + 1) - 1; - if (len < 1) - return 0; - memset(out, 0, ADDRLEN); - - i = 5; - - while (len > 0) { - if ((k = hex_to_bin(in_str[len--])) != -1) - out[i] = k; - else - return 0; - - if (len == 0) - break; - if ((k = hex_to_bin(in_str[len--])) != -1) - out[i] += k << 4; - else - return 0; - if (!i--) - break; - } - return 1; -} - -/*===========================================================================*/ -static struct net_device_stats *ray_get_stats(struct net_device *dev) -{ - ray_dev_t *local = netdev_priv(dev); - struct pcmcia_device *link = local->finder; - struct status __iomem *p = local->sram + STATUS_BASE; - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_cs net_device_stats - device not present\n"); - return &local->stats; - } - if (readb(&p->mrx_overflow_for_host)) { - local->stats.rx_over_errors += swab16(readw(&p->mrx_overflow)); - writeb(0, &p->mrx_overflow); - writeb(0, &p->mrx_overflow_for_host); - } - if (readb(&p->mrx_checksum_error_for_host)) { - local->stats.rx_crc_errors += - swab16(readw(&p->mrx_checksum_error)); - writeb(0, &p->mrx_checksum_error); - writeb(0, &p->mrx_checksum_error_for_host); - } - if (readb(&p->rx_hec_error_for_host)) { - local->stats.rx_frame_errors += swab16(readw(&p->rx_hec_error)); - writeb(0, &p->rx_hec_error); - writeb(0, &p->rx_hec_error_for_host); - } - return &local->stats; -} - -/*===========================================================================*/ -static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, - int len) -{ - ray_dev_t *local = netdev_priv(dev); - struct pcmcia_device *link = local->finder; - int ccsindex; - int i; - struct ccs __iomem *pccs; - - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_update_parm - device not present\n"); - return; - } - - if ((ccsindex = get_free_ccs(local)) < 0) { - dev_dbg(&link->dev, "ray_update_parm - No free ccs\n"); - return; - } - pccs = ccs_base(local) + ccsindex; - writeb(CCS_UPDATE_PARAMS, &pccs->cmd); - writeb(objid, &pccs->var.update_param.object_id); - writeb(1, &pccs->var.update_param.number_objects); - writeb(0, &pccs->var.update_param.failure_cause); - for (i = 0; i < len; i++) { - writeb(value[i], local->sram + HOST_TO_ECF_BASE); - } - /* Interrupt the firmware to process the command */ - if (interrupt_ecf(local, ccsindex)) { - dev_dbg(&link->dev, "ray_cs associate failed - ECF not ready for intr\n"); - writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); - } -} - -/*===========================================================================*/ -static void ray_update_multi_list(struct net_device *dev, int all) -{ - int ccsindex; - struct ccs __iomem *pccs; - ray_dev_t *local = netdev_priv(dev); - struct pcmcia_device *link = local->finder; - void __iomem *p = local->sram + HOST_TO_ECF_BASE; - - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_update_multi_list - device not present\n"); - return; - } else - dev_dbg(&link->dev, "ray_update_multi_list(%p)\n", dev); - if ((ccsindex = get_free_ccs(local)) < 0) { - dev_dbg(&link->dev, "ray_update_multi - No free ccs\n"); - return; - } - pccs = ccs_base(local) + ccsindex; - writeb(CCS_UPDATE_MULTICAST_LIST, &pccs->cmd); - - if (all) { - writeb(0xff, &pccs->var); - local->num_multi = 0xff; - } else { - struct netdev_hw_addr *ha; - int i = 0; - - /* Copy the kernel's list of MC addresses to card */ - netdev_for_each_mc_addr(ha, dev) { - memcpy_toio(p, ha->addr, ETH_ALEN); - dev_dbg(&link->dev, "ray_update_multi add addr %pm\n", - ha->addr); - p += ETH_ALEN; - i++; - } - if (i > 256 / ADDRLEN) - i = 256 / ADDRLEN; - writeb((UCHAR) i, &pccs->var); - dev_dbg(&link->dev, "ray_cs update_multi %d addresses in list\n", i); - /* Interrupt the firmware to process the command */ - local->num_multi = i; - } - if (interrupt_ecf(local, ccsindex)) { - dev_dbg(&link->dev, - "ray_cs update_multi failed - ECF not ready for intr\n"); - writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); - } -} /* end ray_update_multi_list */ - -/*===========================================================================*/ -static void set_multicast_list(struct net_device *dev) -{ - ray_dev_t *local = netdev_priv(dev); - UCHAR promisc; - - pr_debug("ray_cs set_multicast_list(%p)\n", dev); - - if (dev->flags & IFF_PROMISC) { - if (local->sparm.b5.a_promiscuous_mode == 0) { - pr_debug("ray_cs set_multicast_list promisc on\n"); - local->sparm.b5.a_promiscuous_mode = 1; - promisc = 1; - ray_update_parm(dev, OBJID_promiscuous_mode, - &promisc, sizeof(promisc)); - } - } else { - if (local->sparm.b5.a_promiscuous_mode == 1) { - pr_debug("ray_cs set_multicast_list promisc off\n"); - local->sparm.b5.a_promiscuous_mode = 0; - promisc = 0; - ray_update_parm(dev, OBJID_promiscuous_mode, - &promisc, sizeof(promisc)); - } - } - - if (dev->flags & IFF_ALLMULTI) - ray_update_multi_list(dev, 1); - else { - if (local->num_multi != netdev_mc_count(dev)) - ray_update_multi_list(dev, 0); - } -} /* end set_multicast_list */ - -/*============================================================================= - * All routines below here are run at interrupt time. -=============================================================================*/ -static irqreturn_t ray_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct pcmcia_device *link; - ray_dev_t *local; - struct ccs __iomem *pccs; - struct rcs __iomem *prcs; - UCHAR rcsindex; - UCHAR tmp; - UCHAR cmd; - UCHAR status; - UCHAR memtmp[ESSID_SIZE + 1]; - - - if (dev == NULL) /* Note that we want interrupts with dev->start == 0 */ - return IRQ_NONE; - - pr_debug("ray_cs: interrupt for *dev=%p\n", dev); - - local = netdev_priv(dev); - link = local->finder; - if (!pcmcia_dev_present(link)) { - pr_debug( - "ray_cs interrupt from device not present or suspended.\n"); - return IRQ_NONE; - } - rcsindex = readb(&((struct scb __iomem *)(local->sram))->rcs_index); - - if (rcsindex >= (NUMBER_OF_CCS + NUMBER_OF_RCS)) { - dev_dbg(&link->dev, "ray_cs interrupt bad rcsindex = 0x%x\n", rcsindex); - clear_interrupt(local); - return IRQ_HANDLED; - } - if (rcsindex < NUMBER_OF_CCS) { /* If it's a returned CCS */ - pccs = ccs_base(local) + rcsindex; - cmd = readb(&pccs->cmd); - status = readb(&pccs->buffer_status); - switch (cmd) { - case CCS_DOWNLOAD_STARTUP_PARAMS: /* Happens in firmware someday */ - del_timer(&local->timer); - if (status == CCS_COMMAND_COMPLETE) { - dev_dbg(&link->dev, - "ray_cs interrupt download_startup_parameters OK\n"); - } else { - dev_dbg(&link->dev, - "ray_cs interrupt download_startup_parameters fail\n"); - } - break; - case CCS_UPDATE_PARAMS: - dev_dbg(&link->dev, "ray_cs interrupt update params done\n"); - if (status != CCS_COMMAND_COMPLETE) { - tmp = - readb(&pccs->var.update_param. - failure_cause); - dev_dbg(&link->dev, - "ray_cs interrupt update params failed - reason %d\n", - tmp); - } - break; - case CCS_REPORT_PARAMS: - dev_dbg(&link->dev, "ray_cs interrupt report params done\n"); - break; - case CCS_UPDATE_MULTICAST_LIST: /* Note that this CCS isn't returned */ - dev_dbg(&link->dev, - "ray_cs interrupt CCS Update Multicast List done\n"); - break; - case CCS_UPDATE_POWER_SAVINGS_MODE: - dev_dbg(&link->dev, - "ray_cs interrupt update power save mode done\n"); - break; - case CCS_START_NETWORK: - case CCS_JOIN_NETWORK: - memcpy(memtmp, local->sparm.b4.a_current_ess_id, - ESSID_SIZE); - memtmp[ESSID_SIZE] = '\0'; - - if (status == CCS_COMMAND_COMPLETE) { - if (readb - (&pccs->var.start_network.net_initiated) == - 1) { - dev_dbg(&link->dev, - "ray_cs interrupt network \"%s\" started\n", - memtmp); - } else { - dev_dbg(&link->dev, - "ray_cs interrupt network \"%s\" joined\n", - memtmp); - } - memcpy_fromio(&local->bss_id, - pccs->var.start_network.bssid, - ADDRLEN); - - if (local->fw_ver == 0x55) - local->net_default_tx_rate = 3; - else - local->net_default_tx_rate = - readb(&pccs->var.start_network. - net_default_tx_rate); - local->encryption = - readb(&pccs->var.start_network.encryption); - if (!sniffer && (local->net_type == INFRA) - && !(local->sparm.b4.a_acting_as_ap_status)) { - authenticate(local); - } - local->card_status = CARD_ACQ_COMPLETE; - } else { - local->card_status = CARD_ACQ_FAILED; - - del_timer(&local->timer); - local->timer.expires = jiffies + HZ * 5; - if (status == CCS_START_NETWORK) { - dev_dbg(&link->dev, - "ray_cs interrupt network \"%s\" start failed\n", - memtmp); - local->timer.function = start_net; - } else { - dev_dbg(&link->dev, - "ray_cs interrupt network \"%s\" join failed\n", - memtmp); - local->timer.function = join_net; - } - add_timer(&local->timer); - } - break; - case CCS_START_ASSOCIATION: - if (status == CCS_COMMAND_COMPLETE) { - local->card_status = CARD_ASSOC_COMPLETE; - dev_dbg(&link->dev, "ray_cs association successful\n"); - } else { - dev_dbg(&link->dev, "ray_cs association failed,\n"); - local->card_status = CARD_ASSOC_FAILED; - join_net(&local->timer); - } - break; - case CCS_TX_REQUEST: - if (status == CCS_COMMAND_COMPLETE) { - dev_dbg(&link->dev, - "ray_cs interrupt tx request complete\n"); - } else { - dev_dbg(&link->dev, - "ray_cs interrupt tx request failed\n"); - } - if (!sniffer) - netif_start_queue(dev); - netif_wake_queue(dev); - break; - case CCS_TEST_MEMORY: - dev_dbg(&link->dev, "ray_cs interrupt mem test done\n"); - break; - case CCS_SHUTDOWN: - dev_dbg(&link->dev, - "ray_cs interrupt Unexpected CCS returned - Shutdown\n"); - break; - case CCS_DUMP_MEMORY: - dev_dbg(&link->dev, "ray_cs interrupt dump memory done\n"); - break; - case CCS_START_TIMER: - dev_dbg(&link->dev, - "ray_cs interrupt DING - raylink timer expired\n"); - break; - default: - dev_dbg(&link->dev, - "ray_cs interrupt Unexpected CCS 0x%x returned 0x%x\n", - rcsindex, cmd); - } - writeb(CCS_BUFFER_FREE, &pccs->buffer_status); - } else { /* It's an RCS */ - - prcs = rcs_base(local) + rcsindex; - - switch (readb(&prcs->interrupt_id)) { - case PROCESS_RX_PACKET: - ray_rx(dev, local, prcs); - break; - case REJOIN_NET_COMPLETE: - dev_dbg(&link->dev, "ray_cs interrupt rejoin net complete\n"); - local->card_status = CARD_ACQ_COMPLETE; - /* do we need to clear tx buffers CCS's? */ - if (local->sparm.b4.a_network_type == ADHOC) { - if (!sniffer) - netif_start_queue(dev); - } else { - memcpy_fromio(&local->bss_id, - prcs->var.rejoin_net_complete. - bssid, ADDRLEN); - dev_dbg(&link->dev, "ray_cs new BSSID = %pm\n", - local->bss_id); - if (!sniffer) - authenticate(local); - } - break; - case ROAMING_INITIATED: - dev_dbg(&link->dev, "ray_cs interrupt roaming initiated\n"); - netif_stop_queue(dev); - local->card_status = CARD_DOING_ACQ; - break; - case JAPAN_CALL_SIGN_RXD: - dev_dbg(&link->dev, "ray_cs interrupt japan call sign rx\n"); - break; - default: - dev_dbg(&link->dev, - "ray_cs Unexpected interrupt for RCS 0x%x cmd = 0x%x\n", - rcsindex, - (unsigned int)readb(&prcs->interrupt_id)); - break; - } - writeb(CCS_BUFFER_FREE, &prcs->buffer_status); - } - clear_interrupt(local); - return IRQ_HANDLED; -} /* ray_interrupt */ - -/*===========================================================================*/ -static void ray_rx(struct net_device *dev, ray_dev_t *local, - struct rcs __iomem *prcs) -{ - int rx_len; - unsigned int pkt_addr; - void __iomem *pmsg; - pr_debug("ray_rx process rx packet\n"); - - /* Calculate address of packet within Rx buffer */ - pkt_addr = ((readb(&prcs->var.rx_packet.rx_data_ptr[0]) << 8) - + readb(&prcs->var.rx_packet.rx_data_ptr[1])) & RX_BUFF_END; - /* Length of first packet fragment */ - rx_len = (readb(&prcs->var.rx_packet.rx_data_length[0]) << 8) - + readb(&prcs->var.rx_packet.rx_data_length[1]); - - local->last_rsl = readb(&prcs->var.rx_packet.rx_sig_lev); - pmsg = local->rmem + pkt_addr; - switch (readb(pmsg)) { - case DATA_TYPE: - pr_debug("ray_rx data type\n"); - rx_data(dev, prcs, pkt_addr, rx_len); - break; - case AUTHENTIC_TYPE: - pr_debug("ray_rx authentic type\n"); - if (sniffer) - rx_data(dev, prcs, pkt_addr, rx_len); - else - rx_authenticate(local, prcs, pkt_addr, rx_len); - break; - case DEAUTHENTIC_TYPE: - pr_debug("ray_rx deauth type\n"); - if (sniffer) - rx_data(dev, prcs, pkt_addr, rx_len); - else - rx_deauthenticate(local, prcs, pkt_addr, rx_len); - break; - case NULL_MSG_TYPE: - pr_debug("ray_cs rx NULL msg\n"); - break; - case BEACON_TYPE: - pr_debug("ray_rx beacon type\n"); - if (sniffer) - rx_data(dev, prcs, pkt_addr, rx_len); - - copy_from_rx_buff(local, (UCHAR *) &local->last_bcn, pkt_addr, - rx_len < sizeof(struct beacon_rx) ? - rx_len : sizeof(struct beacon_rx)); - - local->beacon_rxed = 1; - /* Get the statistics so the card counters never overflow */ - ray_get_stats(dev); - break; - default: - pr_debug("ray_cs unknown pkt type %2x\n", - (unsigned int)readb(pmsg)); - break; - } - -} /* end ray_rx */ - -/*===========================================================================*/ -static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, - unsigned int pkt_addr, int rx_len) -{ - struct sk_buff *skb = NULL; - struct rcs __iomem *prcslink = prcs; - ray_dev_t *local = netdev_priv(dev); - UCHAR *rx_ptr; - int total_len; - int tmp; -#ifdef WIRELESS_SPY - int siglev = local->last_rsl; - u_char linksrcaddr[ETH_ALEN]; /* Other end of the wireless link */ -#endif - - if (!sniffer) { - if (translate) { -/* TBD length needs fixing for translated header */ - if (rx_len < (ETH_HLEN + RX_MAC_HEADER_LENGTH) || - rx_len > - (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN + - FCS_LEN)) { - pr_debug( - "ray_cs invalid packet length %d received\n", - rx_len); - return; - } - } else { /* encapsulated ethernet */ - - if (rx_len < (ETH_HLEN + RX_MAC_HEADER_LENGTH) || - rx_len > - (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN + - FCS_LEN)) { - pr_debug( - "ray_cs invalid packet length %d received\n", - rx_len); - return; - } - } - } - pr_debug("ray_cs rx_data packet\n"); - /* If fragmented packet, verify sizes of fragments add up */ - if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF) { - pr_debug("ray_cs rx'ed fragment\n"); - tmp = (readb(&prcs->var.rx_packet.totalpacketlength[0]) << 8) - + readb(&prcs->var.rx_packet.totalpacketlength[1]); - total_len = tmp; - prcslink = prcs; - do { - tmp -= - (readb(&prcslink->var.rx_packet.rx_data_length[0]) - << 8) - + readb(&prcslink->var.rx_packet.rx_data_length[1]); - if (readb(&prcslink->var.rx_packet.next_frag_rcs_index) - == 0xFF || tmp < 0) - break; - prcslink = rcs_base(local) - + readb(&prcslink->link_field); - } while (1); - - if (tmp < 0) { - pr_debug( - "ray_cs rx_data fragment lengths don't add up\n"); - local->stats.rx_dropped++; - release_frag_chain(local, prcs); - return; - } - } else { /* Single unfragmented packet */ - total_len = rx_len; - } - - skb = dev_alloc_skb(total_len + 5); - if (skb == NULL) { - pr_debug("ray_cs rx_data could not allocate skb\n"); - local->stats.rx_dropped++; - if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF) - release_frag_chain(local, prcs); - return; - } - skb_reserve(skb, 2); /* Align IP on 16 byte (TBD check this) */ - - pr_debug("ray_cs rx_data total_len = %x, rx_len = %x\n", total_len, - rx_len); - -/************************/ - /* Reserve enough room for the whole damn packet. */ - rx_ptr = skb_put(skb, total_len); - /* Copy the whole packet to sk_buff */ - rx_ptr += - copy_from_rx_buff(local, rx_ptr, pkt_addr & RX_BUFF_END, rx_len); - /* Get source address */ -#ifdef WIRELESS_SPY - skb_copy_from_linear_data_offset(skb, - offsetof(struct mac_header, addr_2), - linksrcaddr, ETH_ALEN); -#endif - /* Now, deal with encapsulation/translation/sniffer */ - if (!sniffer) { - if (!translate) { - /* Encapsulated ethernet, so just lop off 802.11 MAC header */ -/* TBD reserve skb_reserve( skb, RX_MAC_HEADER_LENGTH); */ - skb_pull(skb, RX_MAC_HEADER_LENGTH); - } else { - /* Do translation */ - untranslate(local, skb, total_len); - } - } else { /* sniffer mode, so just pass whole packet */ - } - -/************************/ - /* Now pick up the rest of the fragments if any */ - tmp = 17; - if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF) { - prcslink = prcs; - pr_debug("ray_cs rx_data in fragment loop\n"); - do { - prcslink = rcs_base(local) - + - readb(&prcslink->var.rx_packet.next_frag_rcs_index); - rx_len = - ((readb(&prcslink->var.rx_packet.rx_data_length[0]) - << 8) - + - readb(&prcslink->var.rx_packet.rx_data_length[1])) - & RX_BUFF_END; - pkt_addr = - ((readb(&prcslink->var.rx_packet.rx_data_ptr[0]) << - 8) - + readb(&prcslink->var.rx_packet.rx_data_ptr[1])) - & RX_BUFF_END; - - rx_ptr += - copy_from_rx_buff(local, rx_ptr, pkt_addr, rx_len); - - } while (tmp-- && - readb(&prcslink->var.rx_packet.next_frag_rcs_index) != - 0xFF); - release_frag_chain(local, prcs); - } - - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - local->stats.rx_packets++; - local->stats.rx_bytes += total_len; - - /* Gather signal strength per address */ -#ifdef WIRELESS_SPY - /* For the Access Point or the node having started the ad-hoc net - * note : ad-hoc work only in some specific configurations, but we - * kludge in ray_get_wireless_stats... */ - if (!memcmp(linksrcaddr, local->bss_id, ETH_ALEN)) { - /* Update statistics */ - /*local->wstats.qual.qual = none ? */ - local->wstats.qual.level = siglev; - /*local->wstats.qual.noise = none ? */ - local->wstats.qual.updated = 0x2; - } - /* Now, update the spy stuff */ - { - struct iw_quality wstats; - wstats.level = siglev; - /* wstats.noise = none ? */ - /* wstats.qual = none ? */ - wstats.updated = 0x2; - /* Update spy records */ - wireless_spy_update(dev, linksrcaddr, &wstats); - } -#endif /* WIRELESS_SPY */ -} /* end rx_data */ - -/*===========================================================================*/ -static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len) -{ - snaphdr_t *psnap = (snaphdr_t *) (skb->data + RX_MAC_HEADER_LENGTH); - struct ieee80211_hdr *pmac = (struct ieee80211_hdr *)skb->data; - __be16 type = *(__be16 *) psnap->ethertype; - int delta; - struct ethhdr *peth; - UCHAR srcaddr[ADDRLEN]; - UCHAR destaddr[ADDRLEN]; - static const UCHAR org_bridge[3] = { 0, 0, 0xf8 }; - static const UCHAR org_1042[3] = { 0, 0, 0 }; - - memcpy(destaddr, ieee80211_get_DA(pmac), ADDRLEN); - memcpy(srcaddr, ieee80211_get_SA(pmac), ADDRLEN); - -#if 0 - if { - print_hex_dump(KERN_DEBUG, "skb->data before untranslate: ", - DUMP_PREFIX_NONE, 16, 1, - skb->data, 64, true); - printk(KERN_DEBUG - "type = %08x, xsap = %02x%02x%02x, org = %02x02x02x\n", - ntohs(type), psnap->dsap, psnap->ssap, psnap->ctrl, - psnap->org[0], psnap->org[1], psnap->org[2]); - printk(KERN_DEBUG "untranslate skb->data = %p\n", skb->data); - } -#endif - - if (psnap->dsap != 0xaa || psnap->ssap != 0xaa || psnap->ctrl != 3) { - /* not a snap type so leave it alone */ - pr_debug("ray_cs untranslate NOT SNAP %02x %02x %02x\n", - psnap->dsap, psnap->ssap, psnap->ctrl); - - delta = RX_MAC_HEADER_LENGTH - ETH_HLEN; - peth = (struct ethhdr *)(skb->data + delta); - peth->h_proto = htons(len - RX_MAC_HEADER_LENGTH); - } else { /* Its a SNAP */ - if (memcmp(psnap->org, org_bridge, 3) == 0) { - /* EtherII and nuke the LLC */ - pr_debug("ray_cs untranslate Bridge encap\n"); - delta = RX_MAC_HEADER_LENGTH - + sizeof(struct snaphdr_t) - ETH_HLEN; - peth = (struct ethhdr *)(skb->data + delta); - peth->h_proto = type; - } else if (memcmp(psnap->org, org_1042, 3) == 0) { - switch (ntohs(type)) { - case ETH_P_IPX: - case ETH_P_AARP: - pr_debug("ray_cs untranslate RFC IPX/AARP\n"); - delta = RX_MAC_HEADER_LENGTH - ETH_HLEN; - peth = (struct ethhdr *)(skb->data + delta); - peth->h_proto = - htons(len - RX_MAC_HEADER_LENGTH); - break; - default: - pr_debug("ray_cs untranslate RFC default\n"); - delta = RX_MAC_HEADER_LENGTH + - sizeof(struct snaphdr_t) - ETH_HLEN; - peth = (struct ethhdr *)(skb->data + delta); - peth->h_proto = type; - break; - } - } else { - printk("ray_cs untranslate very confused by packet\n"); - delta = RX_MAC_HEADER_LENGTH - ETH_HLEN; - peth = (struct ethhdr *)(skb->data + delta); - peth->h_proto = type; - } - } -/* TBD reserve skb_reserve(skb, delta); */ - skb_pull(skb, delta); - pr_debug("untranslate after skb_pull(%d), skb->data = %p\n", delta, - skb->data); - memcpy(peth->h_dest, destaddr, ADDRLEN); - memcpy(peth->h_source, srcaddr, ADDRLEN); -#if 0 - { - int i; - printk(KERN_DEBUG "skb->data after untranslate:"); - for (i = 0; i < 64; i++) - printk("%02x ", skb->data[i]); - printk("\n"); - } -#endif -} /* end untranslate */ - -/*===========================================================================*/ -/* Copy data from circular receive buffer to PC memory. - * dest = destination address in PC memory - * pkt_addr = source address in receive buffer - * len = length of packet to copy - */ -static int copy_from_rx_buff(ray_dev_t *local, UCHAR *dest, int pkt_addr, - int length) -{ - int wrap_bytes = (pkt_addr + length) - (RX_BUFF_END + 1); - if (wrap_bytes <= 0) { - memcpy_fromio(dest, local->rmem + pkt_addr, length); - } else { /* Packet wrapped in circular buffer */ - - memcpy_fromio(dest, local->rmem + pkt_addr, - length - wrap_bytes); - memcpy_fromio(dest + length - wrap_bytes, local->rmem, - wrap_bytes); - } - return length; -} - -/*===========================================================================*/ -static void release_frag_chain(ray_dev_t *local, struct rcs __iomem *prcs) -{ - struct rcs __iomem *prcslink = prcs; - int tmp = 17; - unsigned rcsindex = readb(&prcs->var.rx_packet.next_frag_rcs_index); - - while (tmp--) { - writeb(CCS_BUFFER_FREE, &prcslink->buffer_status); - if (rcsindex >= (NUMBER_OF_CCS + NUMBER_OF_RCS)) { - pr_debug("ray_cs interrupt bad rcsindex = 0x%x\n", - rcsindex); - break; - } - prcslink = rcs_base(local) + rcsindex; - rcsindex = readb(&prcslink->var.rx_packet.next_frag_rcs_index); - } - writeb(CCS_BUFFER_FREE, &prcslink->buffer_status); -} - -/*===========================================================================*/ -static void authenticate(ray_dev_t *local) -{ - struct pcmcia_device *link = local->finder; - dev_dbg(&link->dev, "ray_cs Starting authentication.\n"); - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_cs authenticate - device not present\n"); - return; - } - - del_timer(&local->timer); - if (build_auth_frame(local, local->bss_id, OPEN_AUTH_REQUEST)) { - local->timer.function = join_net; - } else { - local->timer.function = authenticate_timeout; - } - local->timer.expires = jiffies + HZ * 2; - add_timer(&local->timer); - local->authentication_state = AWAITING_RESPONSE; -} /* end authenticate */ - -/*===========================================================================*/ -static void rx_authenticate(ray_dev_t *local, struct rcs __iomem *prcs, - unsigned int pkt_addr, int rx_len) -{ - UCHAR buff[256]; - struct ray_rx_msg *msg = (struct ray_rx_msg *) buff; - - del_timer(&local->timer); - - copy_from_rx_buff(local, buff, pkt_addr, rx_len & 0xff); - /* if we are trying to get authenticated */ - if (local->sparm.b4.a_network_type == ADHOC) { - pr_debug("ray_cs rx_auth var= %6ph\n", msg->var); - if (msg->var[2] == 1) { - pr_debug("ray_cs Sending authentication response.\n"); - if (!build_auth_frame - (local, msg->mac.addr_2, OPEN_AUTH_RESPONSE)) { - local->authentication_state = NEED_TO_AUTH; - memcpy(local->auth_id, msg->mac.addr_2, - ADDRLEN); - } - } - } else { /* Infrastructure network */ - - if (local->authentication_state == AWAITING_RESPONSE) { - /* Verify authentication sequence #2 and success */ - if (msg->var[2] == 2) { - if ((msg->var[3] | msg->var[4]) == 0) { - pr_debug("Authentication successful\n"); - local->card_status = CARD_AUTH_COMPLETE; - associate(local); - local->authentication_state = - AUTHENTICATED; - } else { - pr_debug("Authentication refused\n"); - local->card_status = CARD_AUTH_REFUSED; - join_net(&local->timer); - local->authentication_state = - UNAUTHENTICATED; - } - } - } - } - -} /* end rx_authenticate */ - -/*===========================================================================*/ -static void associate(ray_dev_t *local) -{ - struct ccs __iomem *pccs; - struct pcmcia_device *link = local->finder; - struct net_device *dev = link->priv; - int ccsindex; - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_cs associate - device not present\n"); - return; - } - /* If no tx buffers available, return */ - if ((ccsindex = get_free_ccs(local)) < 0) { -/* TBD should never be here but... what if we are? */ - dev_dbg(&link->dev, "ray_cs associate - No free ccs\n"); - return; - } - dev_dbg(&link->dev, "ray_cs Starting association with access point\n"); - pccs = ccs_base(local) + ccsindex; - /* fill in the CCS */ - writeb(CCS_START_ASSOCIATION, &pccs->cmd); - /* Interrupt the firmware to process the command */ - if (interrupt_ecf(local, ccsindex)) { - dev_dbg(&link->dev, "ray_cs associate failed - ECF not ready for intr\n"); - writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); - - del_timer(&local->timer); - local->timer.expires = jiffies + HZ * 2; - local->timer.function = join_net; - add_timer(&local->timer); - local->card_status = CARD_ASSOC_FAILED; - return; - } - if (!sniffer) - netif_start_queue(dev); - -} /* end associate */ - -/*===========================================================================*/ -static void rx_deauthenticate(ray_dev_t *local, struct rcs __iomem *prcs, - unsigned int pkt_addr, int rx_len) -{ -/* UCHAR buff[256]; - struct ray_rx_msg *msg = (struct ray_rx_msg *) buff; -*/ - pr_debug("Deauthentication frame received\n"); - local->authentication_state = UNAUTHENTICATED; - /* Need to reauthenticate or rejoin depending on reason code */ -/* copy_from_rx_buff(local, buff, pkt_addr, rx_len & 0xff); - */ -} - -/*===========================================================================*/ -static void clear_interrupt(ray_dev_t *local) -{ - writeb(0, local->amem + CIS_OFFSET + HCS_INTR_OFFSET); -} - -/*===========================================================================*/ -#ifdef CONFIG_PROC_FS -#define MAXDATA (PAGE_SIZE - 80) - -static const char *card_status[] = { - "Card inserted - uninitialized", /* 0 */ - "Card not downloaded", /* 1 */ - "Waiting for download parameters", /* 2 */ - "Card doing acquisition", /* 3 */ - "Acquisition complete", /* 4 */ - "Authentication complete", /* 5 */ - "Association complete", /* 6 */ - "???", "???", "???", "???", /* 7 8 9 10 undefined */ - "Card init error", /* 11 */ - "Download parameters error", /* 12 */ - "???", /* 13 */ - "Acquisition failed", /* 14 */ - "Authentication refused", /* 15 */ - "Association failed" /* 16 */ -}; - -static const char *nettype[] = { "Adhoc", "Infra " }; -static const char *framing[] = { "Encapsulation", "Translation" } - -; -/*===========================================================================*/ -static int ray_cs_proc_show(struct seq_file *m, void *v) -{ -/* Print current values which are not available via other means - * eg ifconfig - */ - int i; - struct pcmcia_device *link; - struct net_device *dev; - ray_dev_t *local; - UCHAR *p; - struct freq_hop_element *pfh; - UCHAR c[33]; - - link = this_device; - if (!link) - return 0; - dev = link->priv; - if (!dev) - return 0; - local = netdev_priv(dev); - if (!local) - return 0; - - seq_puts(m, "Raylink Wireless LAN driver status\n"); - seq_printf(m, "%s\n", rcsid); - /* build 4 does not report version, and field is 0x55 after memtest */ - seq_puts(m, "Firmware version = "); - if (local->fw_ver == 0x55) - seq_puts(m, "4 - Use dump_cis for more details\n"); - else - seq_printf(m, "%2d.%02d.%02d\n", - local->fw_ver, local->fw_bld, local->fw_var); - - for (i = 0; i < 32; i++) - c[i] = local->sparm.b5.a_current_ess_id[i]; - c[32] = 0; - seq_printf(m, "%s network ESSID = \"%s\"\n", - nettype[local->sparm.b5.a_network_type], c); - - p = local->bss_id; - seq_printf(m, "BSSID = %pM\n", p); - - seq_printf(m, "Country code = %d\n", - local->sparm.b5.a_curr_country_code); - - i = local->card_status; - if (i < 0) - i = 10; - if (i > 16) - i = 10; - seq_printf(m, "Card status = %s\n", card_status[i]); - - seq_printf(m, "Framing mode = %s\n", framing[translate]); - - seq_printf(m, "Last pkt signal lvl = %d\n", local->last_rsl); - - if (local->beacon_rxed) { - /* Pull some fields out of last beacon received */ - seq_printf(m, "Beacon Interval = %d Kus\n", - local->last_bcn.beacon_intvl[0] - + 256 * local->last_bcn.beacon_intvl[1]); - - p = local->last_bcn.elements; - if (p[0] == C_ESSID_ELEMENT_ID) - p += p[1] + 2; - else { - seq_printf(m, - "Parse beacon failed at essid element id = %d\n", - p[0]); - return 0; - } - - if (p[0] == C_SUPPORTED_RATES_ELEMENT_ID) { - seq_puts(m, "Supported rate codes = "); - for (i = 2; i < p[1] + 2; i++) - seq_printf(m, "0x%02x ", p[i]); - seq_putc(m, '\n'); - p += p[1] + 2; - } else { - seq_puts(m, "Parse beacon failed at rates element\n"); - return 0; - } - - if (p[0] == C_FH_PARAM_SET_ELEMENT_ID) { - pfh = (struct freq_hop_element *)p; - seq_printf(m, "Hop dwell = %d Kus\n", - pfh->dwell_time[0] + - 256 * pfh->dwell_time[1]); - seq_printf(m, "Hop set = %d\n", - pfh->hop_set); - seq_printf(m, "Hop pattern = %d\n", - pfh->hop_pattern); - seq_printf(m, "Hop index = %d\n", - pfh->hop_index); - p += p[1] + 2; - } else { - seq_puts(m, - "Parse beacon failed at FH param element\n"); - return 0; - } - } else { - seq_puts(m, "No beacons received\n"); - } - return 0; -} -#endif -/*===========================================================================*/ -static int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type) -{ - int addr; - struct ccs __iomem *pccs; - struct tx_msg __iomem *ptx; - int ccsindex; - - /* If no tx buffers available, return */ - if ((ccsindex = get_free_tx_ccs(local)) < 0) { - pr_debug("ray_cs send authenticate - No free tx ccs\n"); - return -1; - } - - pccs = ccs_base(local) + ccsindex; - - /* Address in card space */ - addr = TX_BUF_BASE + (ccsindex << 11); - /* fill in the CCS */ - writeb(CCS_TX_REQUEST, &pccs->cmd); - writeb(addr >> 8, pccs->var.tx_request.tx_data_ptr); - writeb(0x20, pccs->var.tx_request.tx_data_ptr + 1); - writeb(TX_AUTHENTICATE_LENGTH_MSB, pccs->var.tx_request.tx_data_length); - writeb(TX_AUTHENTICATE_LENGTH_LSB, - pccs->var.tx_request.tx_data_length + 1); - writeb(0, &pccs->var.tx_request.pow_sav_mode); - - ptx = local->sram + addr; - /* fill in the mac header */ - writeb(PROTOCOL_VER | AUTHENTIC_TYPE, &ptx->mac.frame_ctl_1); - writeb(0, &ptx->mac.frame_ctl_2); - - memcpy_toio(ptx->mac.addr_1, dest, ADDRLEN); - memcpy_toio(ptx->mac.addr_2, local->sparm.b4.a_mac_addr, ADDRLEN); - memcpy_toio(ptx->mac.addr_3, local->bss_id, ADDRLEN); - - /* Fill in msg body with protocol 00 00, sequence 01 00 ,status 00 00 */ - memset_io(ptx->var, 0, 6); - writeb(auth_type & 0xff, ptx->var + 2); - - /* Interrupt the firmware to process the command */ - if (interrupt_ecf(local, ccsindex)) { - pr_debug( - "ray_cs send authentication request failed - ECF not ready for intr\n"); - writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); - return -1; - } - return 0; -} /* End build_auth_frame */ - -/*===========================================================================*/ -#ifdef CONFIG_PROC_FS -static ssize_t ray_cs_essid_proc_write(struct file *file, - const char __user *buffer, size_t count, loff_t *pos) -{ - static char proc_essid[33]; - unsigned int len = count; - - if (len > 32) - len = 32; - memset(proc_essid, 0, 33); - if (copy_from_user(proc_essid, buffer, len)) - return -EFAULT; - essid = proc_essid; - return count; -} - -static const struct proc_ops ray_cs_essid_proc_ops = { - .proc_write = ray_cs_essid_proc_write, - .proc_lseek = noop_llseek, -}; - -static ssize_t int_proc_write(struct file *file, const char __user *buffer, - size_t count, loff_t *pos) -{ - static char proc_number[10]; - char *p; - int nr, len; - - if (!count) - return 0; - - if (count > 9) - return -EINVAL; - if (copy_from_user(proc_number, buffer, count)) - return -EFAULT; - p = proc_number; - nr = 0; - len = count; - do { - unsigned int c = *p - '0'; - if (c > 9) - return -EINVAL; - nr = nr * 10 + c; - p++; - } while (--len); - *(int *)pde_data(file_inode(file)) = nr; - return count; -} - -static const struct proc_ops int_proc_ops = { - .proc_write = int_proc_write, - .proc_lseek = noop_llseek, -}; -#endif - -static const struct pcmcia_device_id ray_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0x01a6, 0x0000), - PCMCIA_DEVICE_NULL, -}; - -MODULE_DEVICE_TABLE(pcmcia, ray_ids); - -static struct pcmcia_driver ray_driver = { - .owner = THIS_MODULE, - .name = "ray_cs", - .probe = ray_probe, - .remove = ray_detach, - .id_table = ray_ids, - .suspend = ray_suspend, - .resume = ray_resume, -}; - -static int __init init_ray_cs(void) -{ - int rc; - - pr_debug("%s\n", rcsid); - rc = pcmcia_register_driver(&ray_driver); - pr_debug("raylink init_module register_pcmcia_driver returns 0x%x\n", - rc); - if (rc) - return rc; - -#ifdef CONFIG_PROC_FS - proc_mkdir("driver/ray_cs", NULL); - - proc_create_single("driver/ray_cs/ray_cs", 0, NULL, ray_cs_proc_show); - proc_create("driver/ray_cs/essid", 0200, NULL, &ray_cs_essid_proc_ops); - proc_create_data("driver/ray_cs/net_type", 0200, NULL, &int_proc_ops, - &net_type); - proc_create_data("driver/ray_cs/translate", 0200, NULL, &int_proc_ops, - &translate); -#endif - translate = !!translate; - return 0; -} /* init_ray_cs */ - -/*===========================================================================*/ - -static void __exit exit_ray_cs(void) -{ - pr_debug("ray_cs: cleanup_module\n"); - -#ifdef CONFIG_PROC_FS - remove_proc_subtree("driver/ray_cs", NULL); -#endif - - pcmcia_unregister_driver(&ray_driver); -} /* exit_ray_cs */ - -module_init(init_ray_cs); -module_exit(exit_ray_cs); - -/*===========================================================================*/ diff --git a/drivers/net/wireless/legacy/ray_cs.h b/drivers/net/wireless/legacy/ray_cs.h deleted file mode 100644 index 0609d86250192..0000000000000 --- a/drivers/net/wireless/legacy/ray_cs.h +++ /dev/null @@ -1,74 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Raytheon wireless LAN PCMCIA card driver for Linux - A PCMCIA client driver for the Raylink wireless network card - Written by Corey Thomas -*/ - -#ifndef _RAY_CS_H_ -#define _RAY_CS_H_ - -struct beacon_rx { - struct mac_header mac; - UCHAR timestamp[8]; - UCHAR beacon_intvl[2]; - UCHAR capability[2]; - UCHAR elements[sizeof(struct essid_element) - + sizeof(struct rates_element) - + sizeof(struct freq_hop_element) - + sizeof(struct japan_call_sign_element) - + sizeof(struct tim_element)]; -}; - -/* Return values for get_free{,_tx}_ccs */ -#define ECCSFULL (-1) -#define ECCSBUSY (-2) -#define ECARDGONE (-3) - -typedef struct ray_dev_t { - int card_status; - int authentication_state; - void __iomem *sram; /* pointer to beginning of shared RAM */ - void __iomem *amem; /* pointer to attribute mem window */ - void __iomem *rmem; /* pointer to receive buffer window */ - struct pcmcia_device *finder; /* pointer back to struct pcmcia_device for card */ - struct timer_list timer; - unsigned long tx_ccs_lock; - unsigned long ccs_lock; - int dl_param_ccs; - union { - struct b4_startup_params b4; - struct b5_startup_params b5; - } sparm; - int timeout_flag; - UCHAR supported_rates[8]; - UCHAR japan_call_sign[12]; - struct startup_res_6 startup_res; - int num_multi; - /* Network parameters from start/join */ - UCHAR bss_id[6]; - UCHAR auth_id[6]; - UCHAR net_default_tx_rate; - UCHAR encryption; - struct net_device_stats stats; - - UCHAR net_type; - UCHAR sta_type; - UCHAR fw_ver; - UCHAR fw_bld; - UCHAR fw_var; - UCHAR ASIC_version; - UCHAR assoc_id[2]; - UCHAR tib_length; - UCHAR last_rsl; - int beacon_rxed; - struct beacon_rx last_bcn; - iw_stats wstats; /* Wireless specific stats */ -#ifdef WIRELESS_SPY - struct iw_spy_data spy_data; - struct iw_public_data wireless_data; -#endif /* WIRELESS_SPY */ - -} ray_dev_t; -/*****************************************************************************/ - -#endif /* _RAY_CS_H_ */ diff --git a/drivers/net/wireless/legacy/rayctl.h b/drivers/net/wireless/legacy/rayctl.h deleted file mode 100644 index 1f3bde8ac73d4..0000000000000 --- a/drivers/net/wireless/legacy/rayctl.h +++ /dev/null @@ -1,734 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _RAYCTL_H_ -#define _RAYCTL_H_ - -typedef unsigned char UCHAR; - -/****** IEEE 802.11 constants ************************************************/ -#define ADDRLEN 6 -/* Frame control 1 bit fields */ -#define PROTOCOL_VER 0x00 -#define DATA_TYPE 0x08 -#define ASSOC_REQ_TYPE 0x00 -#define ASSOC_RESP_TYPE 0x10 -#define REASSOC_REQ_TYPE 0x20 -#define REASSOC_RESP_TYPE 0x30 -#define NULL_MSG_TYPE 0x48 -#define BEACON_TYPE 0x80 -#define DISASSOC_TYPE 0xA0 -#define PSPOLL_TYPE 0xA4 -#define AUTHENTIC_TYPE 0xB0 -#define DEAUTHENTIC_TYPE 0xC0 -/* Frame control 2 bit fields */ -#define FC2_TO_DS 0x01 -#define FC2_FROM_DS 0x02 -#define FC2_MORE_FRAG 0x04 -#define FC2_RETRY 0x08 -#define FC2_PSM 0x10 -#define FC2_MORE_DATA 0x20 -#define FC2_WEP 0x40 -#define FC2_ORDER 0x80 -/*****************************************************************************/ -/* 802.11 element ID's and lengths */ -#define C_BP_CAPABILITY_ESS 0x01 -#define C_BP_CAPABILITY_IBSS 0x02 -#define C_BP_CAPABILITY_CF_POLLABLE 0x04 -#define C_BP_CAPABILITY_CF_POLL_REQUEST 0x08 -#define C_BP_CAPABILITY_PRIVACY 0x10 - -#define C_ESSID_ELEMENT_ID 0 -#define C_ESSID_ELEMENT_MAX_LENGTH 32 - -#define C_SUPPORTED_RATES_ELEMENT_ID 1 -#define C_SUPPORTED_RATES_ELEMENT_LENGTH 2 - -#define C_FH_PARAM_SET_ELEMENT_ID 2 -#define C_FH_PARAM_SET_ELEMENT_LNGTH 5 - -#define C_CF_PARAM_SET_ELEMENT_ID 4 -#define C_CF_PARAM_SET_ELEMENT_LNGTH 6 - -#define C_TIM_ELEMENT_ID 5 -#define C_TIM_BITMAP_LENGTH 251 -#define C_TIM_BMCAST_BIT 0x01 - -#define C_IBSS_ELEMENT_ID 6 -#define C_IBSS_ELEMENT_LENGTH 2 - -#define C_JAPAN_CALL_SIGN_ELEMENT_ID 51 -#define C_JAPAN_CALL_SIGN_ELEMENT_LNGTH 12 - -#define C_DISASSOC_REASON_CODE_LEN 2 -#define C_DISASSOC_REASON_CODE_DEFAULT 8 - -#define C_CRC_LEN 4 -#define C_NUM_SUPPORTED_RATES 8 -/****** IEEE 802.11 mac header for type data packets *************************/ -struct mac_header { - UCHAR frame_ctl_1; - UCHAR frame_ctl_2; - UCHAR duration_lsb; - UCHAR duration_msb; - UCHAR addr_1[ADDRLEN]; - UCHAR addr_2[ADDRLEN]; - UCHAR addr_3[ADDRLEN]; - UCHAR seq_frag_num[2]; -/* UCHAR addr_4[ADDRLEN]; *//* only present for AP to AP (TO DS and FROM DS */ -}; -/****** IEEE 802.11 frame element structures *********************************/ -struct essid_element -{ - UCHAR id; - UCHAR length; - UCHAR text[C_ESSID_ELEMENT_MAX_LENGTH]; -}; -struct rates_element -{ - UCHAR id; - UCHAR length; - UCHAR value[8]; -}; -struct freq_hop_element -{ - UCHAR id; - UCHAR length; - UCHAR dwell_time[2]; - UCHAR hop_set; - UCHAR hop_pattern; - UCHAR hop_index; -}; -struct tim_element -{ - UCHAR id; - UCHAR length; - UCHAR dtim_count; - UCHAR dtim_period; - UCHAR bitmap_control; - UCHAR tim[C_TIM_BITMAP_LENGTH]; -}; -struct ibss_element -{ - UCHAR id; - UCHAR length; - UCHAR atim_window[2]; -}; -struct japan_call_sign_element -{ - UCHAR id; - UCHAR length; - UCHAR call_sign[12]; -}; -/****** Beacon message structures ********************************************/ -/* .elements is a large lump of max size because elements are variable size */ -struct infra_beacon -{ - UCHAR timestamp[8]; - UCHAR beacon_intvl[2]; - UCHAR capability[2]; - UCHAR elements[sizeof(struct essid_element) - + sizeof(struct rates_element) - + sizeof(struct freq_hop_element) - + sizeof(struct japan_call_sign_element) - + sizeof(struct tim_element)]; -}; -struct adhoc_beacon -{ - UCHAR timestamp[8]; - UCHAR beacon_intvl[2]; - UCHAR capability[2]; - UCHAR elements[sizeof(struct essid_element) - + sizeof(struct rates_element) - + sizeof(struct freq_hop_element) - + sizeof(struct japan_call_sign_element) - + sizeof(struct ibss_element)]; -}; -/*****************************************************************************/ -/*****************************************************************************/ -/* #define C_MAC_HDR_2_WEP 0x40 */ -/* TX/RX CCS constants */ -#define TX_HEADER_LENGTH 0x1C -#define RX_MAC_HEADER_LENGTH 0x18 -#define TX_AUTHENTICATE_LENGTH (TX_HEADER_LENGTH + 6) -#define TX_AUTHENTICATE_LENGTH_MSB (TX_AUTHENTICATE_LENGTH >> 8) -#define TX_AUTHENTICATE_LENGTH_LSB (TX_AUTHENTICATE_LENGTH & 0xff) -#define TX_DEAUTHENTICATE_LENGTH (TX_HEADER_LENGTH + 2) -#define TX_DEAUTHENTICATE_LENGTH_MSB (TX_AUTHENTICATE_LENGTH >> 8) -#define TX_DEAUTHENTICATE_LENGTH_LSB (TX_AUTHENTICATE_LENGTH & 0xff) -#define FCS_LEN 4 - -#define ADHOC 0 -#define INFRA 1 - -#define TYPE_STA 0 -#define TYPE_AP 1 - -#define PASSIVE_SCAN 1 -#define ACTIVE_SCAN 1 - -#define PSM_CAM 0 - -/* Country codes */ -#define USA 1 -#define EUROPE 2 -#define JAPAN 3 -#define KOREA 4 -#define SPAIN 5 -#define FRANCE 6 -#define ISRAEL 7 -#define AUSTRALIA 8 -#define JAPAN_TEST 9 - -/* Hop pattern lengths */ -#define USA_HOP_MOD 79 -#define EUROPE_HOP_MOD 79 -#define JAPAN_HOP_MOD 23 -#define KOREA_HOP_MOD 23 -#define SPAIN_HOP_MOD 27 -#define FRANCE_HOP_MOD 35 -#define ISRAEL_HOP_MOD 35 -#define AUSTRALIA_HOP_MOD 47 -#define JAPAN_TEST_HOP_MOD 23 - -#define ESSID_SIZE 32 -/**********************************************************************/ -/* CIS Register Constants */ -#define CIS_OFFSET 0x0f00 -/* Configuration Option Register (0x0F00) */ -#define COR_OFFSET 0x00 -#define COR_SOFT_RESET 0x80 -#define COR_LEVEL_IRQ 0x40 -#define COR_CONFIG_NUM 0x01 -#define COR_DEFAULT (COR_LEVEL_IRQ | COR_CONFIG_NUM) - -/* Card Configuration and Status Register (0x0F01) */ -#define CCSR_OFFSET 0x01 -#define CCSR_HOST_INTR_PENDING 0x01 -#define CCSR_POWER_DOWN 0x04 - -/* HCS Interrupt Register (0x0F05) */ -#define HCS_INTR_OFFSET 0x05 -/* #define HCS_INTR_OFFSET 0x0A */ -#define HCS_INTR_CLEAR 0x00 - -/* ECF Interrupt Register (0x0F06) */ -#define ECF_INTR_OFFSET 0x06 -/* #define ECF_INTR_OFFSET 0x0C */ -#define ECF_INTR_SET 0x01 - -/* Authorization Register 0 (0x0F08) */ -#define AUTH_0_ON 0x57 - -/* Authorization Register 1 (0x0F09) */ -#define AUTH_1_ON 0x82 - -/* Program Mode Register (0x0F0A) */ -#define PC2PM 0x02 -#define PC2CAL 0x10 -#define PC2MLSE 0x20 - -/* PC Test Mode Register (0x0F0B) */ -#define PC_TEST_MODE 0x08 - -/* Frequency Control Word (0x0F10) */ -/* Range 0x02 - 0xA6 */ - -/* Test Mode Control 1-4 (0x0F14 - 0x0F17) */ - -/**********************************************************************/ - -/* Shared RAM Area */ -#define SCB_BASE 0x0000 -#define STATUS_BASE 0x0100 -#define HOST_TO_ECF_BASE 0x0200 -#define ECF_TO_HOST_BASE 0x0300 -#define CCS_BASE 0x0400 -#define RCS_BASE 0x0800 -#define INFRA_TIM_BASE 0x0C00 -#define SSID_LIST_BASE 0x0D00 -#define TX_BUF_BASE 0x1000 -#define RX_BUF_BASE 0x8000 - -#define NUMBER_OF_CCS 64 -#define NUMBER_OF_RCS 64 -/*#define NUMBER_OF_TX_CCS 14 */ -#define NUMBER_OF_TX_CCS 14 - -#define TX_BUF_SIZE (2048 - sizeof(struct tx_msg)) -#define RX_BUFF_END 0x3FFF -/* Values for buffer_status */ -#define CCS_BUFFER_FREE 0 -#define CCS_BUFFER_BUSY 1 -#define CCS_COMMAND_COMPLETE 2 -#define CCS_COMMAND_FAILED 3 - -/* Values for cmd */ -#define CCS_DOWNLOAD_STARTUP_PARAMS 1 -#define CCS_UPDATE_PARAMS 2 -#define CCS_REPORT_PARAMS 3 -#define CCS_UPDATE_MULTICAST_LIST 4 -#define CCS_UPDATE_POWER_SAVINGS_MODE 5 -#define CCS_START_NETWORK 6 -#define CCS_JOIN_NETWORK 7 -#define CCS_START_ASSOCIATION 8 -#define CCS_TX_REQUEST 9 -#define CCS_TEST_MEMORY 0xa -#define CCS_SHUTDOWN 0xb -#define CCS_DUMP_MEMORY 0xc -#define CCS_START_TIMER 0xe -#define CCS_LAST_CMD CCS_START_TIMER - -/* Values for link field */ -#define CCS_END_LIST 0xff - -/* values for buffer_status field */ -#define RCS_BUFFER_FREE 0 -#define RCS_BUFFER_BUSY 1 -#define RCS_COMPLETE 2 -#define RCS_FAILED 3 -#define RCS_BUFFER_RELEASE 0xFF - -/* values for interrupt_id field */ -#define PROCESS_RX_PACKET 0x80 /* */ -#define REJOIN_NET_COMPLETE 0x81 /* RCS ID: Rejoin Net Complete */ -#define ROAMING_INITIATED 0x82 /* RCS ID: Roaming Initiated */ -#define JAPAN_CALL_SIGN_RXD 0x83 /* RCS ID: New Japan Call Sign */ - -/*****************************************************************************/ -/* Memory types for dump memory command */ -#define C_MEM_PROG 0 -#define C_MEM_XDATA 1 -#define C_MEM_SFR 2 -#define C_MEM_IDATA 3 - -/*** Return values for hw_xmit **********/ -#define XMIT_OK (0) -#define XMIT_MSG_BAD (-1) -#define XMIT_NO_CCS (-2) -#define XMIT_NO_INTR (-3) -#define XMIT_NEED_AUTH (-4) - -/*** Values for card status */ -#define CARD_INSERTED (0) - -#define CARD_AWAITING_PARAM (1) -#define CARD_INIT_ERROR (11) - -#define CARD_DL_PARAM (2) -#define CARD_DL_PARAM_ERROR (12) - -#define CARD_DOING_ACQ (3) - -#define CARD_ACQ_COMPLETE (4) -#define CARD_ACQ_FAILED (14) - -#define CARD_AUTH_COMPLETE (5) -#define CARD_AUTH_REFUSED (15) - -#define CARD_ASSOC_COMPLETE (6) -#define CARD_ASSOC_FAILED (16) - -/*** Values for authentication_state ***********************************/ -#define UNAUTHENTICATED (0) -#define AWAITING_RESPONSE (1) -#define AUTHENTICATED (2) -#define NEED_TO_AUTH (3) - -/*** Values for authentication type ************************************/ -#define OPEN_AUTH_REQUEST (1) -#define OPEN_AUTH_RESPONSE (2) -#define BROADCAST_DEAUTH (0xc0) -/*** Values for timer functions ****************************************/ -#define TODO_NOTHING (0) -#define TODO_VERIFY_DL_START (-1) -#define TODO_START_NET (-2) -#define TODO_JOIN_NET (-3) -#define TODO_AUTHENTICATE_TIMEOUT (-4) -#define TODO_SEND_CCS (-5) -/***********************************************************************/ -/* Parameter passing structure for update/report parameter CCS's */ -struct object_id { - void *object_addr; - unsigned char object_length; -}; - -#define OBJID_network_type 0 -#define OBJID_acting_as_ap_status 1 -#define OBJID_current_ess_id 2 -#define OBJID_scanning_mode 3 -#define OBJID_power_mgt_state 4 -#define OBJID_mac_address 5 -#define OBJID_frag_threshold 6 -#define OBJID_hop_time 7 -#define OBJID_beacon_period 8 -#define OBJID_dtim_period 9 -#define OBJID_retry_max 10 -#define OBJID_ack_timeout 11 -#define OBJID_sifs 12 -#define OBJID_difs 13 -#define OBJID_pifs 14 -#define OBJID_rts_threshold 15 -#define OBJID_scan_dwell_time 16 -#define OBJID_max_scan_dwell_time 17 -#define OBJID_assoc_resp_timeout 18 -#define OBJID_adhoc_scan_cycle_max 19 -#define OBJID_infra_scan_cycle_max 20 -#define OBJID_infra_super_cycle_max 21 -#define OBJID_promiscuous_mode 22 -#define OBJID_unique_word 23 -#define OBJID_slot_time 24 -#define OBJID_roaming_low_snr 25 -#define OBJID_low_snr_count_thresh 26 -#define OBJID_infra_missed_bcn 27 -#define OBJID_adhoc_missed_bcn 28 -#define OBJID_curr_country_code 29 -#define OBJID_hop_pattern 30 -#define OBJID_reserved 31 -#define OBJID_cw_max_msb 32 -#define OBJID_cw_min_msb 33 -#define OBJID_noise_filter_gain 34 -#define OBJID_noise_limit_offset 35 -#define OBJID_det_rssi_thresh_offset 36 -#define OBJID_med_busy_thresh_offset 37 -#define OBJID_det_sync_thresh 38 -#define OBJID_test_mode 39 -#define OBJID_test_min_chan_num 40 -#define OBJID_test_max_chan_num 41 -#define OBJID_allow_bcast_ID_prbrsp 42 -#define OBJID_privacy_must_start 43 -#define OBJID_privacy_can_join 44 -#define OBJID_basic_rate_set 45 - -/**** Configuration/Status/Control Area ***************************/ -/* System Control Block (SCB) Area - * Located at Shared RAM offset 0 - */ -struct scb { - UCHAR ccs_index; - UCHAR rcs_index; -}; - -/****** Status area at Shared RAM offset 0x0100 ******************************/ -struct status { - UCHAR mrx_overflow_for_host; /* 0=ECF may write, 1=host may write*/ - UCHAR mrx_checksum_error_for_host; /* 0=ECF may write, 1=host may write*/ - UCHAR rx_hec_error_for_host; /* 0=ECF may write, 1=host may write*/ - UCHAR reserved1; - short mrx_overflow; /* ECF increments on rx overflow */ - short mrx_checksum_error; /* ECF increments on rx CRC error */ - short rx_hec_error; /* ECF incs on mac header CRC error */ - UCHAR rxnoise; /* Average RSL measurement */ -}; - -/****** Host-to-ECF Data Area at Shared RAM offset 0x200 *********************/ -struct host_to_ecf_area { - -}; - -/****** ECF-to-Host Data Area at Shared RAM offset 0x0300 ********************/ -struct startup_res_518 { - UCHAR startup_word; - UCHAR station_addr[ADDRLEN]; - UCHAR calc_prog_chksum; - UCHAR calc_cis_chksum; - UCHAR ecf_spare[7]; - UCHAR japan_call_sign[12]; -}; - -struct startup_res_6 { - UCHAR startup_word; - UCHAR station_addr[ADDRLEN]; - UCHAR reserved; - UCHAR supp_rates[8]; - UCHAR japan_call_sign[12]; - UCHAR calc_prog_chksum; - UCHAR calc_cis_chksum; - UCHAR firmware_version[3]; - UCHAR asic_version; - UCHAR tib_length; -}; - -struct start_join_net_params { - UCHAR net_type; - UCHAR ssid[ESSID_SIZE]; - UCHAR reserved; - UCHAR privacy_can_join; -}; - -/****** Command Control Structure area at Shared ram offset 0x0400 ***********/ -/* Structures for command specific parameters (ccs.var) */ -struct update_param_cmd { - UCHAR object_id; - UCHAR number_objects; - UCHAR failure_cause; -}; -struct report_param_cmd { - UCHAR object_id; - UCHAR number_objects; - UCHAR failure_cause; - UCHAR length; -}; -struct start_network_cmd { - UCHAR update_param; - UCHAR bssid[ADDRLEN]; - UCHAR net_initiated; - UCHAR net_default_tx_rate; - UCHAR encryption; -}; -struct join_network_cmd { - UCHAR update_param; - UCHAR bssid[ADDRLEN]; - UCHAR net_initiated; - UCHAR net_default_tx_rate; - UCHAR encryption; -}; -struct tx_requested_cmd { - - UCHAR tx_data_ptr[2]; - UCHAR tx_data_length[2]; - UCHAR host_reserved[2]; - UCHAR reserved[3]; - UCHAR tx_rate; - UCHAR pow_sav_mode; - UCHAR retries; - UCHAR antenna; -}; -struct tx_requested_cmd_4 { - - UCHAR tx_data_ptr[2]; - UCHAR tx_data_length[2]; - UCHAR dest_addr[ADDRLEN]; - UCHAR pow_sav_mode; - UCHAR retries; - UCHAR station_id; -}; -struct memory_dump_cmd { - UCHAR memory_type; - UCHAR memory_ptr[2]; - UCHAR length; -}; -struct update_association_cmd { - UCHAR status; - UCHAR aid[2]; -}; -struct start_timer_cmd { - UCHAR duration[2]; -}; - -struct ccs { - UCHAR buffer_status; /* 0 = buffer free, 1 = buffer busy */ - /* 2 = command complete, 3 = failed */ - UCHAR cmd; /* command to ECF */ - UCHAR link; /* link to next CCS, FF=end of list */ - /* command specific parameters */ - union { - char reserved[13]; - struct update_param_cmd update_param; - struct report_param_cmd report_param; - UCHAR nummulticast; - UCHAR mode; - struct start_network_cmd start_network; - struct join_network_cmd join_network; - struct tx_requested_cmd tx_request; - struct memory_dump_cmd memory_dump; - struct update_association_cmd update_assoc; - struct start_timer_cmd start_timer; - } var; -}; - -/*****************************************************************************/ -/* Transmit buffer structures */ -struct tib_structure { - UCHAR ccs_index; - UCHAR psm; - UCHAR pass_fail; - UCHAR retry_count; - UCHAR max_retries; - UCHAR frags_remaining; - UCHAR no_rb; - UCHAR rts_reqd; - UCHAR csma_tx_cntrl_2; - UCHAR sifs_tx_cntrl_2; - UCHAR tx_dma_addr_1[2]; - UCHAR tx_dma_addr_2[2]; - UCHAR var_dur_2mhz[2]; - UCHAR var_dur_1mhz[2]; - UCHAR max_dur_2mhz[2]; - UCHAR max_dur_1mhz[2]; - UCHAR hdr_len; - UCHAR max_frag_len[2]; - UCHAR var_len[2]; - UCHAR phy_hdr_4; - UCHAR mac_hdr_1; - UCHAR mac_hdr_2; - UCHAR sid[2]; -}; - -struct phy_header { - UCHAR sfd[2]; - UCHAR hdr_3; - UCHAR hdr_4; -}; -struct ray_rx_msg { - struct mac_header mac; - UCHAR var[]; -}; - -struct tx_msg { - struct tib_structure tib; - struct phy_header phy; - struct mac_header mac; - UCHAR var[]; -}; - -/****** ECF Receive Control Structure (RCS) Area at Shared RAM offset 0x0800 */ -/* Structures for command specific parameters (rcs.var) */ -struct rx_packet_cmd { - UCHAR rx_data_ptr[2]; - UCHAR rx_data_length[2]; - UCHAR rx_sig_lev; - UCHAR next_frag_rcs_index; - UCHAR totalpacketlength[2]; -}; -struct rejoin_net_cmplt_cmd { - UCHAR reserved; - UCHAR bssid[ADDRLEN]; -}; -struct japan_call_sign_rxd { - UCHAR rxd_call_sign[8]; - UCHAR reserved[5]; -}; - -struct rcs { - UCHAR buffer_status; - UCHAR interrupt_id; - UCHAR link_field; - /* command specific parameters */ - union { - UCHAR reserved[13]; - struct rx_packet_cmd rx_packet; - struct rejoin_net_cmplt_cmd rejoin_net_complete; - struct japan_call_sign_rxd japan_call_sign; - } var; -}; - -/****** Startup parameter structures for both versions of firmware ***********/ -struct b4_startup_params { - UCHAR a_network_type; /* C_ADHOC, C_INFRA */ - UCHAR a_acting_as_ap_status; /* C_TYPE_STA, C_TYPE_AP */ - UCHAR a_current_ess_id[ESSID_SIZE]; /* Null terminated unless 32 long */ - UCHAR a_scanning_mode; /* passive 0, active 1 */ - UCHAR a_power_mgt_state; /* CAM 0, */ - UCHAR a_mac_addr[ADDRLEN]; /* */ - UCHAR a_frag_threshold[2]; /* 512 */ - UCHAR a_hop_time[2]; /* 16k * 2**n, n=0-4 in Kus */ - UCHAR a_beacon_period[2]; /* n * a_hop_time in Kus */ - UCHAR a_dtim_period; /* in beacons */ - UCHAR a_retry_max; /* */ - UCHAR a_ack_timeout; /* */ - UCHAR a_sifs; /* */ - UCHAR a_difs; /* */ - UCHAR a_pifs; /* */ - UCHAR a_rts_threshold[2]; /* */ - UCHAR a_scan_dwell_time[2]; /* */ - UCHAR a_max_scan_dwell_time[2]; /* */ - UCHAR a_assoc_resp_timeout_thresh; /* */ - UCHAR a_adhoc_scan_cycle_max; /* */ - UCHAR a_infra_scan_cycle_max; /* */ - UCHAR a_infra_super_scan_cycle_max; /* */ - UCHAR a_promiscuous_mode; /* */ - UCHAR a_unique_word[2]; /* */ - UCHAR a_slot_time; /* */ - UCHAR a_roaming_low_snr_thresh; /* */ - UCHAR a_low_snr_count_thresh; /* */ - UCHAR a_infra_missed_bcn_thresh; /* */ - UCHAR a_adhoc_missed_bcn_thresh; /* */ - UCHAR a_curr_country_code; /* C_USA */ - UCHAR a_hop_pattern; /* */ - UCHAR a_hop_pattern_length; /* */ -/* b4 - b5 differences start here */ - UCHAR a_cw_max; /* */ - UCHAR a_cw_min; /* */ - UCHAR a_noise_filter_gain; /* */ - UCHAR a_noise_limit_offset; /* */ - UCHAR a_det_rssi_thresh_offset; /* */ - UCHAR a_med_busy_thresh_offset; /* */ - UCHAR a_det_sync_thresh; /* */ - UCHAR a_test_mode; /* */ - UCHAR a_test_min_chan_num; /* */ - UCHAR a_test_max_chan_num; /* */ - UCHAR a_rx_tx_delay; /* */ - UCHAR a_current_bss_id[ADDRLEN]; /* */ - UCHAR a_hop_set; /* */ -}; -struct b5_startup_params { - UCHAR a_network_type; /* C_ADHOC, C_INFRA */ - UCHAR a_acting_as_ap_status; /* C_TYPE_STA, C_TYPE_AP */ - UCHAR a_current_ess_id[ESSID_SIZE]; /* Null terminated unless 32 long */ - UCHAR a_scanning_mode; /* passive 0, active 1 */ - UCHAR a_power_mgt_state; /* CAM 0, */ - UCHAR a_mac_addr[ADDRLEN]; /* */ - UCHAR a_frag_threshold[2]; /* 512 */ - UCHAR a_hop_time[2]; /* 16k * 2**n, n=0-4 in Kus */ - UCHAR a_beacon_period[2]; /* n * a_hop_time in Kus */ - UCHAR a_dtim_period; /* in beacons */ - UCHAR a_retry_max; /* 4 */ - UCHAR a_ack_timeout; /* */ - UCHAR a_sifs; /* */ - UCHAR a_difs; /* */ - UCHAR a_pifs; /* */ - UCHAR a_rts_threshold[2]; /* */ - UCHAR a_scan_dwell_time[2]; /* */ - UCHAR a_max_scan_dwell_time[2]; /* */ - UCHAR a_assoc_resp_timeout_thresh; /* */ - UCHAR a_adhoc_scan_cycle_max; /* */ - UCHAR a_infra_scan_cycle_max; /* */ - UCHAR a_infra_super_scan_cycle_max; /* */ - UCHAR a_promiscuous_mode; /* */ - UCHAR a_unique_word[2]; /* */ - UCHAR a_slot_time; /* */ - UCHAR a_roaming_low_snr_thresh; /* */ - UCHAR a_low_snr_count_thresh; /* */ - UCHAR a_infra_missed_bcn_thresh; /* */ - UCHAR a_adhoc_missed_bcn_thresh; /* */ - UCHAR a_curr_country_code; /* C_USA */ - UCHAR a_hop_pattern; /* */ - UCHAR a_hop_pattern_length; /* */ -/* b4 - b5 differences start here */ - UCHAR a_cw_max[2]; /* */ - UCHAR a_cw_min[2]; /* */ - UCHAR a_noise_filter_gain; /* */ - UCHAR a_noise_limit_offset; /* */ - UCHAR a_det_rssi_thresh_offset; /* */ - UCHAR a_med_busy_thresh_offset; /* */ - UCHAR a_det_sync_thresh; /* */ - UCHAR a_test_mode; /* */ - UCHAR a_test_min_chan_num; /* */ - UCHAR a_test_max_chan_num; /* */ - UCHAR a_allow_bcast_SSID_probe_rsp; - UCHAR a_privacy_must_start; - UCHAR a_privacy_can_join; - UCHAR a_basic_rate_set[8]; -}; - -/*****************************************************************************/ -#define RAY_IOCG_PARMS (SIOCDEVPRIVATE) -#define RAY_IOCS_PARMS (SIOCDEVPRIVATE + 1) -#define RAY_DO_CMD (SIOCDEVPRIVATE + 2) - -/****** ethernet <-> 802.11 translation **************************************/ -typedef struct snaphdr_t -{ - UCHAR dsap; - UCHAR ssap; - UCHAR ctrl; - UCHAR org[3]; - UCHAR ethertype[2]; -} snaphdr_t; - -#define BRIDGE_ENCAP 0xf80000 -#define RFC1042_ENCAP 0 -#define SNAP_ID 0x0003aaaa -#define RAY_IPX_TYPE 0x8137 -#define APPLEARP_TYPE 0x80f3 -/*****************************************************************************/ -#endif /* _RAYCTL_H_ */ diff --git a/drivers/net/wireless/legacy/rndis_wlan.c b/drivers/net/wireless/legacy/rndis_wlan.c deleted file mode 100644 index e7fea7ded6d5c..0000000000000 --- a/drivers/net/wireless/legacy/rndis_wlan.c +++ /dev/null @@ -1,3760 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Driver for RNDIS based USB wireless devices. - * - * Copyright (C) 2007 by Bjorge Dijkstra - * Copyright (C) 2008-2009 by Jussi Kivilinna - * - * Portions of this file are based on NDISwrapper project, - * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani - * http://ndiswrapper.sourceforge.net/ - */ - -// #define DEBUG // error path messages, extra info -// #define VERBOSE // more; success messages - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* NOTE: All these are settings for Broadcom chipset */ -static char modparam_country[4] = "EU"; -module_param_string(country, modparam_country, 4, 0444); -MODULE_PARM_DESC(country, "Country code (ISO 3166-1 alpha-2), default: EU"); - -static int modparam_frameburst = 1; -module_param_named(frameburst, modparam_frameburst, int, 0444); -MODULE_PARM_DESC(frameburst, "enable frame bursting (default: on)"); - -static int modparam_afterburner = 0; -module_param_named(afterburner, modparam_afterburner, int, 0444); -MODULE_PARM_DESC(afterburner, - "enable afterburner aka '125 High Speed Mode' (default: off)"); - -static int modparam_power_save = 0; -module_param_named(power_save, modparam_power_save, int, 0444); -MODULE_PARM_DESC(power_save, - "set power save mode: 0=off, 1=on, 2=fast (default: off)"); - -static int modparam_power_output = 3; -module_param_named(power_output, modparam_power_output, int, 0444); -MODULE_PARM_DESC(power_output, - "set power output: 0=25%, 1=50%, 2=75%, 3=100% (default: 100%)"); - -static int modparam_roamtrigger = -70; -module_param_named(roamtrigger, modparam_roamtrigger, int, 0444); -MODULE_PARM_DESC(roamtrigger, - "set roaming dBm trigger: -80=optimize for distance, " - "-60=bandwidth (default: -70)"); - -static int modparam_roamdelta = 1; -module_param_named(roamdelta, modparam_roamdelta, int, 0444); -MODULE_PARM_DESC(roamdelta, - "set roaming tendency: 0=aggressive, 1=moderate, " - "2=conservative (default: moderate)"); - -static int modparam_workaround_interval; -module_param_named(workaround_interval, modparam_workaround_interval, - int, 0444); -MODULE_PARM_DESC(workaround_interval, - "set stall workaround interval in msecs (0=disabled) (default: 0)"); - -/* Typical noise/maximum signal level values taken from ndiswrapper iw_ndis.h */ -#define WL_NOISE -96 /* typical noise level in dBm */ -#define WL_SIGMAX -32 /* typical maximum signal level in dBm */ - - -/* Assume that Broadcom 4320 (only chipset at time of writing known to be - * based on wireless rndis) has default txpower of 13dBm. - * This value is from Linksys WUSB54GSC User Guide, Appendix F: Specifications. - * 100% : 20 mW ~ 13dBm - * 75% : 15 mW ~ 12dBm - * 50% : 10 mW ~ 10dBm - * 25% : 5 mW ~ 7dBm - */ -#define BCM4320_DEFAULT_TXPOWER_DBM_100 13 -#define BCM4320_DEFAULT_TXPOWER_DBM_75 12 -#define BCM4320_DEFAULT_TXPOWER_DBM_50 10 -#define BCM4320_DEFAULT_TXPOWER_DBM_25 7 - -/* Known device types */ -#define RNDIS_UNKNOWN 0 -#define RNDIS_BCM4320A 1 -#define RNDIS_BCM4320B 2 - - -/* NDIS data structures. Taken from wpa_supplicant driver_ndis.c - * slightly modified for datatype endianess, etc - */ -#define NDIS_802_11_LENGTH_SSID 32 -#define NDIS_802_11_LENGTH_RATES 8 -#define NDIS_802_11_LENGTH_RATES_EX 16 - -enum ndis_80211_net_type { - NDIS_80211_TYPE_FREQ_HOP, - NDIS_80211_TYPE_DIRECT_SEQ, - NDIS_80211_TYPE_OFDM_A, - NDIS_80211_TYPE_OFDM_G -}; - -enum ndis_80211_net_infra { - NDIS_80211_INFRA_ADHOC, - NDIS_80211_INFRA_INFRA, - NDIS_80211_INFRA_AUTO_UNKNOWN -}; - -enum ndis_80211_auth_mode { - NDIS_80211_AUTH_OPEN, - NDIS_80211_AUTH_SHARED, - NDIS_80211_AUTH_AUTO_SWITCH, - NDIS_80211_AUTH_WPA, - NDIS_80211_AUTH_WPA_PSK, - NDIS_80211_AUTH_WPA_NONE, - NDIS_80211_AUTH_WPA2, - NDIS_80211_AUTH_WPA2_PSK -}; - -enum ndis_80211_encr_status { - NDIS_80211_ENCR_WEP_ENABLED, - NDIS_80211_ENCR_DISABLED, - NDIS_80211_ENCR_WEP_KEY_ABSENT, - NDIS_80211_ENCR_NOT_SUPPORTED, - NDIS_80211_ENCR_TKIP_ENABLED, - NDIS_80211_ENCR_TKIP_KEY_ABSENT, - NDIS_80211_ENCR_CCMP_ENABLED, - NDIS_80211_ENCR_CCMP_KEY_ABSENT -}; - -enum ndis_80211_priv_filter { - NDIS_80211_PRIV_ACCEPT_ALL, - NDIS_80211_PRIV_8021X_WEP -}; - -enum ndis_80211_status_type { - NDIS_80211_STATUSTYPE_AUTHENTICATION, - NDIS_80211_STATUSTYPE_MEDIASTREAMMODE, - NDIS_80211_STATUSTYPE_PMKID_CANDIDATELIST, - NDIS_80211_STATUSTYPE_RADIOSTATE, -}; - -enum ndis_80211_media_stream_mode { - NDIS_80211_MEDIA_STREAM_OFF, - NDIS_80211_MEDIA_STREAM_ON -}; - -enum ndis_80211_radio_status { - NDIS_80211_RADIO_STATUS_ON, - NDIS_80211_RADIO_STATUS_HARDWARE_OFF, - NDIS_80211_RADIO_STATUS_SOFTWARE_OFF, -}; - -enum ndis_80211_addkey_bits { - NDIS_80211_ADDKEY_8021X_AUTH = cpu_to_le32(1 << 28), - NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ = cpu_to_le32(1 << 29), - NDIS_80211_ADDKEY_PAIRWISE_KEY = cpu_to_le32(1 << 30), - NDIS_80211_ADDKEY_TRANSMIT_KEY = cpu_to_le32(1 << 31) -}; - -enum ndis_80211_addwep_bits { - NDIS_80211_ADDWEP_PERCLIENT_KEY = cpu_to_le32(1 << 30), - NDIS_80211_ADDWEP_TRANSMIT_KEY = cpu_to_le32(1 << 31) -}; - -enum ndis_80211_power_mode { - NDIS_80211_POWER_MODE_CAM, - NDIS_80211_POWER_MODE_MAX_PSP, - NDIS_80211_POWER_MODE_FAST_PSP, -}; - -enum ndis_80211_pmkid_cand_list_flag_bits { - NDIS_80211_PMKID_CAND_PREAUTH = cpu_to_le32(1 << 0) -}; - -struct ndis_80211_auth_request { - __le32 length; - u8 bssid[ETH_ALEN]; - u8 padding[2]; - __le32 flags; -} __packed; - -struct ndis_80211_pmkid_candidate { - u8 bssid[ETH_ALEN]; - u8 padding[2]; - __le32 flags; -} __packed; - -struct ndis_80211_pmkid_cand_list { - __le32 version; - __le32 num_candidates; - struct ndis_80211_pmkid_candidate candidate_list[]; -} __packed; - -struct ndis_80211_status_indication { - __le32 status_type; - union { - __le32 media_stream_mode; - __le32 radio_status; - DECLARE_FLEX_ARRAY(struct ndis_80211_auth_request, auth_request); - struct ndis_80211_pmkid_cand_list cand_list; - } u; -} __packed; - -struct ndis_80211_ssid { - __le32 length; - u8 essid[NDIS_802_11_LENGTH_SSID]; -} __packed; - -struct ndis_80211_conf_freq_hop { - __le32 length; - __le32 hop_pattern; - __le32 hop_set; - __le32 dwell_time; -} __packed; - -struct ndis_80211_conf { - __le32 length; - __le32 beacon_period; - __le32 atim_window; - __le32 ds_config; - struct ndis_80211_conf_freq_hop fh_config; -} __packed; - -struct ndis_80211_bssid_ex { - __le32 length; - u8 mac[ETH_ALEN]; - u8 padding[2]; - struct ndis_80211_ssid ssid; - __le32 privacy; - __le32 rssi; - __le32 net_type; - struct ndis_80211_conf config; - __le32 net_infra; - u8 rates[NDIS_802_11_LENGTH_RATES_EX]; - __le32 ie_length; - u8 ies[]; -} __packed; - -struct ndis_80211_bssid_list_ex { - __le32 num_items; - u8 bssid_data[]; -} __packed; - -struct ndis_80211_fixed_ies { - u8 timestamp[8]; - __le16 beacon_interval; - __le16 capabilities; -} __packed; - -struct ndis_80211_wep_key { - __le32 size; - __le32 index; - __le32 length; - u8 material[32]; -} __packed; - -struct ndis_80211_key { - __le32 size; - __le32 index; - __le32 length; - u8 bssid[ETH_ALEN]; - u8 padding[6]; - u8 rsc[8]; - u8 material[32]; -} __packed; - -struct ndis_80211_remove_key { - __le32 size; - __le32 index; - u8 bssid[ETH_ALEN]; - u8 padding[2]; -} __packed; - -struct ndis_config_param { - __le32 name_offs; - __le32 name_length; - __le32 type; - __le32 value_offs; - __le32 value_length; -} __packed; - -struct ndis_80211_assoc_info { - __le32 length; - __le16 req_ies; - struct req_ie { - __le16 capa; - __le16 listen_interval; - u8 cur_ap_address[ETH_ALEN]; - } req_ie; - __le32 req_ie_length; - __le32 offset_req_ies; - __le16 resp_ies; - struct resp_ie { - __le16 capa; - __le16 status_code; - __le16 assoc_id; - } resp_ie; - __le32 resp_ie_length; - __le32 offset_resp_ies; -} __packed; - -struct ndis_80211_capability { - __le32 length; - __le32 version; - __le32 num_pmkids; - __le32 num_auth_encr_pair; -} __packed; - -struct ndis_80211_bssid_info { - u8 bssid[ETH_ALEN]; - u8 pmkid[16]; -} __packed; - -struct ndis_80211_pmkid { - __le32 length; - __le32 bssid_info_count; - struct ndis_80211_bssid_info bssid_info[]; -} __packed; - -/* - * private data - */ -#define CAP_MODE_80211A 1 -#define CAP_MODE_80211B 2 -#define CAP_MODE_80211G 4 -#define CAP_MODE_MASK 7 - -#define WORK_LINK_UP 0 -#define WORK_LINK_DOWN 1 -#define WORK_SET_MULTICAST_LIST 2 - -#define RNDIS_WLAN_ALG_NONE 0 -#define RNDIS_WLAN_ALG_WEP (1<<0) -#define RNDIS_WLAN_ALG_TKIP (1<<1) -#define RNDIS_WLAN_ALG_CCMP (1<<2) - -#define RNDIS_WLAN_NUM_KEYS 4 -#define RNDIS_WLAN_KEY_MGMT_NONE 0 -#define RNDIS_WLAN_KEY_MGMT_802_1X (1<<0) -#define RNDIS_WLAN_KEY_MGMT_PSK (1<<1) - -#define COMMAND_BUFFER_SIZE (CONTROL_BUFFER_SIZE + sizeof(struct rndis_set)) - -static const struct ieee80211_channel rndis_channels[] = { - { .center_freq = 2412 }, - { .center_freq = 2417 }, - { .center_freq = 2422 }, - { .center_freq = 2427 }, - { .center_freq = 2432 }, - { .center_freq = 2437 }, - { .center_freq = 2442 }, - { .center_freq = 2447 }, - { .center_freq = 2452 }, - { .center_freq = 2457 }, - { .center_freq = 2462 }, - { .center_freq = 2467 }, - { .center_freq = 2472 }, - { .center_freq = 2484 }, -}; - -static const struct ieee80211_rate rndis_rates[] = { - { .bitrate = 10 }, - { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 60 }, - { .bitrate = 90 }, - { .bitrate = 120 }, - { .bitrate = 180 }, - { .bitrate = 240 }, - { .bitrate = 360 }, - { .bitrate = 480 }, - { .bitrate = 540 } -}; - -static const u32 rndis_cipher_suites[] = { - WLAN_CIPHER_SUITE_WEP40, - WLAN_CIPHER_SUITE_WEP104, - WLAN_CIPHER_SUITE_TKIP, - WLAN_CIPHER_SUITE_CCMP, -}; - -struct rndis_wlan_encr_key { - int len; - u32 cipher; - u8 material[32]; - u8 bssid[ETH_ALEN]; - bool pairwise; - bool tx_key; -}; - -/* RNDIS device private data */ -struct rndis_wlan_private { - struct usbnet *usbdev; - - struct wireless_dev wdev; - - struct cfg80211_scan_request *scan_request; - - struct workqueue_struct *workqueue; - struct delayed_work dev_poller_work; - struct delayed_work scan_work; - struct work_struct work; - struct mutex command_lock; - unsigned long work_pending; - int last_qual; - s32 cqm_rssi_thold; - u32 cqm_rssi_hyst; - int last_cqm_event_rssi; - - struct ieee80211_supported_band band; - struct ieee80211_channel channels[ARRAY_SIZE(rndis_channels)]; - struct ieee80211_rate rates[ARRAY_SIZE(rndis_rates)]; - u32 cipher_suites[ARRAY_SIZE(rndis_cipher_suites)]; - - int device_type; - int caps; - int multicast_size; - - /* module parameters */ - char param_country[4]; - int param_frameburst; - int param_afterburner; - int param_power_save; - int param_power_output; - int param_roamtrigger; - int param_roamdelta; - u32 param_workaround_interval; - - /* hardware state */ - bool radio_on; - int power_mode; - int infra_mode; - bool connected; - u8 bssid[ETH_ALEN]; - u32 current_command_oid; - - /* encryption stuff */ - u8 encr_tx_key_index; - struct rndis_wlan_encr_key encr_keys[RNDIS_WLAN_NUM_KEYS]; - int wpa_version; - - u8 command_buffer[COMMAND_BUFFER_SIZE]; -}; - -/* - * cfg80211 ops - */ -static int rndis_change_virtual_intf(struct wiphy *wiphy, - struct net_device *dev, - enum nl80211_iftype type, - struct vif_params *params); - -static int rndis_scan(struct wiphy *wiphy, - struct cfg80211_scan_request *request); - -static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed); - -static int rndis_set_tx_power(struct wiphy *wiphy, - struct wireless_dev *wdev, - enum nl80211_tx_power_setting type, - int mbm); -static int rndis_get_tx_power(struct wiphy *wiphy, - struct wireless_dev *wdev, - int *dbm); - -static int rndis_connect(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_connect_params *sme); - -static int rndis_disconnect(struct wiphy *wiphy, struct net_device *dev, - u16 reason_code); - -static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_ibss_params *params); - -static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev); - -static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev, - int link_id, u8 key_index, bool pairwise, - const u8 *mac_addr, struct key_params *params); - -static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev, - int link_id, u8 key_index, bool pairwise, - const u8 *mac_addr); - -static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev, - int link_id, u8 key_index, bool unicast, - bool multicast); - -static int rndis_get_station(struct wiphy *wiphy, struct net_device *dev, - const u8 *mac, struct station_info *sinfo); - -static int rndis_dump_station(struct wiphy *wiphy, struct net_device *dev, - int idx, u8 *mac, struct station_info *sinfo); - -static int rndis_set_pmksa(struct wiphy *wiphy, struct net_device *netdev, - struct cfg80211_pmksa *pmksa); - -static int rndis_del_pmksa(struct wiphy *wiphy, struct net_device *netdev, - struct cfg80211_pmksa *pmksa); - -static int rndis_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev); - -static int rndis_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, - bool enabled, int timeout); - -static int rndis_set_cqm_rssi_config(struct wiphy *wiphy, - struct net_device *dev, - s32 rssi_thold, u32 rssi_hyst); - -static const struct cfg80211_ops rndis_config_ops = { - .change_virtual_intf = rndis_change_virtual_intf, - .scan = rndis_scan, - .set_wiphy_params = rndis_set_wiphy_params, - .set_tx_power = rndis_set_tx_power, - .get_tx_power = rndis_get_tx_power, - .connect = rndis_connect, - .disconnect = rndis_disconnect, - .join_ibss = rndis_join_ibss, - .leave_ibss = rndis_leave_ibss, - .add_key = rndis_add_key, - .del_key = rndis_del_key, - .set_default_key = rndis_set_default_key, - .get_station = rndis_get_station, - .dump_station = rndis_dump_station, - .set_pmksa = rndis_set_pmksa, - .del_pmksa = rndis_del_pmksa, - .flush_pmksa = rndis_flush_pmksa, - .set_power_mgmt = rndis_set_power_mgmt, - .set_cqm_rssi_config = rndis_set_cqm_rssi_config, -}; - -static void *rndis_wiphy_privid = &rndis_wiphy_privid; - - -static struct rndis_wlan_private *get_rndis_wlan_priv(struct usbnet *dev) -{ - return (struct rndis_wlan_private *)dev->driver_priv; -} - -static u32 get_bcm4320_power_dbm(struct rndis_wlan_private *priv) -{ - switch (priv->param_power_output) { - default: - case 3: - return BCM4320_DEFAULT_TXPOWER_DBM_100; - case 2: - return BCM4320_DEFAULT_TXPOWER_DBM_75; - case 1: - return BCM4320_DEFAULT_TXPOWER_DBM_50; - case 0: - return BCM4320_DEFAULT_TXPOWER_DBM_25; - } -} - -static bool is_wpa_key(struct rndis_wlan_private *priv, u8 idx) -{ - int cipher = priv->encr_keys[idx].cipher; - - return (cipher == WLAN_CIPHER_SUITE_CCMP || - cipher == WLAN_CIPHER_SUITE_TKIP); -} - -static int rndis_cipher_to_alg(u32 cipher) -{ - switch (cipher) { - default: - return RNDIS_WLAN_ALG_NONE; - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: - return RNDIS_WLAN_ALG_WEP; - case WLAN_CIPHER_SUITE_TKIP: - return RNDIS_WLAN_ALG_TKIP; - case WLAN_CIPHER_SUITE_CCMP: - return RNDIS_WLAN_ALG_CCMP; - } -} - -static int rndis_akm_suite_to_key_mgmt(u32 akm_suite) -{ - switch (akm_suite) { - default: - return RNDIS_WLAN_KEY_MGMT_NONE; - case WLAN_AKM_SUITE_8021X: - return RNDIS_WLAN_KEY_MGMT_802_1X; - case WLAN_AKM_SUITE_PSK: - return RNDIS_WLAN_KEY_MGMT_PSK; - } -} - -#ifdef DEBUG -static const char *oid_to_string(u32 oid) -{ - switch (oid) { -#define OID_STR(oid) case oid: return(#oid) - /* from rndis_host.h */ - OID_STR(RNDIS_OID_802_3_PERMANENT_ADDRESS); - OID_STR(RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE); - OID_STR(RNDIS_OID_GEN_CURRENT_PACKET_FILTER); - OID_STR(RNDIS_OID_GEN_PHYSICAL_MEDIUM); - - /* from rndis_wlan.c */ - OID_STR(RNDIS_OID_GEN_LINK_SPEED); - OID_STR(RNDIS_OID_GEN_RNDIS_CONFIG_PARAMETER); - - OID_STR(RNDIS_OID_GEN_XMIT_OK); - OID_STR(RNDIS_OID_GEN_RCV_OK); - OID_STR(RNDIS_OID_GEN_XMIT_ERROR); - OID_STR(RNDIS_OID_GEN_RCV_ERROR); - OID_STR(RNDIS_OID_GEN_RCV_NO_BUFFER); - - OID_STR(RNDIS_OID_802_3_CURRENT_ADDRESS); - OID_STR(RNDIS_OID_802_3_MULTICAST_LIST); - OID_STR(RNDIS_OID_802_3_MAXIMUM_LIST_SIZE); - - OID_STR(RNDIS_OID_802_11_BSSID); - OID_STR(RNDIS_OID_802_11_SSID); - OID_STR(RNDIS_OID_802_11_INFRASTRUCTURE_MODE); - OID_STR(RNDIS_OID_802_11_ADD_WEP); - OID_STR(RNDIS_OID_802_11_REMOVE_WEP); - OID_STR(RNDIS_OID_802_11_DISASSOCIATE); - OID_STR(RNDIS_OID_802_11_AUTHENTICATION_MODE); - OID_STR(RNDIS_OID_802_11_PRIVACY_FILTER); - OID_STR(RNDIS_OID_802_11_BSSID_LIST_SCAN); - OID_STR(RNDIS_OID_802_11_ENCRYPTION_STATUS); - OID_STR(RNDIS_OID_802_11_ADD_KEY); - OID_STR(RNDIS_OID_802_11_REMOVE_KEY); - OID_STR(RNDIS_OID_802_11_ASSOCIATION_INFORMATION); - OID_STR(RNDIS_OID_802_11_CAPABILITY); - OID_STR(RNDIS_OID_802_11_PMKID); - OID_STR(RNDIS_OID_802_11_NETWORK_TYPES_SUPPORTED); - OID_STR(RNDIS_OID_802_11_NETWORK_TYPE_IN_USE); - OID_STR(RNDIS_OID_802_11_TX_POWER_LEVEL); - OID_STR(RNDIS_OID_802_11_RSSI); - OID_STR(RNDIS_OID_802_11_RSSI_TRIGGER); - OID_STR(RNDIS_OID_802_11_FRAGMENTATION_THRESHOLD); - OID_STR(RNDIS_OID_802_11_RTS_THRESHOLD); - OID_STR(RNDIS_OID_802_11_SUPPORTED_RATES); - OID_STR(RNDIS_OID_802_11_CONFIGURATION); - OID_STR(RNDIS_OID_802_11_POWER_MODE); - OID_STR(RNDIS_OID_802_11_BSSID_LIST); -#undef OID_STR - } - - return "?"; -} -#else -static const char *oid_to_string(u32 oid) -{ - return "?"; -} -#endif - -/* translate error code */ -static int rndis_error_status(__le32 rndis_status) -{ - int ret = -EINVAL; - switch (le32_to_cpu(rndis_status)) { - case RNDIS_STATUS_SUCCESS: - ret = 0; - break; - case RNDIS_STATUS_FAILURE: - case RNDIS_STATUS_INVALID_DATA: - ret = -EINVAL; - break; - case RNDIS_STATUS_NOT_SUPPORTED: - ret = -EOPNOTSUPP; - break; - case RNDIS_STATUS_ADAPTER_NOT_READY: - case RNDIS_STATUS_ADAPTER_NOT_OPEN: - ret = -EBUSY; - break; - } - return ret; -} - -static int rndis_query_oid(struct usbnet *dev, u32 oid, void *data, int *len) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(dev); - union { - void *buf; - struct rndis_msg_hdr *header; - struct rndis_query *get; - struct rndis_query_c *get_c; - } u; - int ret; - size_t buflen, resplen, respoffs, copylen; - - buflen = *len + sizeof(*u.get); - if (buflen < CONTROL_BUFFER_SIZE) - buflen = CONTROL_BUFFER_SIZE; - - if (buflen > COMMAND_BUFFER_SIZE) { - u.buf = kmalloc(buflen, GFP_KERNEL); - if (!u.buf) - return -ENOMEM; - } else { - u.buf = priv->command_buffer; - } - - mutex_lock(&priv->command_lock); - - memset(u.get, 0, sizeof *u.get); - u.get->msg_type = cpu_to_le32(RNDIS_MSG_QUERY); - u.get->msg_len = cpu_to_le32(sizeof *u.get); - u.get->oid = cpu_to_le32(oid); - - priv->current_command_oid = oid; - ret = rndis_command(dev, u.header, buflen); - priv->current_command_oid = 0; - if (ret < 0) - netdev_dbg(dev->net, "%s(%s): rndis_command() failed, %d (%08x)\n", - __func__, oid_to_string(oid), ret, - le32_to_cpu(u.get_c->status)); - - if (ret == 0) { - resplen = le32_to_cpu(u.get_c->len); - respoffs = le32_to_cpu(u.get_c->offset) + 8; - - if (respoffs > buflen) { - /* Device returned data offset outside buffer, error. */ - netdev_dbg(dev->net, - "%s(%s): received invalid data offset: %zu > %zu\n", - __func__, oid_to_string(oid), respoffs, buflen); - - ret = -EINVAL; - goto exit_unlock; - } - - copylen = min(resplen, buflen - respoffs); - - if (copylen > *len) - copylen = *len; - - memcpy(data, u.buf + respoffs, copylen); - - *len = resplen; - - ret = rndis_error_status(u.get_c->status); - if (ret < 0) - netdev_dbg(dev->net, "%s(%s): device returned error, 0x%08x (%d)\n", - __func__, oid_to_string(oid), - le32_to_cpu(u.get_c->status), ret); - } - -exit_unlock: - mutex_unlock(&priv->command_lock); - - if (u.buf != priv->command_buffer) - kfree(u.buf); - return ret; -} - -static int rndis_set_oid(struct usbnet *dev, u32 oid, const void *data, - int len) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(dev); - union { - void *buf; - struct rndis_msg_hdr *header; - struct rndis_set *set; - struct rndis_set_c *set_c; - } u; - int ret, buflen; - - buflen = len + sizeof(*u.set); - if (buflen < CONTROL_BUFFER_SIZE) - buflen = CONTROL_BUFFER_SIZE; - - if (buflen > COMMAND_BUFFER_SIZE) { - u.buf = kmalloc(buflen, GFP_KERNEL); - if (!u.buf) - return -ENOMEM; - } else { - u.buf = priv->command_buffer; - } - - mutex_lock(&priv->command_lock); - - memset(u.set, 0, sizeof *u.set); - u.set->msg_type = cpu_to_le32(RNDIS_MSG_SET); - u.set->msg_len = cpu_to_le32(sizeof(*u.set) + len); - u.set->oid = cpu_to_le32(oid); - u.set->len = cpu_to_le32(len); - u.set->offset = cpu_to_le32(sizeof(*u.set) - 8); - u.set->handle = cpu_to_le32(0); - memcpy(u.buf + sizeof(*u.set), data, len); - - priv->current_command_oid = oid; - ret = rndis_command(dev, u.header, buflen); - priv->current_command_oid = 0; - if (ret < 0) - netdev_dbg(dev->net, "%s(%s): rndis_command() failed, %d (%08x)\n", - __func__, oid_to_string(oid), ret, - le32_to_cpu(u.set_c->status)); - - if (ret == 0) { - ret = rndis_error_status(u.set_c->status); - - if (ret < 0) - netdev_dbg(dev->net, "%s(%s): device returned error, 0x%08x (%d)\n", - __func__, oid_to_string(oid), - le32_to_cpu(u.set_c->status), ret); - } - - mutex_unlock(&priv->command_lock); - - if (u.buf != priv->command_buffer) - kfree(u.buf); - return ret; -} - -static int rndis_reset(struct usbnet *usbdev) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct rndis_reset *reset; - int ret; - - mutex_lock(&priv->command_lock); - - reset = (void *)priv->command_buffer; - memset(reset, 0, sizeof(*reset)); - reset->msg_type = cpu_to_le32(RNDIS_MSG_RESET); - reset->msg_len = cpu_to_le32(sizeof(*reset)); - priv->current_command_oid = 0; - ret = rndis_command(usbdev, (void *)reset, CONTROL_BUFFER_SIZE); - - mutex_unlock(&priv->command_lock); - - if (ret < 0) - return ret; - return 0; -} - -/* - * Specs say that we can only set config parameters only soon after device - * initialization. - * value_type: 0 = u32, 2 = unicode string - */ -static int rndis_set_config_parameter(struct usbnet *dev, char *param, - int value_type, void *value) -{ - struct ndis_config_param *infobuf; - int value_len, info_len, param_len, ret, i; - __le16 *unibuf; - __le32 *dst_value; - - if (value_type == 0) - value_len = sizeof(__le32); - else if (value_type == 2) - value_len = strlen(value) * sizeof(__le16); - else - return -EINVAL; - - param_len = strlen(param) * sizeof(__le16); - info_len = sizeof(*infobuf) + param_len + value_len; - -#ifdef DEBUG - info_len += 12; -#endif - infobuf = kmalloc(info_len, GFP_KERNEL); - if (!infobuf) - return -ENOMEM; - -#ifdef DEBUG - info_len -= 12; - /* extra 12 bytes are for padding (debug output) */ - memset(infobuf, 0xCC, info_len + 12); -#endif - - if (value_type == 2) - netdev_dbg(dev->net, "setting config parameter: %s, value: %s\n", - param, (u8 *)value); - else - netdev_dbg(dev->net, "setting config parameter: %s, value: %d\n", - param, *(u32 *)value); - - infobuf->name_offs = cpu_to_le32(sizeof(*infobuf)); - infobuf->name_length = cpu_to_le32(param_len); - infobuf->type = cpu_to_le32(value_type); - infobuf->value_offs = cpu_to_le32(sizeof(*infobuf) + param_len); - infobuf->value_length = cpu_to_le32(value_len); - - /* simple string to unicode string conversion */ - unibuf = (void *)infobuf + sizeof(*infobuf); - for (i = 0; i < param_len / sizeof(__le16); i++) - unibuf[i] = cpu_to_le16(param[i]); - - if (value_type == 2) { - unibuf = (void *)infobuf + sizeof(*infobuf) + param_len; - for (i = 0; i < value_len / sizeof(__le16); i++) - unibuf[i] = cpu_to_le16(((u8 *)value)[i]); - } else { - dst_value = (void *)infobuf + sizeof(*infobuf) + param_len; - *dst_value = cpu_to_le32(*(u32 *)value); - } - -#ifdef DEBUG - netdev_dbg(dev->net, "info buffer (len: %d)\n", info_len); - for (i = 0; i < info_len; i += 12) { - u32 *tmp = (u32 *)((u8 *)infobuf + i); - netdev_dbg(dev->net, "%08X:%08X:%08X\n", - cpu_to_be32(tmp[0]), - cpu_to_be32(tmp[1]), - cpu_to_be32(tmp[2])); - } -#endif - - ret = rndis_set_oid(dev, RNDIS_OID_GEN_RNDIS_CONFIG_PARAMETER, - infobuf, info_len); - if (ret != 0) - netdev_dbg(dev->net, "setting rndis config parameter failed, %d\n", - ret); - - kfree(infobuf); - return ret; -} - -static int rndis_set_config_parameter_str(struct usbnet *dev, - char *param, char *value) -{ - return rndis_set_config_parameter(dev, param, 2, value); -} - -/* - * data conversion functions - */ -static int level_to_qual(int level) -{ - int qual = 100 * (level - WL_NOISE) / (WL_SIGMAX - WL_NOISE); - return qual >= 0 ? (qual <= 100 ? qual : 100) : 0; -} - -/* - * common functions - */ -static int set_infra_mode(struct usbnet *usbdev, int mode); -static void restore_keys(struct usbnet *usbdev); -static int rndis_check_bssid_list(struct usbnet *usbdev, u8 *match_bssid, - bool *matched); - -static int rndis_start_bssid_list_scan(struct usbnet *usbdev) -{ - __le32 tmp; - - /* Note: RNDIS_OID_802_11_BSSID_LIST_SCAN clears internal BSS list. */ - tmp = cpu_to_le32(1); - return rndis_set_oid(usbdev, RNDIS_OID_802_11_BSSID_LIST_SCAN, &tmp, - sizeof(tmp)); -} - -static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - int ret; - - ret = rndis_set_oid(usbdev, RNDIS_OID_802_11_SSID, - ssid, sizeof(*ssid)); - if (ret < 0) { - netdev_warn(usbdev->net, "setting SSID failed (%08X)\n", ret); - return ret; - } - if (ret == 0) { - priv->radio_on = true; - netdev_dbg(usbdev->net, "%s(): radio_on = true\n", __func__); - } - - return ret; -} - -static int set_bssid(struct usbnet *usbdev, const u8 *bssid) -{ - int ret; - - ret = rndis_set_oid(usbdev, RNDIS_OID_802_11_BSSID, - bssid, ETH_ALEN); - if (ret < 0) { - netdev_warn(usbdev->net, "setting BSSID[%pM] failed (%08X)\n", - bssid, ret); - return ret; - } - - return ret; -} - -static int clear_bssid(struct usbnet *usbdev) -{ - static const u8 broadcast_mac[ETH_ALEN] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff - }; - - return set_bssid(usbdev, broadcast_mac); -} - -static int get_bssid(struct usbnet *usbdev, u8 bssid[ETH_ALEN]) -{ - int ret, len; - - len = ETH_ALEN; - ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_BSSID, - bssid, &len); - - if (ret != 0) - eth_zero_addr(bssid); - - return ret; -} - -static int get_association_info(struct usbnet *usbdev, - struct ndis_80211_assoc_info *info, int len) -{ - return rndis_query_oid(usbdev, - RNDIS_OID_802_11_ASSOCIATION_INFORMATION, - info, &len); -} - -static bool is_associated(struct usbnet *usbdev) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - u8 bssid[ETH_ALEN]; - - if (!priv->radio_on) - return false; - - return (get_bssid(usbdev, bssid) == 0 && !is_zero_ether_addr(bssid)); -} - -static int disassociate(struct usbnet *usbdev, bool reset_ssid) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct ndis_80211_ssid ssid; - int i, ret = 0; - - if (priv->radio_on) { - ret = rndis_set_oid(usbdev, - RNDIS_OID_802_11_DISASSOCIATE, - NULL, 0); - if (ret == 0) { - priv->radio_on = false; - netdev_dbg(usbdev->net, "%s(): radio_on = false\n", - __func__); - - if (reset_ssid) - msleep(100); - } - } - - /* disassociate causes radio to be turned off; if reset_ssid - * is given, set random ssid to enable radio */ - if (reset_ssid) { - /* Set device to infrastructure mode so we don't get ad-hoc - * 'media connect' indications with the random ssid. - */ - set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA); - - ssid.length = cpu_to_le32(sizeof(ssid.essid)); - get_random_bytes(&ssid.essid[2], sizeof(ssid.essid)-2); - ssid.essid[0] = 0x1; - ssid.essid[1] = 0xff; - for (i = 2; i < sizeof(ssid.essid); i++) - ssid.essid[i] = 0x1 + (ssid.essid[i] * 0xfe / 0xff); - ret = set_essid(usbdev, &ssid); - } - return ret; -} - -static int set_auth_mode(struct usbnet *usbdev, u32 wpa_version, - enum nl80211_auth_type auth_type, int keymgmt) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - __le32 tmp; - int auth_mode, ret; - - netdev_dbg(usbdev->net, "%s(): wpa_version=0x%x authalg=0x%x keymgmt=0x%x\n", - __func__, wpa_version, auth_type, keymgmt); - - if (wpa_version & NL80211_WPA_VERSION_2) { - if (keymgmt & RNDIS_WLAN_KEY_MGMT_802_1X) - auth_mode = NDIS_80211_AUTH_WPA2; - else - auth_mode = NDIS_80211_AUTH_WPA2_PSK; - } else if (wpa_version & NL80211_WPA_VERSION_1) { - if (keymgmt & RNDIS_WLAN_KEY_MGMT_802_1X) - auth_mode = NDIS_80211_AUTH_WPA; - else if (keymgmt & RNDIS_WLAN_KEY_MGMT_PSK) - auth_mode = NDIS_80211_AUTH_WPA_PSK; - else - auth_mode = NDIS_80211_AUTH_WPA_NONE; - } else if (auth_type == NL80211_AUTHTYPE_SHARED_KEY) - auth_mode = NDIS_80211_AUTH_SHARED; - else if (auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) - auth_mode = NDIS_80211_AUTH_OPEN; - else if (auth_type == NL80211_AUTHTYPE_AUTOMATIC) - auth_mode = NDIS_80211_AUTH_AUTO_SWITCH; - else - return -ENOTSUPP; - - tmp = cpu_to_le32(auth_mode); - ret = rndis_set_oid(usbdev, - RNDIS_OID_802_11_AUTHENTICATION_MODE, - &tmp, sizeof(tmp)); - if (ret != 0) { - netdev_warn(usbdev->net, "setting auth mode failed (%08X)\n", - ret); - return ret; - } - - priv->wpa_version = wpa_version; - - return 0; -} - -static int set_priv_filter(struct usbnet *usbdev) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - __le32 tmp; - - netdev_dbg(usbdev->net, "%s(): wpa_version=0x%x\n", - __func__, priv->wpa_version); - - if (priv->wpa_version & NL80211_WPA_VERSION_2 || - priv->wpa_version & NL80211_WPA_VERSION_1) - tmp = cpu_to_le32(NDIS_80211_PRIV_8021X_WEP); - else - tmp = cpu_to_le32(NDIS_80211_PRIV_ACCEPT_ALL); - - return rndis_set_oid(usbdev, - RNDIS_OID_802_11_PRIVACY_FILTER, &tmp, - sizeof(tmp)); -} - -static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise) -{ - __le32 tmp; - int encr_mode, ret; - - netdev_dbg(usbdev->net, "%s(): cipher_pair=0x%x cipher_group=0x%x\n", - __func__, pairwise, groupwise); - - if (pairwise & RNDIS_WLAN_ALG_CCMP) - encr_mode = NDIS_80211_ENCR_CCMP_ENABLED; - else if (pairwise & RNDIS_WLAN_ALG_TKIP) - encr_mode = NDIS_80211_ENCR_TKIP_ENABLED; - else if (pairwise & RNDIS_WLAN_ALG_WEP) - encr_mode = NDIS_80211_ENCR_WEP_ENABLED; - else if (groupwise & RNDIS_WLAN_ALG_CCMP) - encr_mode = NDIS_80211_ENCR_CCMP_ENABLED; - else if (groupwise & RNDIS_WLAN_ALG_TKIP) - encr_mode = NDIS_80211_ENCR_TKIP_ENABLED; - else - encr_mode = NDIS_80211_ENCR_DISABLED; - - tmp = cpu_to_le32(encr_mode); - ret = rndis_set_oid(usbdev, - RNDIS_OID_802_11_ENCRYPTION_STATUS, &tmp, - sizeof(tmp)); - if (ret != 0) { - netdev_warn(usbdev->net, "setting encr mode failed (%08X)\n", - ret); - return ret; - } - - return 0; -} - -static int set_infra_mode(struct usbnet *usbdev, int mode) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - __le32 tmp; - int ret; - - netdev_dbg(usbdev->net, "%s(): infra_mode=0x%x\n", - __func__, priv->infra_mode); - - tmp = cpu_to_le32(mode); - ret = rndis_set_oid(usbdev, - RNDIS_OID_802_11_INFRASTRUCTURE_MODE, - &tmp, sizeof(tmp)); - if (ret != 0) { - netdev_warn(usbdev->net, "setting infra mode failed (%08X)\n", - ret); - return ret; - } - - /* NDIS drivers clear keys when infrastructure mode is - * changed. But Linux tools assume otherwise. So set the - * keys */ - restore_keys(usbdev); - - priv->infra_mode = mode; - return 0; -} - -static int set_rts_threshold(struct usbnet *usbdev, u32 rts_threshold) -{ - __le32 tmp; - - netdev_dbg(usbdev->net, "%s(): %i\n", __func__, rts_threshold); - - if (rts_threshold == -1 || rts_threshold > 2347) - rts_threshold = 2347; - - tmp = cpu_to_le32(rts_threshold); - return rndis_set_oid(usbdev, - RNDIS_OID_802_11_RTS_THRESHOLD, - &tmp, sizeof(tmp)); -} - -static int set_frag_threshold(struct usbnet *usbdev, u32 frag_threshold) -{ - __le32 tmp; - - netdev_dbg(usbdev->net, "%s(): %i\n", __func__, frag_threshold); - - if (frag_threshold < 256 || frag_threshold > 2346) - frag_threshold = 2346; - - tmp = cpu_to_le32(frag_threshold); - return rndis_set_oid(usbdev, - RNDIS_OID_802_11_FRAGMENTATION_THRESHOLD, - &tmp, sizeof(tmp)); -} - -static void set_default_iw_params(struct usbnet *usbdev) -{ - set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA); - set_auth_mode(usbdev, 0, NL80211_AUTHTYPE_OPEN_SYSTEM, - RNDIS_WLAN_KEY_MGMT_NONE); - set_priv_filter(usbdev); - set_encr_mode(usbdev, RNDIS_WLAN_ALG_NONE, RNDIS_WLAN_ALG_NONE); -} - -static int deauthenticate(struct usbnet *usbdev) -{ - int ret; - - ret = disassociate(usbdev, true); - set_default_iw_params(usbdev); - return ret; -} - -static int set_channel(struct usbnet *usbdev, int channel) -{ - struct ndis_80211_conf config; - unsigned int dsconfig; - int len, ret; - - netdev_dbg(usbdev->net, "%s(%d)\n", __func__, channel); - - /* this OID is valid only when not associated */ - if (is_associated(usbdev)) - return 0; - - dsconfig = 1000 * - ieee80211_channel_to_frequency(channel, NL80211_BAND_2GHZ); - - len = sizeof(config); - ret = rndis_query_oid(usbdev, - RNDIS_OID_802_11_CONFIGURATION, - &config, &len); - if (ret < 0) { - netdev_dbg(usbdev->net, "%s(): querying configuration failed\n", - __func__); - return ret; - } - - config.ds_config = cpu_to_le32(dsconfig); - ret = rndis_set_oid(usbdev, - RNDIS_OID_802_11_CONFIGURATION, - &config, sizeof(config)); - - netdev_dbg(usbdev->net, "%s(): %d -> %d\n", __func__, channel, ret); - - return ret; -} - -static struct ieee80211_channel *get_current_channel(struct usbnet *usbdev, - u32 *beacon_period) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct ieee80211_channel *channel; - struct ndis_80211_conf config; - int len, ret; - - /* Get channel and beacon interval */ - len = sizeof(config); - ret = rndis_query_oid(usbdev, - RNDIS_OID_802_11_CONFIGURATION, - &config, &len); - netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_CONFIGURATION -> %d\n", - __func__, ret); - if (ret < 0) - return NULL; - - channel = ieee80211_get_channel(priv->wdev.wiphy, - KHZ_TO_MHZ(le32_to_cpu(config.ds_config))); - if (!channel) - return NULL; - - if (beacon_period) - *beacon_period = le32_to_cpu(config.beacon_period); - return channel; -} - -/* index must be 0 - N, as per NDIS */ -static int add_wep_key(struct usbnet *usbdev, const u8 *key, int key_len, - u8 index) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct ndis_80211_wep_key ndis_key; - u32 cipher; - int ret; - - netdev_dbg(usbdev->net, "%s(idx: %d, len: %d)\n", - __func__, index, key_len); - - if (index >= RNDIS_WLAN_NUM_KEYS) - return -EINVAL; - - if (key_len == 5) - cipher = WLAN_CIPHER_SUITE_WEP40; - else if (key_len == 13) - cipher = WLAN_CIPHER_SUITE_WEP104; - else - return -EINVAL; - - memset(&ndis_key, 0, sizeof(ndis_key)); - - ndis_key.size = cpu_to_le32(sizeof(ndis_key)); - ndis_key.length = cpu_to_le32(key_len); - ndis_key.index = cpu_to_le32(index); - memcpy(&ndis_key.material, key, key_len); - - if (index == priv->encr_tx_key_index) { - ndis_key.index |= NDIS_80211_ADDWEP_TRANSMIT_KEY; - ret = set_encr_mode(usbdev, RNDIS_WLAN_ALG_WEP, - RNDIS_WLAN_ALG_NONE); - if (ret) - netdev_warn(usbdev->net, "encryption couldn't be enabled (%08X)\n", - ret); - } - - ret = rndis_set_oid(usbdev, - RNDIS_OID_802_11_ADD_WEP, &ndis_key, - sizeof(ndis_key)); - if (ret != 0) { - netdev_warn(usbdev->net, "adding encryption key %d failed (%08X)\n", - index + 1, ret); - return ret; - } - - priv->encr_keys[index].len = key_len; - priv->encr_keys[index].cipher = cipher; - memcpy(&priv->encr_keys[index].material, key, key_len); - eth_broadcast_addr(priv->encr_keys[index].bssid); - - return 0; -} - -static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, - u8 index, const u8 *addr, const u8 *rx_seq, - int seq_len, u32 cipher, __le32 flags) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct ndis_80211_key ndis_key; - bool is_addr_ok; - int ret; - - if (index >= RNDIS_WLAN_NUM_KEYS) { - netdev_dbg(usbdev->net, "%s(): index out of range (%i)\n", - __func__, index); - return -EINVAL; - } - if (key_len > sizeof(ndis_key.material) || key_len < 0) { - netdev_dbg(usbdev->net, "%s(): key length out of range (%i)\n", - __func__, key_len); - return -EINVAL; - } - if (flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ) { - if (!rx_seq || seq_len <= 0) { - netdev_dbg(usbdev->net, "%s(): recv seq flag without buffer\n", - __func__); - return -EINVAL; - } - if (rx_seq && seq_len > sizeof(ndis_key.rsc)) { - netdev_dbg(usbdev->net, "%s(): too big recv seq buffer\n", __func__); - return -EINVAL; - } - } - - is_addr_ok = addr && !is_zero_ether_addr(addr) && - !is_broadcast_ether_addr(addr); - if ((flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) && !is_addr_ok) { - netdev_dbg(usbdev->net, "%s(): pairwise but bssid invalid (%pM)\n", - __func__, addr); - return -EINVAL; - } - - netdev_dbg(usbdev->net, "%s(%i): flags:%i%i%i\n", - __func__, index, - !!(flags & NDIS_80211_ADDKEY_TRANSMIT_KEY), - !!(flags & NDIS_80211_ADDKEY_PAIRWISE_KEY), - !!(flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ)); - - memset(&ndis_key, 0, sizeof(ndis_key)); - - ndis_key.size = cpu_to_le32(sizeof(ndis_key) - - sizeof(ndis_key.material) + key_len); - ndis_key.length = cpu_to_le32(key_len); - ndis_key.index = cpu_to_le32(index) | flags; - - if (cipher == WLAN_CIPHER_SUITE_TKIP && key_len == 32) { - /* wpa_supplicant gives us the Michael MIC RX/TX keys in - * different order than NDIS spec, so swap the order here. */ - memcpy(ndis_key.material, key, 16); - memcpy(ndis_key.material + 16, key + 24, 8); - memcpy(ndis_key.material + 24, key + 16, 8); - } else - memcpy(ndis_key.material, key, key_len); - - if (flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ) - memcpy(ndis_key.rsc, rx_seq, seq_len); - - if (flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) { - /* pairwise key */ - memcpy(ndis_key.bssid, addr, ETH_ALEN); - } else { - /* group key */ - if (priv->infra_mode == NDIS_80211_INFRA_ADHOC) - eth_broadcast_addr(ndis_key.bssid); - else - get_bssid(usbdev, ndis_key.bssid); - } - - ret = rndis_set_oid(usbdev, - RNDIS_OID_802_11_ADD_KEY, &ndis_key, - le32_to_cpu(ndis_key.size)); - netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_ADD_KEY -> %08X\n", - __func__, ret); - if (ret != 0) - return ret; - - memset(&priv->encr_keys[index], 0, sizeof(priv->encr_keys[index])); - priv->encr_keys[index].len = key_len; - priv->encr_keys[index].cipher = cipher; - memcpy(&priv->encr_keys[index].material, key, key_len); - if (flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) - memcpy(&priv->encr_keys[index].bssid, ndis_key.bssid, ETH_ALEN); - else - eth_broadcast_addr(priv->encr_keys[index].bssid); - - if (flags & NDIS_80211_ADDKEY_TRANSMIT_KEY) - priv->encr_tx_key_index = index; - - return 0; -} - -static int restore_key(struct usbnet *usbdev, u8 key_idx) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct rndis_wlan_encr_key key; - - if (is_wpa_key(priv, key_idx)) - return 0; - - key = priv->encr_keys[key_idx]; - - netdev_dbg(usbdev->net, "%s(): %i:%i\n", __func__, key_idx, key.len); - - if (key.len == 0) - return 0; - - return add_wep_key(usbdev, key.material, key.len, key_idx); -} - -static void restore_keys(struct usbnet *usbdev) -{ - int i; - - for (i = 0; i < 4; i++) - restore_key(usbdev, i); -} - -static void clear_key(struct rndis_wlan_private *priv, u8 idx) -{ - memset(&priv->encr_keys[idx], 0, sizeof(priv->encr_keys[idx])); -} - -/* remove_key is for both wep and wpa */ -static int remove_key(struct usbnet *usbdev, u8 index, const u8 *bssid) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct ndis_80211_remove_key remove_key; - __le32 keyindex; - bool is_wpa; - int ret; - - if (index >= RNDIS_WLAN_NUM_KEYS) - return -ENOENT; - - if (priv->encr_keys[index].len == 0) - return 0; - - is_wpa = is_wpa_key(priv, index); - - netdev_dbg(usbdev->net, "%s(): %i:%s:%i\n", - __func__, index, is_wpa ? "wpa" : "wep", - priv->encr_keys[index].len); - - clear_key(priv, index); - - if (is_wpa) { - remove_key.size = cpu_to_le32(sizeof(remove_key)); - remove_key.index = cpu_to_le32(index); - if (bssid) { - /* pairwise key */ - if (!is_broadcast_ether_addr(bssid)) - remove_key.index |= - NDIS_80211_ADDKEY_PAIRWISE_KEY; - memcpy(remove_key.bssid, bssid, - sizeof(remove_key.bssid)); - } else - memset(remove_key.bssid, 0xff, - sizeof(remove_key.bssid)); - - ret = rndis_set_oid(usbdev, - RNDIS_OID_802_11_REMOVE_KEY, - &remove_key, sizeof(remove_key)); - if (ret != 0) - return ret; - } else { - keyindex = cpu_to_le32(index); - ret = rndis_set_oid(usbdev, - RNDIS_OID_802_11_REMOVE_WEP, - &keyindex, sizeof(keyindex)); - if (ret != 0) { - netdev_warn(usbdev->net, - "removing encryption key %d failed (%08X)\n", - index, ret); - return ret; - } - } - - /* if it is transmit key, disable encryption */ - if (index == priv->encr_tx_key_index) - set_encr_mode(usbdev, RNDIS_WLAN_ALG_NONE, RNDIS_WLAN_ALG_NONE); - - return 0; -} - -static void set_multicast_list(struct usbnet *usbdev) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct netdev_hw_addr *ha; - __le32 filter, basefilter; - int ret; - char *mc_addrs = NULL; - int mc_count; - - basefilter = filter = cpu_to_le32(RNDIS_PACKET_TYPE_DIRECTED | - RNDIS_PACKET_TYPE_BROADCAST); - - if (usbdev->net->flags & IFF_PROMISC) { - filter |= cpu_to_le32(RNDIS_PACKET_TYPE_PROMISCUOUS | - RNDIS_PACKET_TYPE_ALL_LOCAL); - } else if (usbdev->net->flags & IFF_ALLMULTI) { - filter |= cpu_to_le32(RNDIS_PACKET_TYPE_ALL_MULTICAST); - } - - if (filter != basefilter) - goto set_filter; - - /* - * mc_list should be accessed holding the lock, so copy addresses to - * local buffer first. - */ - netif_addr_lock_bh(usbdev->net); - mc_count = netdev_mc_count(usbdev->net); - if (mc_count > priv->multicast_size) { - filter |= cpu_to_le32(RNDIS_PACKET_TYPE_ALL_MULTICAST); - } else if (mc_count) { - int i = 0; - - mc_addrs = kmalloc_array(mc_count, ETH_ALEN, GFP_ATOMIC); - if (!mc_addrs) { - netif_addr_unlock_bh(usbdev->net); - return; - } - - netdev_for_each_mc_addr(ha, usbdev->net) - memcpy(mc_addrs + i++ * ETH_ALEN, - ha->addr, ETH_ALEN); - } - netif_addr_unlock_bh(usbdev->net); - - if (filter != basefilter) - goto set_filter; - - if (mc_count) { - ret = rndis_set_oid(usbdev, - RNDIS_OID_802_3_MULTICAST_LIST, - mc_addrs, mc_count * ETH_ALEN); - kfree(mc_addrs); - if (ret == 0) - filter |= cpu_to_le32(RNDIS_PACKET_TYPE_MULTICAST); - else - filter |= cpu_to_le32(RNDIS_PACKET_TYPE_ALL_MULTICAST); - - netdev_dbg(usbdev->net, "RNDIS_OID_802_3_MULTICAST_LIST(%d, max: %d) -> %d\n", - mc_count, priv->multicast_size, ret); - } - -set_filter: - ret = rndis_set_oid(usbdev, RNDIS_OID_GEN_CURRENT_PACKET_FILTER, &filter, - sizeof(filter)); - if (ret < 0) { - netdev_warn(usbdev->net, "couldn't set packet filter: %08x\n", - le32_to_cpu(filter)); - } - - netdev_dbg(usbdev->net, "RNDIS_OID_GEN_CURRENT_PACKET_FILTER(%08x) -> %d\n", - le32_to_cpu(filter), ret); -} - -#ifdef DEBUG -static void debug_print_pmkids(struct usbnet *usbdev, - struct ndis_80211_pmkid *pmkids, - const char *func_str) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - int i, len, count, max_pmkids, entry_len; - - max_pmkids = priv->wdev.wiphy->max_num_pmkids; - len = le32_to_cpu(pmkids->length); - count = le32_to_cpu(pmkids->bssid_info_count); - - entry_len = (count > 0) ? (len - sizeof(*pmkids)) / count : -1; - - netdev_dbg(usbdev->net, "%s(): %d PMKIDs (data len: %d, entry len: " - "%d)\n", func_str, count, len, entry_len); - - if (count > max_pmkids) - count = max_pmkids; - - for (i = 0; i < count; i++) { - u32 *tmp = (u32 *)pmkids->bssid_info[i].pmkid; - - netdev_dbg(usbdev->net, "%s(): bssid: %pM, " - "pmkid: %08X:%08X:%08X:%08X\n", - func_str, pmkids->bssid_info[i].bssid, - cpu_to_be32(tmp[0]), cpu_to_be32(tmp[1]), - cpu_to_be32(tmp[2]), cpu_to_be32(tmp[3])); - } -} -#else -static void debug_print_pmkids(struct usbnet *usbdev, - struct ndis_80211_pmkid *pmkids, - const char *func_str) -{ - return; -} -#endif - -static struct ndis_80211_pmkid *get_device_pmkids(struct usbnet *usbdev) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct ndis_80211_pmkid *pmkids; - int len, ret, max_pmkids; - - max_pmkids = priv->wdev.wiphy->max_num_pmkids; - len = struct_size(pmkids, bssid_info, max_pmkids); - - pmkids = kzalloc(len, GFP_KERNEL); - if (!pmkids) - return ERR_PTR(-ENOMEM); - - pmkids->length = cpu_to_le32(len); - pmkids->bssid_info_count = cpu_to_le32(max_pmkids); - - ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_PMKID, - pmkids, &len); - if (ret < 0) { - netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_PMKID(%d, %d)" - " -> %d\n", __func__, len, max_pmkids, ret); - - kfree(pmkids); - return ERR_PTR(ret); - } - - if (le32_to_cpu(pmkids->bssid_info_count) > max_pmkids) - pmkids->bssid_info_count = cpu_to_le32(max_pmkids); - - debug_print_pmkids(usbdev, pmkids, __func__); - - return pmkids; -} - -static int set_device_pmkids(struct usbnet *usbdev, - struct ndis_80211_pmkid *pmkids) -{ - int ret, len, num_pmkids; - - num_pmkids = le32_to_cpu(pmkids->bssid_info_count); - len = struct_size(pmkids, bssid_info, num_pmkids); - pmkids->length = cpu_to_le32(len); - - debug_print_pmkids(usbdev, pmkids, __func__); - - ret = rndis_set_oid(usbdev, RNDIS_OID_802_11_PMKID, pmkids, - le32_to_cpu(pmkids->length)); - if (ret < 0) { - netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_PMKID(%d, %d) -> %d" - "\n", __func__, len, num_pmkids, ret); - } - - kfree(pmkids); - return ret; -} - -static struct ndis_80211_pmkid *remove_pmkid(struct usbnet *usbdev, - struct ndis_80211_pmkid *pmkids, - struct cfg80211_pmksa *pmksa, - int max_pmkids) -{ - int i, err; - unsigned int count; - - count = le32_to_cpu(pmkids->bssid_info_count); - - if (count > max_pmkids) - count = max_pmkids; - - for (i = 0; i < count; i++) - if (ether_addr_equal(pmkids->bssid_info[i].bssid, - pmksa->bssid)) - break; - - /* pmkid not found */ - if (i == count) { - netdev_dbg(usbdev->net, "%s(): bssid not found (%pM)\n", - __func__, pmksa->bssid); - err = -ENOENT; - goto error; - } - - for (; i + 1 < count; i++) - pmkids->bssid_info[i] = pmkids->bssid_info[i + 1]; - - count--; - pmkids->length = cpu_to_le32(struct_size(pmkids, bssid_info, count)); - pmkids->bssid_info_count = cpu_to_le32(count); - - return pmkids; -error: - kfree(pmkids); - return ERR_PTR(err); -} - -static struct ndis_80211_pmkid *update_pmkid(struct usbnet *usbdev, - struct ndis_80211_pmkid *pmkids, - struct cfg80211_pmksa *pmksa, - int max_pmkids) -{ - struct ndis_80211_pmkid *new_pmkids; - int i, err, newlen; - unsigned int count; - - count = le32_to_cpu(pmkids->bssid_info_count); - - if (count > max_pmkids) - count = max_pmkids; - - /* update with new pmkid */ - for (i = 0; i < count; i++) { - if (!ether_addr_equal(pmkids->bssid_info[i].bssid, - pmksa->bssid)) - continue; - - memcpy(pmkids->bssid_info[i].pmkid, pmksa->pmkid, - WLAN_PMKID_LEN); - - return pmkids; - } - - /* out of space, return error */ - if (i == max_pmkids) { - netdev_dbg(usbdev->net, "%s(): out of space\n", __func__); - err = -ENOSPC; - goto error; - } - - /* add new pmkid */ - newlen = struct_size(pmkids, bssid_info, count + 1); - - new_pmkids = krealloc(pmkids, newlen, GFP_KERNEL); - if (!new_pmkids) { - err = -ENOMEM; - goto error; - } - pmkids = new_pmkids; - - pmkids->length = cpu_to_le32(newlen); - pmkids->bssid_info_count = cpu_to_le32(count + 1); - - memcpy(pmkids->bssid_info[count].bssid, pmksa->bssid, ETH_ALEN); - memcpy(pmkids->bssid_info[count].pmkid, pmksa->pmkid, WLAN_PMKID_LEN); - - return pmkids; -error: - kfree(pmkids); - return ERR_PTR(err); -} - -/* - * cfg80211 ops - */ -static int rndis_change_virtual_intf(struct wiphy *wiphy, - struct net_device *dev, - enum nl80211_iftype type, - struct vif_params *params) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - int mode; - - switch (type) { - case NL80211_IFTYPE_ADHOC: - mode = NDIS_80211_INFRA_ADHOC; - break; - case NL80211_IFTYPE_STATION: - mode = NDIS_80211_INFRA_INFRA; - break; - default: - return -EINVAL; - } - - priv->wdev.iftype = type; - - return set_infra_mode(usbdev, mode); -} - -static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - int err; - - if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { - err = set_frag_threshold(usbdev, wiphy->frag_threshold); - if (err < 0) - return err; - } - - if (changed & WIPHY_PARAM_RTS_THRESHOLD) { - err = set_rts_threshold(usbdev, wiphy->rts_threshold); - if (err < 0) - return err; - } - - return 0; -} - -static int rndis_set_tx_power(struct wiphy *wiphy, - struct wireless_dev *wdev, - enum nl80211_tx_power_setting type, - int mbm) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - - netdev_dbg(usbdev->net, "%s(): type:0x%x mbm:%i\n", - __func__, type, mbm); - - if (mbm < 0 || (mbm % 100)) - return -ENOTSUPP; - - /* Device doesn't support changing txpower after initialization, only - * turn off/on radio. Support 'auto' mode and setting same dBm that is - * currently used. - */ - if (type == NL80211_TX_POWER_AUTOMATIC || - MBM_TO_DBM(mbm) == get_bcm4320_power_dbm(priv)) { - if (!priv->radio_on) - disassociate(usbdev, true); /* turn on radio */ - - return 0; - } - - return -ENOTSUPP; -} - -static int rndis_get_tx_power(struct wiphy *wiphy, - struct wireless_dev *wdev, - int *dbm) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - - *dbm = get_bcm4320_power_dbm(priv); - - netdev_dbg(usbdev->net, "%s(): dbm:%i\n", __func__, *dbm); - - return 0; -} - -#define SCAN_DELAY_JIFFIES (6 * HZ) -static int rndis_scan(struct wiphy *wiphy, - struct cfg80211_scan_request *request) -{ - struct net_device *dev = request->wdev->netdev; - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - int ret; - int delay = SCAN_DELAY_JIFFIES; - - netdev_dbg(usbdev->net, "cfg80211.scan\n"); - - /* Get current bssid list from device before new scan, as new scan - * clears internal bssid list. - */ - rndis_check_bssid_list(usbdev, NULL, NULL); - - if (priv->scan_request && priv->scan_request != request) - return -EBUSY; - - priv->scan_request = request; - - ret = rndis_start_bssid_list_scan(usbdev); - if (ret == 0) { - if (priv->device_type == RNDIS_BCM4320A) - delay = HZ; - - /* Wait before retrieving scan results from device */ - queue_delayed_work(priv->workqueue, &priv->scan_work, delay); - } - - return ret; -} - -static bool rndis_bss_info_update(struct usbnet *usbdev, - struct ndis_80211_bssid_ex *bssid) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct ieee80211_channel *channel; - struct cfg80211_bss *bss; - s32 signal; - u64 timestamp; - u16 capability; - u16 beacon_interval; - struct ndis_80211_fixed_ies *fixed; - int ie_len, bssid_len; - u8 *ie; - - netdev_dbg(usbdev->net, " found bssid: '%.32s' [%pM], len: %d\n", - bssid->ssid.essid, bssid->mac, le32_to_cpu(bssid->length)); - - /* parse bssid structure */ - bssid_len = le32_to_cpu(bssid->length); - - if (bssid_len < sizeof(struct ndis_80211_bssid_ex) + - sizeof(struct ndis_80211_fixed_ies)) - return false; - - fixed = (struct ndis_80211_fixed_ies *)bssid->ies; - - ie = (void *)(bssid->ies + sizeof(struct ndis_80211_fixed_ies)); - ie_len = min(bssid_len - (int)sizeof(*bssid), - (int)le32_to_cpu(bssid->ie_length)); - ie_len -= sizeof(struct ndis_80211_fixed_ies); - if (ie_len < 0) - return false; - - /* extract data for cfg80211_inform_bss */ - channel = ieee80211_get_channel(priv->wdev.wiphy, - KHZ_TO_MHZ(le32_to_cpu(bssid->config.ds_config))); - if (!channel) - return false; - - signal = level_to_qual(le32_to_cpu(bssid->rssi)); - timestamp = le64_to_cpu(*(__le64 *)fixed->timestamp); - capability = le16_to_cpu(fixed->capabilities); - beacon_interval = le16_to_cpu(fixed->beacon_interval); - - bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, - CFG80211_BSS_FTYPE_UNKNOWN, bssid->mac, - timestamp, capability, beacon_interval, - ie, ie_len, signal, GFP_KERNEL); - cfg80211_put_bss(priv->wdev.wiphy, bss); - - return (bss != NULL); -} - -static struct ndis_80211_bssid_ex *next_bssid_list_item( - struct ndis_80211_bssid_ex *bssid, - int *bssid_len, void *buf, int len) -{ - void *buf_end, *bssid_end; - - buf_end = (char *)buf + len; - bssid_end = (char *)bssid + *bssid_len; - - if ((int)(buf_end - bssid_end) < sizeof(bssid->length)) { - *bssid_len = 0; - return NULL; - } else { - bssid = (void *)((char *)bssid + *bssid_len); - *bssid_len = le32_to_cpu(bssid->length); - return bssid; - } -} - -static bool check_bssid_list_item(struct ndis_80211_bssid_ex *bssid, - int bssid_len, void *buf, int len) -{ - void *buf_end, *bssid_end; - - if (!bssid || bssid_len <= 0 || bssid_len > len) - return false; - - buf_end = (char *)buf + len; - bssid_end = (char *)bssid + bssid_len; - - return (int)(buf_end - bssid_end) >= 0 && (int)(bssid_end - buf) >= 0; -} - -static int rndis_check_bssid_list(struct usbnet *usbdev, u8 *match_bssid, - bool *matched) -{ - void *buf = NULL; - struct ndis_80211_bssid_list_ex *bssid_list; - struct ndis_80211_bssid_ex *bssid; - int ret = -EINVAL, len, count, bssid_len, real_count, new_len; - - netdev_dbg(usbdev->net, "%s()\n", __func__); - - len = CONTROL_BUFFER_SIZE; -resize_buf: - buf = kzalloc(len, GFP_KERNEL); - if (!buf) { - ret = -ENOMEM; - goto out; - } - - /* BSSID-list might have got bigger last time we checked, keep - * resizing until it won't get any bigger. - */ - new_len = len; - ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_BSSID_LIST, - buf, &new_len); - if (ret != 0 || new_len < sizeof(struct ndis_80211_bssid_list_ex)) - goto out; - - if (new_len > len) { - len = new_len; - kfree(buf); - goto resize_buf; - } - - len = new_len; - - bssid_list = buf; - count = le32_to_cpu(bssid_list->num_items); - real_count = 0; - netdev_dbg(usbdev->net, "%s(): buflen: %d\n", __func__, len); - - bssid_len = 0; - bssid = next_bssid_list_item((void *)bssid_list->bssid_data, - &bssid_len, buf, len); - - /* Device returns incorrect 'num_items'. Workaround by ignoring the - * received 'num_items' and walking through full bssid buffer instead. - */ - while (check_bssid_list_item(bssid, bssid_len, buf, len)) { - if (rndis_bss_info_update(usbdev, bssid) && match_bssid && - matched) { - if (ether_addr_equal(bssid->mac, match_bssid)) - *matched = true; - } - - real_count++; - bssid = next_bssid_list_item(bssid, &bssid_len, buf, len); - } - - netdev_dbg(usbdev->net, "%s(): num_items from device: %d, really found:" - " %d\n", __func__, count, real_count); - -out: - kfree(buf); - return ret; -} - -static void rndis_get_scan_results(struct work_struct *work) -{ - struct rndis_wlan_private *priv = - container_of(work, struct rndis_wlan_private, scan_work.work); - struct usbnet *usbdev = priv->usbdev; - struct cfg80211_scan_info info = {}; - int ret; - - netdev_dbg(usbdev->net, "get_scan_results\n"); - - if (!priv->scan_request) - return; - - ret = rndis_check_bssid_list(usbdev, NULL, NULL); - - info.aborted = ret < 0; - cfg80211_scan_done(priv->scan_request, &info); - - priv->scan_request = NULL; -} - -static int rndis_connect(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_connect_params *sme) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - struct ieee80211_channel *channel = sme->channel; - struct ndis_80211_ssid ssid; - int pairwise = RNDIS_WLAN_ALG_NONE; - int groupwise = RNDIS_WLAN_ALG_NONE; - int keymgmt = RNDIS_WLAN_KEY_MGMT_NONE; - int length, i, ret, chan = -1; - - if (channel) - chan = ieee80211_frequency_to_channel(channel->center_freq); - - groupwise = rndis_cipher_to_alg(sme->crypto.cipher_group); - for (i = 0; i < sme->crypto.n_ciphers_pairwise; i++) - pairwise |= - rndis_cipher_to_alg(sme->crypto.ciphers_pairwise[i]); - - if (sme->crypto.n_ciphers_pairwise > 0 && - pairwise == RNDIS_WLAN_ALG_NONE) { - netdev_err(usbdev->net, "Unsupported pairwise cipher\n"); - return -ENOTSUPP; - } - - for (i = 0; i < sme->crypto.n_akm_suites; i++) - keymgmt |= - rndis_akm_suite_to_key_mgmt(sme->crypto.akm_suites[i]); - - if (sme->crypto.n_akm_suites > 0 && - keymgmt == RNDIS_WLAN_KEY_MGMT_NONE) { - netdev_err(usbdev->net, "Invalid keymgmt\n"); - return -ENOTSUPP; - } - - netdev_dbg(usbdev->net, "cfg80211.connect('%.32s':[%pM]:%d:[%d,0x%x:0x%x]:[0x%x:0x%x]:0x%x)\n", - sme->ssid, sme->bssid, chan, - sme->privacy, sme->crypto.wpa_versions, sme->auth_type, - groupwise, pairwise, keymgmt); - - if (is_associated(usbdev)) - disassociate(usbdev, false); - - ret = set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA); - if (ret < 0) { - netdev_dbg(usbdev->net, "connect: set_infra_mode failed, %d\n", - ret); - goto err_turn_radio_on; - } - - ret = set_auth_mode(usbdev, sme->crypto.wpa_versions, sme->auth_type, - keymgmt); - if (ret < 0) { - netdev_dbg(usbdev->net, "connect: set_auth_mode failed, %d\n", - ret); - goto err_turn_radio_on; - } - - set_priv_filter(usbdev); - - ret = set_encr_mode(usbdev, pairwise, groupwise); - if (ret < 0) { - netdev_dbg(usbdev->net, "connect: set_encr_mode failed, %d\n", - ret); - goto err_turn_radio_on; - } - - if (channel) { - ret = set_channel(usbdev, chan); - if (ret < 0) { - netdev_dbg(usbdev->net, "connect: set_channel failed, %d\n", - ret); - goto err_turn_radio_on; - } - } - - if (sme->key && ((groupwise | pairwise) & RNDIS_WLAN_ALG_WEP)) { - priv->encr_tx_key_index = sme->key_idx; - ret = add_wep_key(usbdev, sme->key, sme->key_len, sme->key_idx); - if (ret < 0) { - netdev_dbg(usbdev->net, "connect: add_wep_key failed, %d (%d, %d)\n", - ret, sme->key_len, sme->key_idx); - goto err_turn_radio_on; - } - } - - if (sme->bssid && !is_zero_ether_addr(sme->bssid) && - !is_broadcast_ether_addr(sme->bssid)) { - ret = set_bssid(usbdev, sme->bssid); - if (ret < 0) { - netdev_dbg(usbdev->net, "connect: set_bssid failed, %d\n", - ret); - goto err_turn_radio_on; - } - } else - clear_bssid(usbdev); - - length = sme->ssid_len; - if (length > NDIS_802_11_LENGTH_SSID) - length = NDIS_802_11_LENGTH_SSID; - - memset(&ssid, 0, sizeof(ssid)); - ssid.length = cpu_to_le32(length); - memcpy(ssid.essid, sme->ssid, length); - - /* Pause and purge rx queue, so we don't pass packets before - * 'media connect'-indication. - */ - usbnet_pause_rx(usbdev); - usbnet_purge_paused_rxq(usbdev); - - ret = set_essid(usbdev, &ssid); - if (ret < 0) - netdev_dbg(usbdev->net, "connect: set_essid failed, %d\n", ret); - return ret; - -err_turn_radio_on: - disassociate(usbdev, true); - - return ret; -} - -static int rndis_disconnect(struct wiphy *wiphy, struct net_device *dev, - u16 reason_code) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - - netdev_dbg(usbdev->net, "cfg80211.disconnect(%d)\n", reason_code); - - priv->connected = false; - eth_zero_addr(priv->bssid); - - return deauthenticate(usbdev); -} - -static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_ibss_params *params) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - struct ieee80211_channel *channel = params->chandef.chan; - struct ndis_80211_ssid ssid; - enum nl80211_auth_type auth_type; - int ret, alg, length, chan = -1; - - if (channel) - chan = ieee80211_frequency_to_channel(channel->center_freq); - - /* TODO: How to handle ad-hoc encryption? - * connect() has *key, join_ibss() doesn't. RNDIS requires key to be - * pre-shared for encryption (open/shared/wpa), is key set before - * join_ibss? Which auth_type to use (not in params)? What about WPA? - */ - if (params->privacy) { - auth_type = NL80211_AUTHTYPE_SHARED_KEY; - alg = RNDIS_WLAN_ALG_WEP; - } else { - auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM; - alg = RNDIS_WLAN_ALG_NONE; - } - - netdev_dbg(usbdev->net, "cfg80211.join_ibss('%.32s':[%pM]:%d:%d)\n", - params->ssid, params->bssid, chan, params->privacy); - - if (is_associated(usbdev)) - disassociate(usbdev, false); - - ret = set_infra_mode(usbdev, NDIS_80211_INFRA_ADHOC); - if (ret < 0) { - netdev_dbg(usbdev->net, "join_ibss: set_infra_mode failed, %d\n", - ret); - goto err_turn_radio_on; - } - - ret = set_auth_mode(usbdev, 0, auth_type, RNDIS_WLAN_KEY_MGMT_NONE); - if (ret < 0) { - netdev_dbg(usbdev->net, "join_ibss: set_auth_mode failed, %d\n", - ret); - goto err_turn_radio_on; - } - - set_priv_filter(usbdev); - - ret = set_encr_mode(usbdev, alg, RNDIS_WLAN_ALG_NONE); - if (ret < 0) { - netdev_dbg(usbdev->net, "join_ibss: set_encr_mode failed, %d\n", - ret); - goto err_turn_radio_on; - } - - if (channel) { - ret = set_channel(usbdev, chan); - if (ret < 0) { - netdev_dbg(usbdev->net, "join_ibss: set_channel failed, %d\n", - ret); - goto err_turn_radio_on; - } - } - - if (params->bssid && !is_zero_ether_addr(params->bssid) && - !is_broadcast_ether_addr(params->bssid)) { - ret = set_bssid(usbdev, params->bssid); - if (ret < 0) { - netdev_dbg(usbdev->net, "join_ibss: set_bssid failed, %d\n", - ret); - goto err_turn_radio_on; - } - } else - clear_bssid(usbdev); - - length = params->ssid_len; - if (length > NDIS_802_11_LENGTH_SSID) - length = NDIS_802_11_LENGTH_SSID; - - memset(&ssid, 0, sizeof(ssid)); - ssid.length = cpu_to_le32(length); - memcpy(ssid.essid, params->ssid, length); - - /* Don't need to pause rx queue for ad-hoc. */ - usbnet_purge_paused_rxq(usbdev); - usbnet_resume_rx(usbdev); - - ret = set_essid(usbdev, &ssid); - if (ret < 0) - netdev_dbg(usbdev->net, "join_ibss: set_essid failed, %d\n", - ret); - return ret; - -err_turn_radio_on: - disassociate(usbdev, true); - - return ret; -} - -static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - - netdev_dbg(usbdev->net, "cfg80211.leave_ibss()\n"); - - priv->connected = false; - eth_zero_addr(priv->bssid); - - return deauthenticate(usbdev); -} - -static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev, - int link_id, u8 key_index, bool pairwise, - const u8 *mac_addr, struct key_params *params) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - __le32 flags; - - netdev_dbg(usbdev->net, "%s(%i, %pM, %08x)\n", - __func__, key_index, mac_addr, params->cipher); - - switch (params->cipher) { - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: - return add_wep_key(usbdev, params->key, params->key_len, - key_index); - case WLAN_CIPHER_SUITE_TKIP: - case WLAN_CIPHER_SUITE_CCMP: - flags = 0; - - if (params->seq && params->seq_len > 0) - flags |= NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ; - if (mac_addr) - flags |= NDIS_80211_ADDKEY_PAIRWISE_KEY | - NDIS_80211_ADDKEY_TRANSMIT_KEY; - - return add_wpa_key(usbdev, params->key, params->key_len, - key_index, mac_addr, params->seq, - params->seq_len, params->cipher, flags); - default: - netdev_dbg(usbdev->net, "%s(): unsupported cipher %08x\n", - __func__, params->cipher); - return -ENOTSUPP; - } -} - -static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev, - int link_id, u8 key_index, bool pairwise, - const u8 *mac_addr) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - - netdev_dbg(usbdev->net, "%s(%i, %pM)\n", __func__, key_index, mac_addr); - - return remove_key(usbdev, key_index, mac_addr); -} - -static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev, - int link_id, u8 key_index, bool unicast, - bool multicast) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - struct rndis_wlan_encr_key key; - - netdev_dbg(usbdev->net, "%s(%i)\n", __func__, key_index); - - if (key_index >= RNDIS_WLAN_NUM_KEYS) - return -ENOENT; - - priv->encr_tx_key_index = key_index; - - if (is_wpa_key(priv, key_index)) - return 0; - - key = priv->encr_keys[key_index]; - - return add_wep_key(usbdev, key.material, key.len, key_index); -} - -static void rndis_fill_station_info(struct usbnet *usbdev, - struct station_info *sinfo) -{ - __le32 linkspeed, rssi; - int ret, len; - - memset(sinfo, 0, sizeof(*sinfo)); - - len = sizeof(linkspeed); - ret = rndis_query_oid(usbdev, RNDIS_OID_GEN_LINK_SPEED, &linkspeed, &len); - if (ret == 0) { - sinfo->txrate.legacy = le32_to_cpu(linkspeed) / 1000; - sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); - } - - len = sizeof(rssi); - ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_RSSI, - &rssi, &len); - if (ret == 0) { - sinfo->signal = level_to_qual(le32_to_cpu(rssi)); - sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); - } -} - -static int rndis_get_station(struct wiphy *wiphy, struct net_device *dev, - const u8 *mac, struct station_info *sinfo) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - - if (!ether_addr_equal(priv->bssid, mac)) - return -ENOENT; - - rndis_fill_station_info(usbdev, sinfo); - - return 0; -} - -static int rndis_dump_station(struct wiphy *wiphy, struct net_device *dev, - int idx, u8 *mac, struct station_info *sinfo) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - - if (idx != 0) - return -ENOENT; - - memcpy(mac, priv->bssid, ETH_ALEN); - - rndis_fill_station_info(usbdev, sinfo); - - return 0; -} - -static int rndis_set_pmksa(struct wiphy *wiphy, struct net_device *netdev, - struct cfg80211_pmksa *pmksa) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - struct ndis_80211_pmkid *pmkids; - u32 *tmp = (u32 *)pmksa->pmkid; - - netdev_dbg(usbdev->net, "%s(%pM, %08X:%08X:%08X:%08X)\n", __func__, - pmksa->bssid, - cpu_to_be32(tmp[0]), cpu_to_be32(tmp[1]), - cpu_to_be32(tmp[2]), cpu_to_be32(tmp[3])); - - pmkids = get_device_pmkids(usbdev); - if (IS_ERR(pmkids)) { - /* couldn't read PMKID cache from device */ - return PTR_ERR(pmkids); - } - - pmkids = update_pmkid(usbdev, pmkids, pmksa, wiphy->max_num_pmkids); - if (IS_ERR(pmkids)) { - /* not found, list full, etc */ - return PTR_ERR(pmkids); - } - - return set_device_pmkids(usbdev, pmkids); -} - -static int rndis_del_pmksa(struct wiphy *wiphy, struct net_device *netdev, - struct cfg80211_pmksa *pmksa) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - struct ndis_80211_pmkid *pmkids; - u32 *tmp = (u32 *)pmksa->pmkid; - - netdev_dbg(usbdev->net, "%s(%pM, %08X:%08X:%08X:%08X)\n", __func__, - pmksa->bssid, - cpu_to_be32(tmp[0]), cpu_to_be32(tmp[1]), - cpu_to_be32(tmp[2]), cpu_to_be32(tmp[3])); - - pmkids = get_device_pmkids(usbdev); - if (IS_ERR(pmkids)) { - /* Couldn't read PMKID cache from device */ - return PTR_ERR(pmkids); - } - - pmkids = remove_pmkid(usbdev, pmkids, pmksa, wiphy->max_num_pmkids); - if (IS_ERR(pmkids)) { - /* not found, etc */ - return PTR_ERR(pmkids); - } - - return set_device_pmkids(usbdev, pmkids); -} - -static int rndis_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - struct ndis_80211_pmkid pmkid; - - netdev_dbg(usbdev->net, "%s()\n", __func__); - - memset(&pmkid, 0, sizeof(pmkid)); - - pmkid.length = cpu_to_le32(sizeof(pmkid)); - pmkid.bssid_info_count = cpu_to_le32(0); - - return rndis_set_oid(usbdev, RNDIS_OID_802_11_PMKID, - &pmkid, sizeof(pmkid)); -} - -static int rndis_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, - bool enabled, int timeout) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - int power_mode; - __le32 mode; - int ret; - - if (priv->device_type != RNDIS_BCM4320B) - return -ENOTSUPP; - - netdev_dbg(usbdev->net, "%s(): %s, %d\n", __func__, - enabled ? "enabled" : "disabled", - timeout); - - if (enabled) - power_mode = NDIS_80211_POWER_MODE_FAST_PSP; - else - power_mode = NDIS_80211_POWER_MODE_CAM; - - if (power_mode == priv->power_mode) - return 0; - - priv->power_mode = power_mode; - - mode = cpu_to_le32(power_mode); - ret = rndis_set_oid(usbdev, RNDIS_OID_802_11_POWER_MODE, - &mode, sizeof(mode)); - - netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_POWER_MODE -> %d\n", - __func__, ret); - - return ret; -} - -static int rndis_set_cqm_rssi_config(struct wiphy *wiphy, - struct net_device *dev, - s32 rssi_thold, u32 rssi_hyst) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - - priv->cqm_rssi_thold = rssi_thold; - priv->cqm_rssi_hyst = rssi_hyst; - priv->last_cqm_event_rssi = 0; - - return 0; -} - -static void rndis_wlan_craft_connected_bss(struct usbnet *usbdev, u8 *bssid, - struct ndis_80211_assoc_info *info) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct ieee80211_channel *channel; - struct ndis_80211_ssid ssid; - struct cfg80211_bss *bss; - s32 signal; - u64 timestamp; - u16 capability; - u32 beacon_period = 0; - __le32 rssi; - u8 ie_buf[34]; - int len, ret, ie_len; - - /* Get signal quality, in case of error use rssi=0 and ignore error. */ - len = sizeof(rssi); - rssi = 0; - ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_RSSI, - &rssi, &len); - signal = level_to_qual(le32_to_cpu(rssi)); - - netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_RSSI -> %d, " - "rssi:%d, qual: %d\n", __func__, ret, le32_to_cpu(rssi), - level_to_qual(le32_to_cpu(rssi))); - - /* Get AP capabilities */ - if (info) { - capability = le16_to_cpu(info->resp_ie.capa); - } else { - /* Set atleast ESS/IBSS capability */ - capability = (priv->infra_mode == NDIS_80211_INFRA_INFRA) ? - WLAN_CAPABILITY_ESS : WLAN_CAPABILITY_IBSS; - } - - /* Get channel and beacon interval */ - channel = get_current_channel(usbdev, &beacon_period); - if (!channel) { - netdev_warn(usbdev->net, "%s(): could not get channel.\n", - __func__); - return; - } - - /* Get SSID, in case of error, use zero length SSID and ignore error. */ - len = sizeof(ssid); - memset(&ssid, 0, sizeof(ssid)); - ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_SSID, - &ssid, &len); - netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_SSID -> %d, len: %d, ssid: " - "'%.32s'\n", __func__, ret, - le32_to_cpu(ssid.length), ssid.essid); - - if (le32_to_cpu(ssid.length) > 32) - ssid.length = cpu_to_le32(32); - - ie_buf[0] = WLAN_EID_SSID; - ie_buf[1] = le32_to_cpu(ssid.length); - memcpy(&ie_buf[2], ssid.essid, le32_to_cpu(ssid.length)); - - ie_len = le32_to_cpu(ssid.length) + 2; - - /* no tsf */ - timestamp = 0; - - netdev_dbg(usbdev->net, "%s(): channel:%d(freq), bssid:[%pM], tsf:%d, " - "capa:%x, beacon int:%d, resp_ie(len:%d, essid:'%.32s'), " - "signal:%d\n", __func__, (channel ? channel->center_freq : -1), - bssid, (u32)timestamp, capability, beacon_period, ie_len, - ssid.essid, signal); - - bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, - CFG80211_BSS_FTYPE_UNKNOWN, bssid, - timestamp, capability, beacon_period, - ie_buf, ie_len, signal, GFP_KERNEL); - cfg80211_put_bss(priv->wdev.wiphy, bss); -} - -/* - * workers, indication handlers, device poller - */ -static void rndis_wlan_do_link_up_work(struct usbnet *usbdev) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct ndis_80211_assoc_info *info = NULL; - u8 bssid[ETH_ALEN]; - unsigned int resp_ie_len, req_ie_len; - unsigned int offset; - u8 *req_ie, *resp_ie; - int ret; - bool roamed = false; - bool match_bss; - - if (priv->infra_mode == NDIS_80211_INFRA_INFRA && priv->connected) { - /* received media connect indication while connected, either - * device reassociated with same AP or roamed to new. */ - roamed = true; - } - - req_ie_len = 0; - resp_ie_len = 0; - req_ie = NULL; - resp_ie = NULL; - - if (priv->infra_mode == NDIS_80211_INFRA_INFRA) { - info = kzalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL); - if (!info) { - /* No memory? Try resume work later */ - set_bit(WORK_LINK_UP, &priv->work_pending); - queue_work(priv->workqueue, &priv->work); - return; - } - - /* Get association info IEs from device. */ - ret = get_association_info(usbdev, info, CONTROL_BUFFER_SIZE); - if (!ret) { - req_ie_len = le32_to_cpu(info->req_ie_length); - if (req_ie_len > CONTROL_BUFFER_SIZE) - req_ie_len = CONTROL_BUFFER_SIZE; - if (req_ie_len != 0) { - offset = le32_to_cpu(info->offset_req_ies); - - if (offset > CONTROL_BUFFER_SIZE) - offset = CONTROL_BUFFER_SIZE; - - req_ie = (u8 *)info + offset; - - if (offset + req_ie_len > CONTROL_BUFFER_SIZE) - req_ie_len = - CONTROL_BUFFER_SIZE - offset; - } - - resp_ie_len = le32_to_cpu(info->resp_ie_length); - if (resp_ie_len > CONTROL_BUFFER_SIZE) - resp_ie_len = CONTROL_BUFFER_SIZE; - if (resp_ie_len != 0) { - offset = le32_to_cpu(info->offset_resp_ies); - - if (offset > CONTROL_BUFFER_SIZE) - offset = CONTROL_BUFFER_SIZE; - - resp_ie = (u8 *)info + offset; - - if (offset + resp_ie_len > CONTROL_BUFFER_SIZE) - resp_ie_len = - CONTROL_BUFFER_SIZE - offset; - } - } else { - /* Since rndis_wlan_craft_connected_bss() might use info - * later and expects info to contain valid data if - * non-null, free info and set NULL here. - */ - kfree(info); - info = NULL; - } - } else if (WARN_ON(priv->infra_mode != NDIS_80211_INFRA_ADHOC)) - return; - - ret = get_bssid(usbdev, bssid); - if (ret < 0) - memset(bssid, 0, sizeof(bssid)); - - netdev_dbg(usbdev->net, "link up work: [%pM]%s\n", - bssid, roamed ? " roamed" : ""); - - /* Internal bss list in device should contain at least the currently - * connected bss and we can get it to cfg80211 with - * rndis_check_bssid_list(). - * - * NDIS spec says: "If the device is associated, but the associated - * BSSID is not in its BSSID scan list, then the driver must add an - * entry for the BSSID at the end of the data that it returns in - * response to query of RNDIS_OID_802_11_BSSID_LIST." - * - * NOTE: Seems to be true for BCM4320b variant, but not BCM4320a. - */ - match_bss = false; - rndis_check_bssid_list(usbdev, bssid, &match_bss); - - if (!is_zero_ether_addr(bssid) && !match_bss) { - /* Couldn't get bss from device, we need to manually craft bss - * for cfg80211. - */ - rndis_wlan_craft_connected_bss(usbdev, bssid, info); - } - - if (priv->infra_mode == NDIS_80211_INFRA_INFRA) { - if (!roamed) { - cfg80211_connect_result(usbdev->net, bssid, req_ie, - req_ie_len, resp_ie, - resp_ie_len, 0, GFP_KERNEL); - } else { - struct cfg80211_roam_info roam_info = { - .links[0].channel = - get_current_channel(usbdev, NULL), - .links[0].bssid = bssid, - .req_ie = req_ie, - .req_ie_len = req_ie_len, - .resp_ie = resp_ie, - .resp_ie_len = resp_ie_len, - }; - - cfg80211_roamed(usbdev->net, &roam_info, GFP_KERNEL); - } - } else if (priv->infra_mode == NDIS_80211_INFRA_ADHOC) - cfg80211_ibss_joined(usbdev->net, bssid, - get_current_channel(usbdev, NULL), - GFP_KERNEL); - - kfree(info); - - priv->connected = true; - memcpy(priv->bssid, bssid, ETH_ALEN); - - usbnet_resume_rx(usbdev); - netif_carrier_on(usbdev->net); -} - -static void rndis_wlan_do_link_down_work(struct usbnet *usbdev) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - - if (priv->connected) { - priv->connected = false; - eth_zero_addr(priv->bssid); - - deauthenticate(usbdev); - - cfg80211_disconnected(usbdev->net, 0, NULL, 0, true, GFP_KERNEL); - } - - netif_carrier_off(usbdev->net); -} - -static void rndis_wlan_worker(struct work_struct *work) -{ - struct rndis_wlan_private *priv = - container_of(work, struct rndis_wlan_private, work); - struct usbnet *usbdev = priv->usbdev; - - if (test_and_clear_bit(WORK_LINK_UP, &priv->work_pending)) - rndis_wlan_do_link_up_work(usbdev); - - if (test_and_clear_bit(WORK_LINK_DOWN, &priv->work_pending)) - rndis_wlan_do_link_down_work(usbdev); - - if (test_and_clear_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending)) - set_multicast_list(usbdev); -} - -static void rndis_wlan_set_multicast_list(struct net_device *dev) -{ - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - - if (test_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending)) - return; - - set_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending); - queue_work(priv->workqueue, &priv->work); -} - -static void rndis_wlan_auth_indication(struct usbnet *usbdev, - struct ndis_80211_status_indication *indication, - int len) -{ - u8 *buf; - const char *type; - int flags, buflen, key_id; - bool pairwise_error, group_error; - struct ndis_80211_auth_request *auth_req; - enum nl80211_key_type key_type; - - /* must have at least one array entry */ - if (len < offsetof(struct ndis_80211_status_indication, u) + - sizeof(struct ndis_80211_auth_request)) { - netdev_info(usbdev->net, "authentication indication: too short message (%i)\n", - len); - return; - } - - buf = (void *)&indication->u.auth_request[0]; - buflen = len - offsetof(struct ndis_80211_status_indication, u); - - while (buflen >= sizeof(*auth_req)) { - auth_req = (void *)buf; - if (buflen < le32_to_cpu(auth_req->length)) - return; - type = "unknown"; - flags = le32_to_cpu(auth_req->flags); - pairwise_error = false; - group_error = false; - - if (flags & 0x1) - type = "reauth request"; - if (flags & 0x2) - type = "key update request"; - if (flags & 0x6) { - pairwise_error = true; - type = "pairwise_error"; - } - if (flags & 0xe) { - group_error = true; - type = "group_error"; - } - - netdev_info(usbdev->net, "authentication indication: %s (0x%08x)\n", - type, le32_to_cpu(auth_req->flags)); - - if (pairwise_error) { - key_type = NL80211_KEYTYPE_PAIRWISE; - key_id = -1; - - cfg80211_michael_mic_failure(usbdev->net, - auth_req->bssid, - key_type, key_id, NULL, - GFP_KERNEL); - } - - if (group_error) { - key_type = NL80211_KEYTYPE_GROUP; - key_id = -1; - - cfg80211_michael_mic_failure(usbdev->net, - auth_req->bssid, - key_type, key_id, NULL, - GFP_KERNEL); - } - - buflen -= le32_to_cpu(auth_req->length); - buf += le32_to_cpu(auth_req->length); - } -} - -static void rndis_wlan_pmkid_cand_list_indication(struct usbnet *usbdev, - struct ndis_80211_status_indication *indication, - int len) -{ - struct ndis_80211_pmkid_cand_list *cand_list; - int list_len, expected_len, i; - - if (len < offsetof(struct ndis_80211_status_indication, u) + - sizeof(struct ndis_80211_pmkid_cand_list)) { - netdev_info(usbdev->net, "pmkid candidate list indication: too short message (%i)\n", - len); - return; - } - - list_len = le32_to_cpu(indication->u.cand_list.num_candidates) * - sizeof(struct ndis_80211_pmkid_candidate); - expected_len = sizeof(struct ndis_80211_pmkid_cand_list) + list_len + - offsetof(struct ndis_80211_status_indication, u); - - if (len < expected_len) { - netdev_info(usbdev->net, "pmkid candidate list indication: list larger than buffer (%i < %i)\n", - len, expected_len); - return; - } - - cand_list = &indication->u.cand_list; - - netdev_info(usbdev->net, "pmkid candidate list indication: version %i, candidates %i\n", - le32_to_cpu(cand_list->version), - le32_to_cpu(cand_list->num_candidates)); - - if (le32_to_cpu(cand_list->version) != 1) - return; - - for (i = 0; i < le32_to_cpu(cand_list->num_candidates); i++) { - struct ndis_80211_pmkid_candidate *cand = - &cand_list->candidate_list[i]; - bool preauth = !!(cand->flags & NDIS_80211_PMKID_CAND_PREAUTH); - - netdev_dbg(usbdev->net, "cand[%i]: flags: 0x%08x, preauth: %d, bssid: %pM\n", - i, le32_to_cpu(cand->flags), preauth, cand->bssid); - - cfg80211_pmksa_candidate_notify(usbdev->net, i, cand->bssid, - preauth, GFP_ATOMIC); - } -} - -static void rndis_wlan_media_specific_indication(struct usbnet *usbdev, - struct rndis_indicate *msg, int buflen) -{ - struct ndis_80211_status_indication *indication; - unsigned int len, offset; - - offset = offsetof(struct rndis_indicate, status) + - le32_to_cpu(msg->offset); - len = le32_to_cpu(msg->length); - - if (len < 8) { - netdev_info(usbdev->net, "media specific indication, ignore too short message (%i < 8)\n", - len); - return; - } - - if (len > buflen || offset > buflen || offset + len > buflen) { - netdev_info(usbdev->net, "media specific indication, too large to fit to buffer (%i > %i)\n", - offset + len, buflen); - return; - } - - indication = (void *)((u8 *)msg + offset); - - switch (le32_to_cpu(indication->status_type)) { - case NDIS_80211_STATUSTYPE_RADIOSTATE: - netdev_info(usbdev->net, "radio state indication: %i\n", - le32_to_cpu(indication->u.radio_status)); - return; - - case NDIS_80211_STATUSTYPE_MEDIASTREAMMODE: - netdev_info(usbdev->net, "media stream mode indication: %i\n", - le32_to_cpu(indication->u.media_stream_mode)); - return; - - case NDIS_80211_STATUSTYPE_AUTHENTICATION: - rndis_wlan_auth_indication(usbdev, indication, len); - return; - - case NDIS_80211_STATUSTYPE_PMKID_CANDIDATELIST: - rndis_wlan_pmkid_cand_list_indication(usbdev, indication, len); - return; - - default: - netdev_info(usbdev->net, "media specific indication: unknown status type 0x%08x\n", - le32_to_cpu(indication->status_type)); - } -} - -static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct rndis_indicate *msg = ind; - - switch (le32_to_cpu(msg->status)) { - case RNDIS_STATUS_MEDIA_CONNECT: - if (priv->current_command_oid == RNDIS_OID_802_11_ADD_KEY) { - /* RNDIS_OID_802_11_ADD_KEY causes sometimes extra - * "media connect" indications which confuses driver - * and userspace to think that device is - * roaming/reassociating when it isn't. - */ - netdev_dbg(usbdev->net, "ignored RNDIS_OID_802_11_ADD_KEY triggered 'media connect'\n"); - return; - } - - usbnet_pause_rx(usbdev); - - netdev_info(usbdev->net, "media connect\n"); - - /* queue work to avoid recursive calls into rndis_command */ - set_bit(WORK_LINK_UP, &priv->work_pending); - queue_work(priv->workqueue, &priv->work); - break; - - case RNDIS_STATUS_MEDIA_DISCONNECT: - netdev_info(usbdev->net, "media disconnect\n"); - - /* queue work to avoid recursive calls into rndis_command */ - set_bit(WORK_LINK_DOWN, &priv->work_pending); - queue_work(priv->workqueue, &priv->work); - break; - - case RNDIS_STATUS_MEDIA_SPECIFIC_INDICATION: - rndis_wlan_media_specific_indication(usbdev, msg, buflen); - break; - - default: - netdev_info(usbdev->net, "indication: 0x%08x\n", - le32_to_cpu(msg->status)); - break; - } -} - -static int rndis_wlan_get_caps(struct usbnet *usbdev, struct wiphy *wiphy) -{ - struct { - __le32 num_items; - __le32 items[8]; - } networks_supported; - struct ndis_80211_capability caps; - int len, retval, i, n; - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - - /* determine supported modes */ - len = sizeof(networks_supported); - retval = rndis_query_oid(usbdev, - RNDIS_OID_802_11_NETWORK_TYPES_SUPPORTED, - &networks_supported, &len); - if (!retval) { - n = le32_to_cpu(networks_supported.num_items); - if (n > 8) - n = 8; - for (i = 0; i < n; i++) { - switch (le32_to_cpu(networks_supported.items[i])) { - case NDIS_80211_TYPE_FREQ_HOP: - case NDIS_80211_TYPE_DIRECT_SEQ: - priv->caps |= CAP_MODE_80211B; - break; - case NDIS_80211_TYPE_OFDM_A: - priv->caps |= CAP_MODE_80211A; - break; - case NDIS_80211_TYPE_OFDM_G: - priv->caps |= CAP_MODE_80211G; - break; - } - } - } - - /* get device 802.11 capabilities, number of PMKIDs */ - len = sizeof(caps); - retval = rndis_query_oid(usbdev, - RNDIS_OID_802_11_CAPABILITY, - &caps, &len); - if (!retval) { - netdev_dbg(usbdev->net, "RNDIS_OID_802_11_CAPABILITY -> len %d, " - "ver %d, pmkids %d, auth-encr-pairs %d\n", - le32_to_cpu(caps.length), - le32_to_cpu(caps.version), - le32_to_cpu(caps.num_pmkids), - le32_to_cpu(caps.num_auth_encr_pair)); - wiphy->max_num_pmkids = le32_to_cpu(caps.num_pmkids); - } else - wiphy->max_num_pmkids = 0; - - return retval; -} - -static void rndis_do_cqm(struct usbnet *usbdev, s32 rssi) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - enum nl80211_cqm_rssi_threshold_event event; - int thold, hyst, last_event; - - if (priv->cqm_rssi_thold >= 0 || rssi >= 0) - return; - if (priv->infra_mode != NDIS_80211_INFRA_INFRA) - return; - - last_event = priv->last_cqm_event_rssi; - thold = priv->cqm_rssi_thold; - hyst = priv->cqm_rssi_hyst; - - if (rssi < thold && (last_event == 0 || rssi < last_event - hyst)) - event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW; - else if (rssi > thold && (last_event == 0 || rssi > last_event + hyst)) - event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; - else - return; - - priv->last_cqm_event_rssi = rssi; - cfg80211_cqm_rssi_notify(usbdev->net, event, rssi, GFP_KERNEL); -} - -#define DEVICE_POLLER_JIFFIES (HZ) -static void rndis_device_poller(struct work_struct *work) -{ - struct rndis_wlan_private *priv = - container_of(work, struct rndis_wlan_private, - dev_poller_work.work); - struct usbnet *usbdev = priv->usbdev; - __le32 rssi, tmp; - int len, ret, j; - int update_jiffies = DEVICE_POLLER_JIFFIES; - void *buf; - - /* Only check/do workaround when connected. Calling is_associated() - * also polls device with rndis_command() and catches for media link - * indications. - */ - if (!is_associated(usbdev)) { - /* Workaround bad scanning in BCM4320a devices with active - * background scanning when not associated. - */ - if (priv->device_type == RNDIS_BCM4320A && priv->radio_on && - !priv->scan_request) { - /* Get previous scan results */ - rndis_check_bssid_list(usbdev, NULL, NULL); - - /* Initiate new scan */ - rndis_start_bssid_list_scan(usbdev); - } - - goto end; - } - - len = sizeof(rssi); - ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_RSSI, - &rssi, &len); - if (ret == 0) { - priv->last_qual = level_to_qual(le32_to_cpu(rssi)); - rndis_do_cqm(usbdev, le32_to_cpu(rssi)); - } - - netdev_dbg(usbdev->net, "dev-poller: RNDIS_OID_802_11_RSSI -> %d, rssi:%d, qual: %d\n", - ret, le32_to_cpu(rssi), level_to_qual(le32_to_cpu(rssi))); - - /* Workaround transfer stalls on poor quality links. - * TODO: find right way to fix these stalls (as stalls do not happen - * with ndiswrapper/windows driver). */ - if (priv->param_workaround_interval > 0 && priv->last_qual <= 25) { - /* Decrease stats worker interval to catch stalls. - * faster. Faster than 400-500ms causes packet loss, - * Slower doesn't catch stalls fast enough. - */ - j = msecs_to_jiffies(priv->param_workaround_interval); - if (j > DEVICE_POLLER_JIFFIES) - j = DEVICE_POLLER_JIFFIES; - else if (j <= 0) - j = 1; - update_jiffies = j; - - /* Send scan OID. Use of both OIDs is required to get device - * working. - */ - tmp = cpu_to_le32(1); - rndis_set_oid(usbdev, - RNDIS_OID_802_11_BSSID_LIST_SCAN, - &tmp, sizeof(tmp)); - - len = CONTROL_BUFFER_SIZE; - buf = kmalloc(len, GFP_KERNEL); - if (!buf) - goto end; - - rndis_query_oid(usbdev, - RNDIS_OID_802_11_BSSID_LIST, - buf, &len); - kfree(buf); - } - -end: - if (update_jiffies >= HZ) - update_jiffies = round_jiffies_relative(update_jiffies); - else { - j = round_jiffies_relative(update_jiffies); - if (abs(j - update_jiffies) <= 10) - update_jiffies = j; - } - - queue_delayed_work(priv->workqueue, &priv->dev_poller_work, - update_jiffies); -} - -/* - * driver/device initialization - */ -static void rndis_copy_module_params(struct usbnet *usbdev, int device_type) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - - priv->device_type = device_type; - - priv->param_country[0] = modparam_country[0]; - priv->param_country[1] = modparam_country[1]; - priv->param_country[2] = 0; - priv->param_frameburst = modparam_frameburst; - priv->param_afterburner = modparam_afterburner; - priv->param_power_save = modparam_power_save; - priv->param_power_output = modparam_power_output; - priv->param_roamtrigger = modparam_roamtrigger; - priv->param_roamdelta = modparam_roamdelta; - - priv->param_country[0] = toupper(priv->param_country[0]); - priv->param_country[1] = toupper(priv->param_country[1]); - /* doesn't support EU as country code, use FI instead */ - if (!strcmp(priv->param_country, "EU")) - strcpy(priv->param_country, "FI"); - - if (priv->param_power_save < 0) - priv->param_power_save = 0; - else if (priv->param_power_save > 2) - priv->param_power_save = 2; - - if (priv->param_power_output < 0) - priv->param_power_output = 0; - else if (priv->param_power_output > 3) - priv->param_power_output = 3; - - if (priv->param_roamtrigger < -80) - priv->param_roamtrigger = -80; - else if (priv->param_roamtrigger > -60) - priv->param_roamtrigger = -60; - - if (priv->param_roamdelta < 0) - priv->param_roamdelta = 0; - else if (priv->param_roamdelta > 2) - priv->param_roamdelta = 2; - - if (modparam_workaround_interval < 0) - priv->param_workaround_interval = 500; - else - priv->param_workaround_interval = modparam_workaround_interval; -} - -static int unknown_early_init(struct usbnet *usbdev) -{ - /* copy module parameters for unknown so that iwconfig reports txpower - * and workaround parameter is copied to private structure correctly. - */ - rndis_copy_module_params(usbdev, RNDIS_UNKNOWN); - - /* This is unknown device, so do not try set configuration parameters. - */ - - return 0; -} - -static int bcm4320a_early_init(struct usbnet *usbdev) -{ - /* copy module parameters for bcm4320a so that iwconfig reports txpower - * and workaround parameter is copied to private structure correctly. - */ - rndis_copy_module_params(usbdev, RNDIS_BCM4320A); - - /* bcm4320a doesn't handle configuration parameters well. Try - * set any and you get partially zeroed mac and broken device. - */ - - return 0; -} - -static int bcm4320b_early_init(struct usbnet *usbdev) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - char buf[8]; - - rndis_copy_module_params(usbdev, RNDIS_BCM4320B); - - /* Early initialization settings, setting these won't have effect - * if called after generic_rndis_bind(). - */ - - rndis_set_config_parameter_str(usbdev, "Country", priv->param_country); - rndis_set_config_parameter_str(usbdev, "FrameBursting", - priv->param_frameburst ? "1" : "0"); - rndis_set_config_parameter_str(usbdev, "Afterburner", - priv->param_afterburner ? "1" : "0"); - sprintf(buf, "%d", priv->param_power_save); - rndis_set_config_parameter_str(usbdev, "PowerSaveMode", buf); - sprintf(buf, "%d", priv->param_power_output); - rndis_set_config_parameter_str(usbdev, "PwrOut", buf); - sprintf(buf, "%d", priv->param_roamtrigger); - rndis_set_config_parameter_str(usbdev, "RoamTrigger", buf); - sprintf(buf, "%d", priv->param_roamdelta); - rndis_set_config_parameter_str(usbdev, "RoamDelta", buf); - - return 0; -} - -/* same as rndis_netdev_ops but with local multicast handler */ -static const struct net_device_ops rndis_wlan_netdev_ops = { - .ndo_open = usbnet_open, - .ndo_stop = usbnet_stop, - .ndo_start_xmit = usbnet_start_xmit, - .ndo_tx_timeout = usbnet_tx_timeout, - .ndo_get_stats64 = dev_get_tstats64, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, - .ndo_set_rx_mode = rndis_wlan_set_multicast_list, -}; - -static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) -{ - struct wiphy *wiphy; - struct rndis_wlan_private *priv; - int retval, len; - __le32 tmp; - - /* allocate wiphy and rndis private data - * NOTE: We only support a single virtual interface, so wiphy - * and wireless_dev are somewhat synonymous for this device. - */ - wiphy = wiphy_new(&rndis_config_ops, sizeof(struct rndis_wlan_private)); - if (!wiphy) - return -ENOMEM; - - priv = wiphy_priv(wiphy); - usbdev->net->ieee80211_ptr = &priv->wdev; - priv->wdev.wiphy = wiphy; - priv->wdev.iftype = NL80211_IFTYPE_STATION; - - /* These have to be initialized before calling generic_rndis_bind(). - * Otherwise we'll be in big trouble in rndis_wlan_early_init(). - */ - usbdev->driver_priv = priv; - priv->usbdev = usbdev; - - mutex_init(&priv->command_lock); - - /* because rndis_command() sleeps we need to use workqueue */ - priv->workqueue = create_singlethread_workqueue("rndis_wlan"); - if (!priv->workqueue) { - wiphy_free(wiphy); - return -ENOMEM; - } - INIT_WORK(&priv->work, rndis_wlan_worker); - INIT_DELAYED_WORK(&priv->dev_poller_work, rndis_device_poller); - INIT_DELAYED_WORK(&priv->scan_work, rndis_get_scan_results); - - /* try bind rndis_host */ - retval = generic_rndis_bind(usbdev, intf, FLAG_RNDIS_PHYM_WIRELESS); - if (retval < 0) - goto fail; - - /* generic_rndis_bind set packet filter to multicast_all+ - * promisc mode which doesn't work well for our devices (device - * picks up rssi to closest station instead of to access point). - * - * rndis_host wants to avoid all OID as much as possible - * so do promisc/multicast handling in rndis_wlan. - */ - usbdev->net->netdev_ops = &rndis_wlan_netdev_ops; - - tmp = cpu_to_le32(RNDIS_PACKET_TYPE_DIRECTED | RNDIS_PACKET_TYPE_BROADCAST); - retval = rndis_set_oid(usbdev, - RNDIS_OID_GEN_CURRENT_PACKET_FILTER, - &tmp, sizeof(tmp)); - - len = sizeof(tmp); - retval = rndis_query_oid(usbdev, - RNDIS_OID_802_3_MAXIMUM_LIST_SIZE, - &tmp, &len); - priv->multicast_size = le32_to_cpu(tmp); - if (retval < 0 || priv->multicast_size < 0) - priv->multicast_size = 0; - if (priv->multicast_size > 0) - usbdev->net->flags |= IFF_MULTICAST; - else - usbdev->net->flags &= ~IFF_MULTICAST; - - /* fill-out wiphy structure and register w/ cfg80211 */ - memcpy(wiphy->perm_addr, usbdev->net->dev_addr, ETH_ALEN); - wiphy->privid = rndis_wiphy_privid; - wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) - | BIT(NL80211_IFTYPE_ADHOC); - wiphy->max_scan_ssids = 1; - - /* TODO: fill-out band/encr information based on priv->caps */ - rndis_wlan_get_caps(usbdev, wiphy); - - memcpy(priv->channels, rndis_channels, sizeof(rndis_channels)); - memcpy(priv->rates, rndis_rates, sizeof(rndis_rates)); - priv->band.channels = priv->channels; - priv->band.n_channels = ARRAY_SIZE(rndis_channels); - priv->band.bitrates = priv->rates; - priv->band.n_bitrates = ARRAY_SIZE(rndis_rates); - wiphy->bands[NL80211_BAND_2GHZ] = &priv->band; - wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; - - memcpy(priv->cipher_suites, rndis_cipher_suites, - sizeof(rndis_cipher_suites)); - wiphy->cipher_suites = priv->cipher_suites; - wiphy->n_cipher_suites = ARRAY_SIZE(rndis_cipher_suites); - - set_wiphy_dev(wiphy, &usbdev->udev->dev); - - if (wiphy_register(wiphy)) { - retval = -ENODEV; - goto fail; - } - - set_default_iw_params(usbdev); - - priv->power_mode = -1; - - /* set default rts/frag */ - rndis_set_wiphy_params(wiphy, - WIPHY_PARAM_FRAG_THRESHOLD | WIPHY_PARAM_RTS_THRESHOLD); - - /* turn radio off on init */ - priv->radio_on = false; - disassociate(usbdev, false); - netif_carrier_off(usbdev->net); - - return 0; - -fail: - cancel_delayed_work_sync(&priv->dev_poller_work); - cancel_delayed_work_sync(&priv->scan_work); - cancel_work_sync(&priv->work); - destroy_workqueue(priv->workqueue); - - wiphy_free(wiphy); - return retval; -} - -static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - - /* turn radio off */ - disassociate(usbdev, false); - - cancel_delayed_work_sync(&priv->dev_poller_work); - cancel_delayed_work_sync(&priv->scan_work); - cancel_work_sync(&priv->work); - destroy_workqueue(priv->workqueue); - - rndis_unbind(usbdev, intf); - - wiphy_unregister(priv->wdev.wiphy); - wiphy_free(priv->wdev.wiphy); -} - -static int rndis_wlan_reset(struct usbnet *usbdev) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - int retval; - - netdev_dbg(usbdev->net, "%s()\n", __func__); - - retval = rndis_reset(usbdev); - if (retval) - netdev_warn(usbdev->net, "rndis_reset failed: %d\n", retval); - - /* rndis_reset cleared multicast list, so restore here. - (set_multicast_list() also turns on current packet filter) */ - set_multicast_list(usbdev); - - queue_delayed_work(priv->workqueue, &priv->dev_poller_work, - round_jiffies_relative(DEVICE_POLLER_JIFFIES)); - - return deauthenticate(usbdev); -} - -static int rndis_wlan_stop(struct usbnet *usbdev) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - int retval; - __le32 filter; - - netdev_dbg(usbdev->net, "%s()\n", __func__); - - retval = disassociate(usbdev, false); - - priv->work_pending = 0; - cancel_delayed_work_sync(&priv->dev_poller_work); - cancel_delayed_work_sync(&priv->scan_work); - cancel_work_sync(&priv->work); - flush_workqueue(priv->workqueue); - - if (priv->scan_request) { - struct cfg80211_scan_info info = { - .aborted = true, - }; - - cfg80211_scan_done(priv->scan_request, &info); - priv->scan_request = NULL; - } - - /* Set current packet filter zero to block receiving data packets from - device. */ - filter = 0; - rndis_set_oid(usbdev, RNDIS_OID_GEN_CURRENT_PACKET_FILTER, &filter, - sizeof(filter)); - - return retval; -} - -static const struct driver_info bcm4320b_info = { - .description = "Wireless RNDIS device, BCM4320b based", - .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT | - FLAG_AVOID_UNLINK_URBS, - .bind = rndis_wlan_bind, - .unbind = rndis_wlan_unbind, - .status = rndis_status, - .rx_fixup = rndis_rx_fixup, - .tx_fixup = rndis_tx_fixup, - .reset = rndis_wlan_reset, - .stop = rndis_wlan_stop, - .early_init = bcm4320b_early_init, - .indication = rndis_wlan_indication, -}; - -static const struct driver_info bcm4320a_info = { - .description = "Wireless RNDIS device, BCM4320a based", - .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT | - FLAG_AVOID_UNLINK_URBS, - .bind = rndis_wlan_bind, - .unbind = rndis_wlan_unbind, - .status = rndis_status, - .rx_fixup = rndis_rx_fixup, - .tx_fixup = rndis_tx_fixup, - .reset = rndis_wlan_reset, - .stop = rndis_wlan_stop, - .early_init = bcm4320a_early_init, - .indication = rndis_wlan_indication, -}; - -static const struct driver_info rndis_wlan_info = { - .description = "Wireless RNDIS device", - .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT | - FLAG_AVOID_UNLINK_URBS, - .bind = rndis_wlan_bind, - .unbind = rndis_wlan_unbind, - .status = rndis_status, - .rx_fixup = rndis_rx_fixup, - .tx_fixup = rndis_tx_fixup, - .reset = rndis_wlan_reset, - .stop = rndis_wlan_stop, - .early_init = unknown_early_init, - .indication = rndis_wlan_indication, -}; - -/*-------------------------------------------------------------------------*/ - -static const struct usb_device_id products [] = { -#define RNDIS_MASTER_INTERFACE \ - .bInterfaceClass = USB_CLASS_COMM, \ - .bInterfaceSubClass = 2 /* ACM */, \ - .bInterfaceProtocol = 0x0ff - -/* INF driver for these devices have DriverVer >= 4.xx.xx.xx and many custom - * parameters available. Chipset marked as 'BCM4320SKFBG' in NDISwrapper-wiki. - */ -{ - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x0411, - .idProduct = 0x00bc, /* Buffalo WLI-U2-KG125S */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320b_info, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x0baf, - .idProduct = 0x011b, /* U.S. Robotics USR5421 */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320b_info, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x050d, - .idProduct = 0x011b, /* Belkin F5D7051 */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320b_info, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x1799, /* Belkin has two vendor ids */ - .idProduct = 0x011b, /* Belkin F5D7051 */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320b_info, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x13b1, - .idProduct = 0x0014, /* Linksys WUSB54GSv2 */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320b_info, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x13b1, - .idProduct = 0x0026, /* Linksys WUSB54GSC */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320b_info, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x0b05, - .idProduct = 0x1717, /* Asus WL169gE */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320b_info, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x0a5c, - .idProduct = 0xd11b, /* Eminent EM4045 */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320b_info, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x1690, - .idProduct = 0x0715, /* BT Voyager 1055 */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320b_info, -}, -/* These devices have DriverVer < 4.xx.xx.xx and do not have any custom - * parameters available, hardware probably contain older firmware version with - * no way of updating. Chipset marked as 'BCM4320????' in NDISwrapper-wiki. - */ -{ - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x13b1, - .idProduct = 0x000e, /* Linksys WUSB54GSv1 */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320a_info, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x0baf, - .idProduct = 0x0111, /* U.S. Robotics USR5420 */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320a_info, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x0411, - .idProduct = 0x004b, /* BUFFALO WLI-USB-G54 */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320a_info, -}, -/* Generic Wireless RNDIS devices that we don't have exact - * idVendor/idProduct/chip yet. - */ -{ - /* RNDIS is MSFT's un-official variant of CDC ACM */ - USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff), - .driver_info = (unsigned long) &rndis_wlan_info, -}, { - /* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */ - USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1), - .driver_info = (unsigned long) &rndis_wlan_info, -}, - { }, // END -}; -MODULE_DEVICE_TABLE(usb, products); - -static struct usb_driver rndis_wlan_driver = { - .name = "rndis_wlan", - .id_table = products, - .probe = usbnet_probe, - .disconnect = usbnet_disconnect, - .suspend = usbnet_suspend, - .resume = usbnet_resume, - .disable_hub_initiated_lpm = 1, -}; - -module_usb_driver(rndis_wlan_driver); - -MODULE_AUTHOR("Bjorge Dijkstra"); -MODULE_AUTHOR("Jussi Kivilinna"); -MODULE_DESCRIPTION("Driver for RNDIS based USB Wireless adapters"); -MODULE_LICENSE("GPL"); - diff --git a/drivers/net/wireless/legacy/wl3501.h b/drivers/net/wireless/legacy/wl3501.h deleted file mode 100644 index 91f276dd22a1b..0000000000000 --- a/drivers/net/wireless/legacy/wl3501.h +++ /dev/null @@ -1,615 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __WL3501_H__ -#define __WL3501_H__ - -#include -#include - -/* define for WLA 2.0 */ -#define WL3501_BLKSZ 256 -/* - * ID for input Signals of DRIVER block - * bit[7-5] is block ID: 000 - * bit[4-0] is signal ID -*/ -enum wl3501_signals { - WL3501_SIG_ALARM, - WL3501_SIG_MD_CONFIRM, - WL3501_SIG_MD_IND, - WL3501_SIG_ASSOC_CONFIRM, - WL3501_SIG_ASSOC_IND, - WL3501_SIG_AUTH_CONFIRM, - WL3501_SIG_AUTH_IND, - WL3501_SIG_DEAUTH_CONFIRM, - WL3501_SIG_DEAUTH_IND, - WL3501_SIG_DISASSOC_CONFIRM, - WL3501_SIG_DISASSOC_IND, - WL3501_SIG_GET_CONFIRM, - WL3501_SIG_JOIN_CONFIRM, - WL3501_SIG_PWR_MGMT_CONFIRM, - WL3501_SIG_REASSOC_CONFIRM, - WL3501_SIG_REASSOC_IND, - WL3501_SIG_SCAN_CONFIRM, - WL3501_SIG_SET_CONFIRM, - WL3501_SIG_START_CONFIRM, - WL3501_SIG_RESYNC_CONFIRM, - WL3501_SIG_SITE_CONFIRM, - WL3501_SIG_SAVE_CONFIRM, - WL3501_SIG_RFTEST_CONFIRM, -/* - * ID for input Signals of MLME block - * bit[7-5] is block ID: 010 - * bit[4-0] is signal ID - */ - WL3501_SIG_ASSOC_REQ = 0x20, - WL3501_SIG_AUTH_REQ, - WL3501_SIG_DEAUTH_REQ, - WL3501_SIG_DISASSOC_REQ, - WL3501_SIG_GET_REQ, - WL3501_SIG_JOIN_REQ, - WL3501_SIG_PWR_MGMT_REQ, - WL3501_SIG_REASSOC_REQ, - WL3501_SIG_SCAN_REQ, - WL3501_SIG_SET_REQ, - WL3501_SIG_START_REQ, - WL3501_SIG_MD_REQ, - WL3501_SIG_RESYNC_REQ, - WL3501_SIG_SITE_REQ, - WL3501_SIG_SAVE_REQ, - WL3501_SIG_RF_TEST_REQ, - WL3501_SIG_MM_CONFIRM = 0x60, - WL3501_SIG_MM_IND, -}; - -enum wl3501_mib_attribs { - WL3501_MIB_ATTR_STATION_ID, - WL3501_MIB_ATTR_AUTH_ALGORITHMS, - WL3501_MIB_ATTR_AUTH_TYPE, - WL3501_MIB_ATTR_MEDIUM_OCCUPANCY_LIMIT, - WL3501_MIB_ATTR_CF_POLLABLE, - WL3501_MIB_ATTR_CFP_PERIOD, - WL3501_MIB_ATTR_CFPMAX_DURATION, - WL3501_MIB_ATTR_AUTH_RESP_TMOUT, - WL3501_MIB_ATTR_RX_DTIMS, - WL3501_MIB_ATTR_PRIV_OPT_IMPLEMENTED, - WL3501_MIB_ATTR_PRIV_INVOKED, - WL3501_MIB_ATTR_WEP_DEFAULT_KEYS, - WL3501_MIB_ATTR_WEP_DEFAULT_KEY_ID, - WL3501_MIB_ATTR_WEP_KEY_MAPPINGS, - WL3501_MIB_ATTR_WEP_KEY_MAPPINGS_LEN, - WL3501_MIB_ATTR_EXCLUDE_UNENCRYPTED, - WL3501_MIB_ATTR_WEP_ICV_ERROR_COUNT, - WL3501_MIB_ATTR_WEP_UNDECRYPTABLE_COUNT, - WL3501_MIB_ATTR_WEP_EXCLUDED_COUNT, - WL3501_MIB_ATTR_MAC_ADDR, - WL3501_MIB_ATTR_GROUP_ADDRS, - WL3501_MIB_ATTR_RTS_THRESHOLD, - WL3501_MIB_ATTR_SHORT_RETRY_LIMIT, - WL3501_MIB_ATTR_LONG_RETRY_LIMIT, - WL3501_MIB_ATTR_FRAG_THRESHOLD, - WL3501_MIB_ATTR_MAX_TX_MSDU_LIFETIME, - WL3501_MIB_ATTR_MAX_RX_LIFETIME, - WL3501_MIB_ATTR_MANUFACTURER_ID, - WL3501_MIB_ATTR_PRODUCT_ID, - WL3501_MIB_ATTR_TX_FRAG_COUNT, - WL3501_MIB_ATTR_MULTICAST_TX_FRAME_COUNT, - WL3501_MIB_ATTR_FAILED_COUNT, - WL3501_MIB_ATTR_RX_FRAG_COUNT, - WL3501_MIB_ATTR_MULTICAST_RX_COUNT, - WL3501_MIB_ATTR_FCS_ERROR_COUNT, - WL3501_MIB_ATTR_RETRY_COUNT, - WL3501_MIB_ATTR_MULTIPLE_RETRY_COUNT, - WL3501_MIB_ATTR_RTS_SUCCESS_COUNT, - WL3501_MIB_ATTR_RTS_FAILURE_COUNT, - WL3501_MIB_ATTR_ACK_FAILURE_COUNT, - WL3501_MIB_ATTR_FRAME_DUPLICATE_COUNT, - WL3501_MIB_ATTR_PHY_TYPE, - WL3501_MIB_ATTR_REG_DOMAINS_SUPPORT, - WL3501_MIB_ATTR_CURRENT_REG_DOMAIN, - WL3501_MIB_ATTR_SLOT_TIME, - WL3501_MIB_ATTR_CCA_TIME, - WL3501_MIB_ATTR_RX_TX_TURNAROUND_TIME, - WL3501_MIB_ATTR_TX_PLCP_DELAY, - WL3501_MIB_ATTR_RX_TX_SWITCH_TIME, - WL3501_MIB_ATTR_TX_RAMP_ON_TIME, - WL3501_MIB_ATTR_TX_RF_DELAY, - WL3501_MIB_ATTR_SIFS_TIME, - WL3501_MIB_ATTR_RX_RF_DELAY, - WL3501_MIB_ATTR_RX_PLCP_DELAY, - WL3501_MIB_ATTR_MAC_PROCESSING_DELAY, - WL3501_MIB_ATTR_TX_RAMP_OFF_TIME, - WL3501_MIB_ATTR_PREAMBLE_LEN, - WL3501_MIB_ATTR_PLCP_HEADER_LEN, - WL3501_MIB_ATTR_MPDU_DURATION_FACTOR, - WL3501_MIB_ATTR_AIR_PROPAGATION_TIME, - WL3501_MIB_ATTR_TEMP_TYPE, - WL3501_MIB_ATTR_CW_MIN, - WL3501_MIB_ATTR_CW_MAX, - WL3501_MIB_ATTR_SUPPORT_DATA_RATES_TX, - WL3501_MIB_ATTR_SUPPORT_DATA_RATES_RX, - WL3501_MIB_ATTR_MPDU_MAX_LEN, - WL3501_MIB_ATTR_SUPPORT_TX_ANTENNAS, - WL3501_MIB_ATTR_CURRENT_TX_ANTENNA, - WL3501_MIB_ATTR_SUPPORT_RX_ANTENNAS, - WL3501_MIB_ATTR_DIVERSITY_SUPPORT, - WL3501_MIB_ATTR_DIVERSITY_SELECTION_RS, - WL3501_MIB_ATTR_NR_SUPPORTED_PWR_LEVELS, - WL3501_MIB_ATTR_TX_PWR_LEVEL1, - WL3501_MIB_ATTR_TX_PWR_LEVEL2, - WL3501_MIB_ATTR_TX_PWR_LEVEL3, - WL3501_MIB_ATTR_TX_PWR_LEVEL4, - WL3501_MIB_ATTR_TX_PWR_LEVEL5, - WL3501_MIB_ATTR_TX_PWR_LEVEL6, - WL3501_MIB_ATTR_TX_PWR_LEVEL7, - WL3501_MIB_ATTR_TX_PWR_LEVEL8, - WL3501_MIB_ATTR_CURRENT_TX_PWR_LEVEL, - WL3501_MIB_ATTR_CURRENT_CHAN, - WL3501_MIB_ATTR_CCA_MODE_SUPPORTED, - WL3501_MIB_ATTR_CURRENT_CCA_MODE, - WL3501_MIB_ATTR_ED_THRESHOLD, - WL3501_MIB_ATTR_SINTHESIZER_LOCKED, - WL3501_MIB_ATTR_CURRENT_PWR_STATE, - WL3501_MIB_ATTR_DOZE_TURNON_TIME, - WL3501_MIB_ATTR_RCR33, - WL3501_MIB_ATTR_DEFAULT_CHAN, - WL3501_MIB_ATTR_SSID, - WL3501_MIB_ATTR_PWR_MGMT_ENABLE, - WL3501_MIB_ATTR_NET_CAPABILITY, - WL3501_MIB_ATTR_ROUTING, -}; - -enum wl3501_net_type { - WL3501_NET_TYPE_INFRA, - WL3501_NET_TYPE_ADHOC, - WL3501_NET_TYPE_ANY_BSS, -}; - -enum wl3501_scan_type { - WL3501_SCAN_TYPE_ACTIVE, - WL3501_SCAN_TYPE_PASSIVE, -}; - -enum wl3501_tx_result { - WL3501_TX_RESULT_SUCCESS, - WL3501_TX_RESULT_NO_BSS, - WL3501_TX_RESULT_RETRY_LIMIT, -}; - -enum wl3501_sys_type { - WL3501_SYS_TYPE_OPEN, - WL3501_SYS_TYPE_SHARE_KEY, -}; - -enum wl3501_status { - WL3501_STATUS_SUCCESS, - WL3501_STATUS_INVALID, - WL3501_STATUS_TIMEOUT, - WL3501_STATUS_REFUSED, - WL3501_STATUS_MANY_REQ, - WL3501_STATUS_ALREADY_BSS, -}; - -#define WL3501_MGMT_CAPABILITY_ESS 0x0001 /* see 802.11 p.58 */ -#define WL3501_MGMT_CAPABILITY_IBSS 0x0002 /* - " - */ -#define WL3501_MGMT_CAPABILITY_CF_POLLABLE 0x0004 /* - " - */ -#define WL3501_MGMT_CAPABILITY_CF_POLL_REQUEST 0x0008 /* - " - */ -#define WL3501_MGMT_CAPABILITY_PRIVACY 0x0010 /* - " - */ - -#define IW_REG_DOMAIN_FCC 0x10 /* Channel 1 to 11 USA */ -#define IW_REG_DOMAIN_DOC 0x20 /* Channel 1 to 11 Canada */ -#define IW_REG_DOMAIN_ETSI 0x30 /* Channel 1 to 13 Europe */ -#define IW_REG_DOMAIN_SPAIN 0x31 /* Channel 10 to 11 Spain */ -#define IW_REG_DOMAIN_FRANCE 0x32 /* Channel 10 to 13 France */ -#define IW_REG_DOMAIN_MKK 0x40 /* Channel 14 Japan */ -#define IW_REG_DOMAIN_MKK1 0x41 /* Channel 1-14 Japan */ -#define IW_REG_DOMAIN_ISRAEL 0x50 /* Channel 3 - 9 Israel */ - -#define IW_MGMT_RATE_LABEL_MANDATORY 128 /* MSB */ - -enum iw_mgmt_rate_labels { - IW_MGMT_RATE_LABEL_1MBIT = 2, - IW_MGMT_RATE_LABEL_2MBIT = 4, - IW_MGMT_RATE_LABEL_5_5MBIT = 11, - IW_MGMT_RATE_LABEL_11MBIT = 22, -}; - -enum iw_mgmt_info_element_ids { - IW_MGMT_INFO_ELEMENT_SSID, /* Service Set Identity */ - IW_MGMT_INFO_ELEMENT_SUPPORTED_RATES, - IW_MGMT_INFO_ELEMENT_FH_PARAMETER_SET, - IW_MGMT_INFO_ELEMENT_DS_PARAMETER_SET, - IW_MGMT_INFO_ELEMENT_CS_PARAMETER_SET, - IW_MGMT_INFO_ELEMENT_CS_TIM, /* Traffic Information Map */ - IW_MGMT_INFO_ELEMENT_IBSS_PARAMETER_SET, - /* 7-15: Reserved, unused */ - IW_MGMT_INFO_ELEMENT_CHALLENGE_TEXT = 16, - /* 17-31 Reserved for challenge text extension */ - /* 32-255 Reserved, unused */ -}; - -struct iw_mgmt_info_element { - u8 id; /* one of enum iw_mgmt_info_element_ids, - but sizeof(enum) > sizeof(u8) :-( */ - u8 len; - u8 data[]; -} __packed; - -struct iw_mgmt_essid_pset { - struct iw_mgmt_info_element el; - u8 essid[IW_ESSID_MAX_SIZE]; -} __packed; - -/* - * According to 802.11 Wireless Networks, the definitive guide - O'Reilly - * Pg 75 - */ -#define IW_DATA_RATE_MAX_LABELS 8 - -struct iw_mgmt_data_rset { - struct iw_mgmt_info_element el; - u8 data_rate_labels[IW_DATA_RATE_MAX_LABELS]; -} __packed; - -struct iw_mgmt_ds_pset { - struct iw_mgmt_info_element el; - u8 chan; -} __packed; - -struct iw_mgmt_cf_pset { - struct iw_mgmt_info_element el; - u8 cfp_count; - u8 cfp_period; - u16 cfp_max_duration; - u16 cfp_dur_remaining; -} __packed; - -struct iw_mgmt_ibss_pset { - struct iw_mgmt_info_element el; - u16 atim_window; -} __packed; - -struct wl3501_tx_hdr { - u16 tx_cnt; - u8 sync[16]; - u16 sfd; - u8 signal; - u8 service; - u16 len; - u16 crc16; - u16 frame_ctrl; - u16 duration_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 addr3[ETH_ALEN]; - u16 seq_ctrl; - u8 addr4[ETH_ALEN]; -}; - -struct wl3501_rx_hdr { - u16 rx_next_blk; - u16 rc_next_frame_blk; - u8 rx_blk_ctrl; - u8 rx_next_frame; - u8 rx_next_frame1; - u8 rssi; - char time[8]; - u8 signal; - u8 service; - u16 len; - u16 crc16; - u16 frame_ctrl; - u16 duration; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 addr3[ETH_ALEN]; - u16 seq; - u8 addr4[ETH_ALEN]; -}; - -struct wl3501_start_req { - u16 next_blk; - u8 sig_id; - u8 bss_type; - u16 beacon_period; - u16 dtim_period; - u16 probe_delay; - u16 cap_info; - struct iw_mgmt_essid_pset ssid; - struct iw_mgmt_data_rset bss_basic_rset; - struct iw_mgmt_data_rset operational_rset; - struct iw_mgmt_cf_pset cf_pset; - struct iw_mgmt_ds_pset ds_pset; - struct iw_mgmt_ibss_pset ibss_pset; -}; - -struct wl3501_assoc_req { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 timeout; - u16 cap_info; - u16 listen_interval; - u8 mac_addr[ETH_ALEN]; -}; - -struct wl3501_assoc_confirm { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 status; -}; - -struct wl3501_assoc_ind { - u16 next_blk; - u8 sig_id; - u8 mac_addr[ETH_ALEN]; -}; - -struct wl3501_auth_req { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 type; - u16 timeout; - u8 mac_addr[ETH_ALEN]; -}; - -struct wl3501_auth_confirm { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 type; - u16 status; - u8 mac_addr[ETH_ALEN]; -}; - -struct wl3501_get_req { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 mib_attrib; -}; - -struct wl3501_get_confirm { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 mib_status; - u16 mib_attrib; - u8 mib_value[100]; -}; - -struct wl3501_req { - u16 beacon_period; - u16 dtim_period; - u16 cap_info; - u8 bss_type; - u8 bssid[ETH_ALEN]; - struct iw_mgmt_essid_pset ssid; - struct iw_mgmt_ds_pset ds_pset; - struct iw_mgmt_cf_pset cf_pset; - struct iw_mgmt_ibss_pset ibss_pset; - struct iw_mgmt_data_rset bss_basic_rset; -}; - -struct wl3501_join_req { - u16 next_blk; - u8 sig_id; - u8 reserved; - struct iw_mgmt_data_rset operational_rset; - u16 reserved2; - u16 timeout; - u16 probe_delay; - u8 timestamp[8]; - u8 local_time[8]; - struct wl3501_req req; -}; - -struct wl3501_join_confirm { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 status; -}; - -struct wl3501_pwr_mgmt_req { - u16 next_blk; - u8 sig_id; - u8 pwr_save; - u8 wake_up; - u8 receive_dtims; -}; - -struct wl3501_pwr_mgmt_confirm { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 status; -}; - -struct wl3501_scan_req { - u16 next_blk; - u8 sig_id; - u8 bss_type; - u16 probe_delay; - u16 min_chan_time; - u16 max_chan_time; - u8 chan_list[14]; - u8 bssid[ETH_ALEN]; - struct iw_mgmt_essid_pset ssid; - enum wl3501_scan_type scan_type; -}; - -struct wl3501_scan_confirm { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 status; - char timestamp[8]; - char localtime[8]; - struct wl3501_req req; - u8 rssi; -}; - -struct wl3501_start_confirm { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 status; -}; - -struct wl3501_md_req { - u16 next_blk; - u8 sig_id; - u8 routing; - u16 data; - u16 size; - u8 pri; - u8 service_class; - struct { - u8 daddr[ETH_ALEN]; - u8 saddr[ETH_ALEN]; - } addr; -}; - -struct wl3501_md_ind { - u16 next_blk; - u8 sig_id; - u8 routing; - u16 data; - u16 size; - u8 reception; - u8 pri; - u8 service_class; - struct { - u8 daddr[ETH_ALEN]; - u8 saddr[ETH_ALEN]; - } addr; -}; - -struct wl3501_md_confirm { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 data; - u8 status; - u8 pri; - u8 service_class; -}; - -struct wl3501_resync_req { - u16 next_blk; - u8 sig_id; -}; - -/* Definitions for supporting clone adapters. */ -/* System Interface Registers (SIR space) */ -#define WL3501_NIC_GCR ((u8)0x00) /* SIR0 - General Conf Register */ -#define WL3501_NIC_BSS ((u8)0x01) /* SIR1 - Bank Switching Select Reg */ -#define WL3501_NIC_LMAL ((u8)0x02) /* SIR2 - Local Mem addr Reg [7:0] */ -#define WL3501_NIC_LMAH ((u8)0x03) /* SIR3 - Local Mem addr Reg [14:8] */ -#define WL3501_NIC_IODPA ((u8)0x04) /* SIR4 - I/O Data Port A */ -#define WL3501_NIC_IODPB ((u8)0x05) /* SIR5 - I/O Data Port B */ -#define WL3501_NIC_IODPC ((u8)0x06) /* SIR6 - I/O Data Port C */ -#define WL3501_NIC_IODPD ((u8)0x07) /* SIR7 - I/O Data Port D */ - -/* Bits in GCR */ -#define WL3501_GCR_SWRESET ((u8)0x80) -#define WL3501_GCR_CORESET ((u8)0x40) -#define WL3501_GCR_DISPWDN ((u8)0x20) -#define WL3501_GCR_ECWAIT ((u8)0x10) -#define WL3501_GCR_ECINT ((u8)0x08) -#define WL3501_GCR_INT2EC ((u8)0x04) -#define WL3501_GCR_ENECINT ((u8)0x02) -#define WL3501_GCR_DAM ((u8)0x01) - -/* Bits in BSS (Bank Switching Select Register) */ -#define WL3501_BSS_FPAGE0 ((u8)0x20) /* Flash memory page0 */ -#define WL3501_BSS_FPAGE1 ((u8)0x28) -#define WL3501_BSS_FPAGE2 ((u8)0x30) -#define WL3501_BSS_FPAGE3 ((u8)0x38) -#define WL3501_BSS_SPAGE0 ((u8)0x00) /* SRAM page0 */ -#define WL3501_BSS_SPAGE1 ((u8)0x08) -#define WL3501_BSS_SPAGE2 ((u8)0x10) -#define WL3501_BSS_SPAGE3 ((u8)0x18) - -/* Define Driver Interface */ -/* Refer IEEE 802.11 */ -/* Tx packet header, include PLCP and MPDU */ -/* Tx PLCP Header */ -struct wl3501_80211_tx_plcp_hdr { - u8 sync[16]; - u16 sfd; - u8 signal; - u8 service; - u16 len; - u16 crc16; -} __packed; - -struct wl3501_80211_tx_hdr { - struct wl3501_80211_tx_plcp_hdr pclp_hdr; - struct ieee80211_hdr mac_hdr; -} __packed __aligned(2); - -/* - Reserve the beginning Tx space for descriptor use. - - TxBlockOffset --> *----*----*----*----* \ - (TxFreeDesc) | 0 | 1 | 2 | 3 | \ - | 4 | 5 | 6 | 7 | | - | 8 | 9 | 10 | 11 | TX_DESC * 20 - | 12 | 13 | 14 | 15 | | - | 16 | 17 | 18 | 19 | / - TxBufferBegin --> *----*----*----*----* / - (TxBufferHead) | | - (TxBufferTail) | | - | Send Buffer | - | | - | | - *-------------------* - TxBufferEnd -------------------------/ - -*/ - -struct wl3501_card { - int base_addr; - u8 mac_addr[ETH_ALEN]; - spinlock_t lock; - wait_queue_head_t wait; - struct wl3501_get_confirm sig_get_confirm; - struct wl3501_pwr_mgmt_confirm sig_pwr_mgmt_confirm; - u16 tx_buffer_size; - u16 tx_buffer_head; - u16 tx_buffer_tail; - u16 tx_buffer_cnt; - u16 esbq_req_start; - u16 esbq_req_end; - u16 esbq_req_head; - u16 esbq_req_tail; - u16 esbq_confirm_start; - u16 esbq_confirm_end; - u16 esbq_confirm; - struct iw_mgmt_essid_pset essid; - struct iw_mgmt_essid_pset keep_essid; - u8 bssid[ETH_ALEN]; - int net_type; - char nick[32]; - char card_name[32]; - char firmware_date[32]; - u8 chan; - u8 cap_info; - u16 start_seg; - u16 bss_cnt; - u16 join_sta_bss; - u8 rssi; - u8 adhoc_times; - u8 reg_domain; - u8 version[2]; - struct wl3501_scan_confirm bss_set[20]; - - struct iw_statistics wstats; - struct iw_spy_data spy_data; - struct iw_public_data wireless_data; - struct pcmcia_device *p_dev; -}; -#endif diff --git a/drivers/net/wireless/legacy/wl3501_cs.c b/drivers/net/wireless/legacy/wl3501_cs.c deleted file mode 100644 index c45c4b7cbbaf1..0000000000000 --- a/drivers/net/wireless/legacy/wl3501_cs.c +++ /dev/null @@ -1,2036 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * WL3501 Wireless LAN PCMCIA Card Driver for Linux - * Written originally for Linux 2.0.30 by Fox Chen, mhchen@golf.ccl.itri.org.tw - * Ported to 2.2, 2.4 & 2.5 by Arnaldo Carvalho de Melo - * Wireless extensions in 2.4 by Gustavo Niemeyer - * - * References used by Fox Chen while writing the original driver for 2.0.30: - * - * 1. WL24xx packet drivers (tooasm.asm) - * 2. Access Point Firmware Interface Specification for IEEE 802.11 SUTRO - * 3. IEEE 802.11 - * 4. Linux network driver (/usr/src/linux/drivers/net) - * 5. ISA card driver - wl24.c - * 6. Linux PCMCIA skeleton driver - skeleton.c - * 7. Linux PCMCIA 3c589 network driver - 3c589_cs.c - * - * Tested with WL2400 firmware 1.2, Linux 2.0.30, and pcmcia-cs-2.9.12 - * 1. Performance: about 165 Kbytes/sec in TCP/IP with Ad-Hoc mode. - * rsh 192.168.1.3 "dd if=/dev/zero bs=1k count=1000" > /dev/null - * (Specification 2M bits/sec. is about 250 Kbytes/sec., but we must deduct - * ETHER/IP/UDP/TCP header, and acknowledgement overhead) - * - * Tested with Planet AP in 2.4.17, 184 Kbytes/s in UDP in Infrastructure mode, - * 173 Kbytes/s in TCP. - * - * Tested with Planet AP in 2.5.73-bk, 216 Kbytes/s in Infrastructure mode - * with a SMP machine (dual pentium 100), using pktgen, 432 pps (pkt_size = 60) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include -#include - -#include "wl3501.h" - -#ifndef __i386__ -#define slow_down_io() -#endif - -/* For rough constant delay */ -#define WL3501_NOPLOOP(n) { int x = 0; while (x++ < n) slow_down_io(); } - - - -#define wl3501_outb(a, b) { outb(a, b); slow_down_io(); } -#define wl3501_outb_p(a, b) { outb_p(a, b); slow_down_io(); } -#define wl3501_outsb(a, b, c) { outsb(a, b, c); slow_down_io(); } - -#define WL3501_RELEASE_TIMEOUT (25 * HZ) -#define WL3501_MAX_ADHOC_TRIES 16 - -#define WL3501_RESUME 0 -#define WL3501_SUSPEND 1 - -static int wl3501_config(struct pcmcia_device *link); -static void wl3501_release(struct pcmcia_device *link); - -static const struct { - int reg_domain; - int min, max, deflt; -} iw_channel_table[] = { - { - .reg_domain = IW_REG_DOMAIN_FCC, - .min = 1, - .max = 11, - .deflt = 1, - }, - { - .reg_domain = IW_REG_DOMAIN_DOC, - .min = 1, - .max = 11, - .deflt = 1, - }, - { - .reg_domain = IW_REG_DOMAIN_ETSI, - .min = 1, - .max = 13, - .deflt = 1, - }, - { - .reg_domain = IW_REG_DOMAIN_SPAIN, - .min = 10, - .max = 11, - .deflt = 10, - }, - { - .reg_domain = IW_REG_DOMAIN_FRANCE, - .min = 10, - .max = 13, - .deflt = 10, - }, - { - .reg_domain = IW_REG_DOMAIN_MKK, - .min = 14, - .max = 14, - .deflt = 14, - }, - { - .reg_domain = IW_REG_DOMAIN_MKK1, - .min = 1, - .max = 14, - .deflt = 1, - }, - { - .reg_domain = IW_REG_DOMAIN_ISRAEL, - .min = 3, - .max = 9, - .deflt = 9, - }, -}; - -/** - * iw_valid_channel - validate channel in regulatory domain - * @reg_domain: regulatory domain - * @channel: channel to validate - * - * Returns 0 if invalid in the specified regulatory domain, non-zero if valid. - */ -static int iw_valid_channel(int reg_domain, int channel) -{ - int i, rc = 0; - - for (i = 0; i < ARRAY_SIZE(iw_channel_table); i++) - if (reg_domain == iw_channel_table[i].reg_domain) { - rc = channel >= iw_channel_table[i].min && - channel <= iw_channel_table[i].max; - break; - } - return rc; -} - -/** - * iw_default_channel - get default channel for a regulatory domain - * @reg_domain: regulatory domain - * - * Returns the default channel for a regulatory domain - */ -static int iw_default_channel(int reg_domain) -{ - int i, rc = 1; - - for (i = 0; i < ARRAY_SIZE(iw_channel_table); i++) - if (reg_domain == iw_channel_table[i].reg_domain) { - rc = iw_channel_table[i].deflt; - break; - } - return rc; -} - -static void iw_set_mgmt_info_element(enum iw_mgmt_info_element_ids id, - struct iw_mgmt_info_element *el, - void *value, int len) -{ - el->id = id; - el->len = len; - memcpy(el->data, value, len); -} - -static void iw_copy_mgmt_info_element(struct iw_mgmt_info_element *to, - struct iw_mgmt_info_element *from) -{ - iw_set_mgmt_info_element(from->id, to, from->data, from->len); -} - -static inline void wl3501_switch_page(struct wl3501_card *this, u8 page) -{ - wl3501_outb(page, this->base_addr + WL3501_NIC_BSS); -} - -/* - * Get Ethernet MAC address. - * - * WARNING: We switch to FPAGE0 and switc back again. - * Making sure there is no other WL function beening called by ISR. - */ -static int wl3501_get_flash_mac_addr(struct wl3501_card *this) -{ - int base_addr = this->base_addr; - - /* get MAC addr */ - wl3501_outb(WL3501_BSS_FPAGE3, base_addr + WL3501_NIC_BSS); /* BSS */ - wl3501_outb(0x00, base_addr + WL3501_NIC_LMAL); /* LMAL */ - wl3501_outb(0x40, base_addr + WL3501_NIC_LMAH); /* LMAH */ - - /* wait for reading EEPROM */ - WL3501_NOPLOOP(100); - this->mac_addr[0] = inb(base_addr + WL3501_NIC_IODPA); - WL3501_NOPLOOP(100); - this->mac_addr[1] = inb(base_addr + WL3501_NIC_IODPA); - WL3501_NOPLOOP(100); - this->mac_addr[2] = inb(base_addr + WL3501_NIC_IODPA); - WL3501_NOPLOOP(100); - this->mac_addr[3] = inb(base_addr + WL3501_NIC_IODPA); - WL3501_NOPLOOP(100); - this->mac_addr[4] = inb(base_addr + WL3501_NIC_IODPA); - WL3501_NOPLOOP(100); - this->mac_addr[5] = inb(base_addr + WL3501_NIC_IODPA); - WL3501_NOPLOOP(100); - this->reg_domain = inb(base_addr + WL3501_NIC_IODPA); - WL3501_NOPLOOP(100); - wl3501_outb(WL3501_BSS_FPAGE0, base_addr + WL3501_NIC_BSS); - wl3501_outb(0x04, base_addr + WL3501_NIC_LMAL); - wl3501_outb(0x40, base_addr + WL3501_NIC_LMAH); - WL3501_NOPLOOP(100); - this->version[0] = inb(base_addr + WL3501_NIC_IODPA); - WL3501_NOPLOOP(100); - this->version[1] = inb(base_addr + WL3501_NIC_IODPA); - /* switch to SRAM Page 0 (for safety) */ - wl3501_switch_page(this, WL3501_BSS_SPAGE0); - - /* The MAC addr should be 00:60:... */ - return this->mac_addr[0] == 0x00 && this->mac_addr[1] == 0x60; -} - -/** - * wl3501_set_to_wla - Move 'size' bytes from PC to card - * @this: Card - * @dest: Card addressing space - * @src: PC addressing space - * @size: Bytes to move - * - * Move 'size' bytes from PC to card. (Shouldn't be interrupted) - */ -static void wl3501_set_to_wla(struct wl3501_card *this, u16 dest, void *src, - int size) -{ - /* switch to SRAM Page 0 */ - wl3501_switch_page(this, (dest & 0x8000) ? WL3501_BSS_SPAGE1 : - WL3501_BSS_SPAGE0); - /* set LMAL and LMAH */ - wl3501_outb(dest & 0xff, this->base_addr + WL3501_NIC_LMAL); - wl3501_outb(((dest >> 8) & 0x7f), this->base_addr + WL3501_NIC_LMAH); - - /* rep out to Port A */ - wl3501_outsb(this->base_addr + WL3501_NIC_IODPA, src, size); -} - -/** - * wl3501_get_from_wla - Move 'size' bytes from card to PC - * @this: Card - * @src: Card addressing space - * @dest: PC addressing space - * @size: Bytes to move - * - * Move 'size' bytes from card to PC. (Shouldn't be interrupted) - */ -static void wl3501_get_from_wla(struct wl3501_card *this, u16 src, void *dest, - int size) -{ - /* switch to SRAM Page 0 */ - wl3501_switch_page(this, (src & 0x8000) ? WL3501_BSS_SPAGE1 : - WL3501_BSS_SPAGE0); - /* set LMAL and LMAH */ - wl3501_outb(src & 0xff, this->base_addr + WL3501_NIC_LMAL); - wl3501_outb((src >> 8) & 0x7f, this->base_addr + WL3501_NIC_LMAH); - - /* rep get from Port A */ - insb(this->base_addr + WL3501_NIC_IODPA, dest, size); -} - -/* - * Get/Allocate a free Tx Data Buffer - * - * *--------------*-----------------*----------------------------------* - * | PLCP | MAC Header | DST SRC Data ... | - * | (24 bytes) | (30 bytes) | (6) (6) (Ethernet Row Data) | - * *--------------*-----------------*----------------------------------* - * \ \- IEEE 802.11 -/ \-------------- len --------------/ - * \-struct wl3501_80211_tx_hdr--/ \-------- Ethernet Frame -------/ - * - * Return = Position in Card - */ -static u16 wl3501_get_tx_buffer(struct wl3501_card *this, u16 len) -{ - u16 next, blk_cnt = 0, zero = 0; - u16 full_len = sizeof(struct wl3501_80211_tx_hdr) + len; - u16 ret = 0; - - if (full_len > this->tx_buffer_cnt * 254) - goto out; - ret = this->tx_buffer_head; - while (full_len) { - if (full_len < 254) - full_len = 0; - else - full_len -= 254; - wl3501_get_from_wla(this, this->tx_buffer_head, &next, - sizeof(next)); - if (!full_len) - wl3501_set_to_wla(this, this->tx_buffer_head, &zero, - sizeof(zero)); - this->tx_buffer_head = next; - blk_cnt++; - /* if buffer is not enough */ - if (!next && full_len) { - this->tx_buffer_head = ret; - ret = 0; - goto out; - } - } - this->tx_buffer_cnt -= blk_cnt; -out: - return ret; -} - -/* - * Free an allocated Tx Buffer. ptr must be correct position. - */ -static void wl3501_free_tx_buffer(struct wl3501_card *this, u16 ptr) -{ - /* check if all space is not free */ - if (!this->tx_buffer_head) - this->tx_buffer_head = ptr; - else - wl3501_set_to_wla(this, this->tx_buffer_tail, - &ptr, sizeof(ptr)); - while (ptr) { - u16 next; - - this->tx_buffer_cnt++; - wl3501_get_from_wla(this, ptr, &next, sizeof(next)); - this->tx_buffer_tail = ptr; - ptr = next; - } -} - -static int wl3501_esbq_req_test(struct wl3501_card *this) -{ - u8 tmp = 0; - - wl3501_get_from_wla(this, this->esbq_req_head + 3, &tmp, sizeof(tmp)); - return tmp & 0x80; -} - -static void wl3501_esbq_req(struct wl3501_card *this, u16 *ptr) -{ - u16 tmp = 0; - - wl3501_set_to_wla(this, this->esbq_req_head, ptr, 2); - wl3501_set_to_wla(this, this->esbq_req_head + 2, &tmp, sizeof(tmp)); - this->esbq_req_head += 4; - if (this->esbq_req_head >= this->esbq_req_end) - this->esbq_req_head = this->esbq_req_start; -} - -static int wl3501_esbq_exec(struct wl3501_card *this, void *sig, int sig_size) -{ - int rc = -EIO; - - if (wl3501_esbq_req_test(this)) { - u16 ptr = wl3501_get_tx_buffer(this, sig_size); - if (ptr) { - wl3501_set_to_wla(this, ptr, sig, sig_size); - wl3501_esbq_req(this, &ptr); - rc = 0; - } - } - return rc; -} - -static int wl3501_request_mib(struct wl3501_card *this, u8 index, void *bf) -{ - struct wl3501_get_req sig = { - .sig_id = WL3501_SIG_GET_REQ, - .mib_attrib = index, - }; - unsigned long flags; - int rc = -EIO; - - spin_lock_irqsave(&this->lock, flags); - if (wl3501_esbq_req_test(this)) { - u16 ptr = wl3501_get_tx_buffer(this, sizeof(sig)); - if (ptr) { - wl3501_set_to_wla(this, ptr, &sig, sizeof(sig)); - wl3501_esbq_req(this, &ptr); - this->sig_get_confirm.mib_status = 255; - rc = 0; - } - } - spin_unlock_irqrestore(&this->lock, flags); - - return rc; -} - -static int wl3501_get_mib_value(struct wl3501_card *this, u8 index, - void *bf, int size) -{ - int rc; - - rc = wl3501_request_mib(this, index, bf); - if (rc) - return rc; - - rc = wait_event_interruptible(this->wait, - this->sig_get_confirm.mib_status != 255); - if (rc) - return rc; - - memcpy(bf, this->sig_get_confirm.mib_value, size); - return 0; -} - -static int wl3501_pwr_mgmt(struct wl3501_card *this, int suspend) -{ - struct wl3501_pwr_mgmt_req sig = { - .sig_id = WL3501_SIG_PWR_MGMT_REQ, - .pwr_save = suspend, - .wake_up = !suspend, - .receive_dtims = 10, - }; - unsigned long flags; - int rc = -EIO; - - spin_lock_irqsave(&this->lock, flags); - if (wl3501_esbq_req_test(this)) { - u16 ptr = wl3501_get_tx_buffer(this, sizeof(sig)); - if (ptr) { - wl3501_set_to_wla(this, ptr, &sig, sizeof(sig)); - wl3501_esbq_req(this, &ptr); - this->sig_pwr_mgmt_confirm.status = 255; - spin_unlock_irqrestore(&this->lock, flags); - rc = wait_event_interruptible(this->wait, - this->sig_pwr_mgmt_confirm.status != 255); - printk(KERN_INFO "%s: %s status=%d\n", __func__, - suspend ? "suspend" : "resume", - this->sig_pwr_mgmt_confirm.status); - goto out; - } - } - spin_unlock_irqrestore(&this->lock, flags); -out: - return rc; -} - -/** - * wl3501_send_pkt - Send a packet. - * @this: Card - * @data: Ethernet raw frame. (e.g. data[0] - data[5] is Dest MAC Addr, - * data[6] - data[11] is Src MAC Addr) - * @len: Packet length - * Ref: IEEE 802.11 - */ -static int wl3501_send_pkt(struct wl3501_card *this, u8 *data, u16 len) -{ - u16 bf, sig_bf, next, tmplen, pktlen; - struct wl3501_md_req sig = { - .sig_id = WL3501_SIG_MD_REQ, - }; - size_t sig_addr_len = sizeof(sig.addr); - u8 *pdata = (char *)data; - int rc = -EIO; - - if (wl3501_esbq_req_test(this)) { - sig_bf = wl3501_get_tx_buffer(this, sizeof(sig)); - rc = -ENOMEM; - if (!sig_bf) /* No free buffer available */ - goto out; - bf = wl3501_get_tx_buffer(this, len + 26 + 24); - if (!bf) { - /* No free buffer available */ - wl3501_free_tx_buffer(this, sig_bf); - goto out; - } - rc = 0; - memcpy(&sig.addr, pdata, sig_addr_len); - pktlen = len - sig_addr_len; - pdata += sig_addr_len; - sig.data = bf; - if (((*pdata) * 256 + (*(pdata + 1))) > 1500) { - u8 addr4[ETH_ALEN] = { - [0] = 0xAA, [1] = 0xAA, [2] = 0x03, [4] = 0x00, - }; - - wl3501_set_to_wla(this, bf + 2 + - offsetof(struct wl3501_tx_hdr, addr4), - addr4, sizeof(addr4)); - sig.size = pktlen + 24 + 4 + 6; - if (pktlen > (254 - sizeof(struct wl3501_tx_hdr))) { - tmplen = 254 - sizeof(struct wl3501_tx_hdr); - pktlen -= tmplen; - } else { - tmplen = pktlen; - pktlen = 0; - } - wl3501_set_to_wla(this, - bf + 2 + sizeof(struct wl3501_tx_hdr), - pdata, tmplen); - pdata += tmplen; - wl3501_get_from_wla(this, bf, &next, sizeof(next)); - bf = next; - } else { - sig.size = pktlen + 24 + 4 - 2; - pdata += 2; - pktlen -= 2; - if (pktlen > (254 - sizeof(struct wl3501_tx_hdr) + 6)) { - tmplen = 254 - sizeof(struct wl3501_tx_hdr) + 6; - pktlen -= tmplen; - } else { - tmplen = pktlen; - pktlen = 0; - } - wl3501_set_to_wla(this, bf + 2 + - offsetof(struct wl3501_tx_hdr, addr4), - pdata, tmplen); - pdata += tmplen; - wl3501_get_from_wla(this, bf, &next, sizeof(next)); - bf = next; - } - while (pktlen > 0) { - if (pktlen > 254) { - tmplen = 254; - pktlen -= 254; - } else { - tmplen = pktlen; - pktlen = 0; - } - wl3501_set_to_wla(this, bf + 2, pdata, tmplen); - pdata += tmplen; - wl3501_get_from_wla(this, bf, &next, sizeof(next)); - bf = next; - } - wl3501_set_to_wla(this, sig_bf, &sig, sizeof(sig)); - wl3501_esbq_req(this, &sig_bf); - } -out: - return rc; -} - -static int wl3501_mgmt_resync(struct wl3501_card *this) -{ - struct wl3501_resync_req sig = { - .sig_id = WL3501_SIG_RESYNC_REQ, - }; - - return wl3501_esbq_exec(this, &sig, sizeof(sig)); -} - -static inline int wl3501_fw_bss_type(struct wl3501_card *this) -{ - return this->net_type == IW_MODE_INFRA ? WL3501_NET_TYPE_INFRA : - WL3501_NET_TYPE_ADHOC; -} - -static inline int wl3501_fw_cap_info(struct wl3501_card *this) -{ - return this->net_type == IW_MODE_INFRA ? WL3501_MGMT_CAPABILITY_ESS : - WL3501_MGMT_CAPABILITY_IBSS; -} - -static int wl3501_mgmt_scan(struct wl3501_card *this, u16 chan_time) -{ - struct wl3501_scan_req sig = { - .sig_id = WL3501_SIG_SCAN_REQ, - .scan_type = WL3501_SCAN_TYPE_ACTIVE, - .probe_delay = 0x10, - .min_chan_time = chan_time, - .max_chan_time = chan_time, - .bss_type = wl3501_fw_bss_type(this), - }; - - this->bss_cnt = this->join_sta_bss = 0; - return wl3501_esbq_exec(this, &sig, sizeof(sig)); -} - -static int wl3501_mgmt_join(struct wl3501_card *this, u16 stas) -{ - struct wl3501_join_req sig = { - .sig_id = WL3501_SIG_JOIN_REQ, - .timeout = 10, - .req.ds_pset = { - .el = { - .id = IW_MGMT_INFO_ELEMENT_DS_PARAMETER_SET, - .len = 1, - }, - .chan = this->chan, - }, - }; - - memcpy(&sig.req, &this->bss_set[stas].req, sizeof(sig.req)); - return wl3501_esbq_exec(this, &sig, sizeof(sig)); -} - -static int wl3501_mgmt_start(struct wl3501_card *this) -{ - struct wl3501_start_req sig = { - .sig_id = WL3501_SIG_START_REQ, - .beacon_period = 400, - .dtim_period = 1, - .ds_pset = { - .el = { - .id = IW_MGMT_INFO_ELEMENT_DS_PARAMETER_SET, - .len = 1, - }, - .chan = this->chan, - }, - .bss_basic_rset = { - .el = { - .id = IW_MGMT_INFO_ELEMENT_SUPPORTED_RATES, - .len = 2, - }, - .data_rate_labels = { - [0] = IW_MGMT_RATE_LABEL_MANDATORY | - IW_MGMT_RATE_LABEL_1MBIT, - [1] = IW_MGMT_RATE_LABEL_MANDATORY | - IW_MGMT_RATE_LABEL_2MBIT, - }, - }, - .operational_rset = { - .el = { - .id = IW_MGMT_INFO_ELEMENT_SUPPORTED_RATES, - .len = 2, - }, - .data_rate_labels = { - [0] = IW_MGMT_RATE_LABEL_MANDATORY | - IW_MGMT_RATE_LABEL_1MBIT, - [1] = IW_MGMT_RATE_LABEL_MANDATORY | - IW_MGMT_RATE_LABEL_2MBIT, - }, - }, - .ibss_pset = { - .el = { - .id = IW_MGMT_INFO_ELEMENT_IBSS_PARAMETER_SET, - .len = 2, - }, - .atim_window = 10, - }, - .bss_type = wl3501_fw_bss_type(this), - .cap_info = wl3501_fw_cap_info(this), - }; - - iw_copy_mgmt_info_element(&sig.ssid.el, &this->essid.el); - iw_copy_mgmt_info_element(&this->keep_essid.el, &this->essid.el); - return wl3501_esbq_exec(this, &sig, sizeof(sig)); -} - -static void wl3501_mgmt_scan_confirm(struct wl3501_card *this, u16 addr) -{ - u16 i = 0; - int matchflag = 0; - struct wl3501_scan_confirm sig; - - pr_debug("entry"); - wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); - if (sig.status == WL3501_STATUS_SUCCESS) { - pr_debug("success"); - if ((this->net_type == IW_MODE_INFRA && - (sig.req.cap_info & WL3501_MGMT_CAPABILITY_ESS)) || - (this->net_type == IW_MODE_ADHOC && - (sig.req.cap_info & WL3501_MGMT_CAPABILITY_IBSS)) || - this->net_type == IW_MODE_AUTO) { - if (!this->essid.el.len) - matchflag = 1; - else if (this->essid.el.len == 3 && - !memcmp(this->essid.essid, "ANY", 3)) - matchflag = 1; - else if (this->essid.el.len != sig.req.ssid.el.len) - matchflag = 0; - else if (memcmp(this->essid.essid, sig.req.ssid.essid, - this->essid.el.len)) - matchflag = 0; - else - matchflag = 1; - if (matchflag) { - for (i = 0; i < this->bss_cnt; i++) { - if (ether_addr_equal_unaligned(this->bss_set[i].req.bssid, - sig.req.bssid)) { - matchflag = 0; - break; - } - } - } - if (matchflag && (i < 20)) { - memcpy(&this->bss_set[i].req, - &sig.req, sizeof(sig.req)); - this->bss_cnt++; - this->rssi = sig.rssi; - this->bss_set[i].rssi = sig.rssi; - } - } - } else if (sig.status == WL3501_STATUS_TIMEOUT) { - pr_debug("timeout"); - this->join_sta_bss = 0; - for (i = this->join_sta_bss; i < this->bss_cnt; i++) - if (!wl3501_mgmt_join(this, i)) - break; - this->join_sta_bss = i; - if (this->join_sta_bss == this->bss_cnt) { - if (this->net_type == IW_MODE_INFRA) - wl3501_mgmt_scan(this, 100); - else { - this->adhoc_times++; - if (this->adhoc_times > WL3501_MAX_ADHOC_TRIES) - wl3501_mgmt_start(this); - else - wl3501_mgmt_scan(this, 100); - } - } - } -} - -/** - * wl3501_block_interrupt - Mask interrupt from SUTRO - * @this: Card - * - * Mask interrupt from SUTRO. (i.e. SUTRO cannot interrupt the HOST) - * Return: 1 if interrupt is originally enabled - */ -static int wl3501_block_interrupt(struct wl3501_card *this) -{ - u8 old = inb(this->base_addr + WL3501_NIC_GCR); - u8 new = old & (~(WL3501_GCR_ECINT | WL3501_GCR_INT2EC | - WL3501_GCR_ENECINT)); - - wl3501_outb(new, this->base_addr + WL3501_NIC_GCR); - return old & WL3501_GCR_ENECINT; -} - -/** - * wl3501_unblock_interrupt - Enable interrupt from SUTRO - * @this: Card - * - * Enable interrupt from SUTRO. (i.e. SUTRO can interrupt the HOST) - * Return: 1 if interrupt is originally enabled - */ -static int wl3501_unblock_interrupt(struct wl3501_card *this) -{ - u8 old = inb(this->base_addr + WL3501_NIC_GCR); - u8 new = (old & ~(WL3501_GCR_ECINT | WL3501_GCR_INT2EC)) | - WL3501_GCR_ENECINT; - - wl3501_outb(new, this->base_addr + WL3501_NIC_GCR); - return old & WL3501_GCR_ENECINT; -} - -/** - * wl3501_receive - Receive data from Receive Queue. - * - * Receive data from Receive Queue. - * - * @this: card - * @bf: address of host - * @size: size of buffer. - */ -static u16 wl3501_receive(struct wl3501_card *this, u8 *bf, u16 size) -{ - u16 next_addr, next_addr1; - u8 *data = bf + 12; - - size -= 12; - wl3501_get_from_wla(this, this->start_seg + 2, - &next_addr, sizeof(next_addr)); - if (size > WL3501_BLKSZ - sizeof(struct wl3501_rx_hdr)) { - wl3501_get_from_wla(this, - this->start_seg + - sizeof(struct wl3501_rx_hdr), data, - WL3501_BLKSZ - - sizeof(struct wl3501_rx_hdr)); - size -= WL3501_BLKSZ - sizeof(struct wl3501_rx_hdr); - data += WL3501_BLKSZ - sizeof(struct wl3501_rx_hdr); - } else { - wl3501_get_from_wla(this, - this->start_seg + - sizeof(struct wl3501_rx_hdr), - data, size); - size = 0; - } - while (size > 0) { - if (size > WL3501_BLKSZ - 5) { - wl3501_get_from_wla(this, next_addr + 5, data, - WL3501_BLKSZ - 5); - size -= WL3501_BLKSZ - 5; - data += WL3501_BLKSZ - 5; - wl3501_get_from_wla(this, next_addr + 2, &next_addr1, - sizeof(next_addr1)); - next_addr = next_addr1; - } else { - wl3501_get_from_wla(this, next_addr + 5, data, size); - size = 0; - } - } - return 0; -} - -static void wl3501_esbq_req_free(struct wl3501_card *this) -{ - u8 tmp; - u16 addr; - - if (this->esbq_req_head == this->esbq_req_tail) - goto out; - wl3501_get_from_wla(this, this->esbq_req_tail + 3, &tmp, sizeof(tmp)); - if (!(tmp & 0x80)) - goto out; - wl3501_get_from_wla(this, this->esbq_req_tail, &addr, sizeof(addr)); - wl3501_free_tx_buffer(this, addr); - this->esbq_req_tail += 4; - if (this->esbq_req_tail >= this->esbq_req_end) - this->esbq_req_tail = this->esbq_req_start; -out: - return; -} - -static int wl3501_esbq_confirm(struct wl3501_card *this) -{ - u8 tmp; - - wl3501_get_from_wla(this, this->esbq_confirm + 3, &tmp, sizeof(tmp)); - return tmp & 0x80; -} - -static void wl3501_online(struct net_device *dev) -{ - struct wl3501_card *this = netdev_priv(dev); - - printk(KERN_INFO "%s: Wireless LAN online. BSSID: %pM\n", - dev->name, this->bssid); - netif_wake_queue(dev); -} - -static void wl3501_esbq_confirm_done(struct wl3501_card *this) -{ - u8 tmp = 0; - - wl3501_set_to_wla(this, this->esbq_confirm + 3, &tmp, sizeof(tmp)); - this->esbq_confirm += 4; - if (this->esbq_confirm >= this->esbq_confirm_end) - this->esbq_confirm = this->esbq_confirm_start; -} - -static int wl3501_mgmt_auth(struct wl3501_card *this) -{ - struct wl3501_auth_req sig = { - .sig_id = WL3501_SIG_AUTH_REQ, - .type = WL3501_SYS_TYPE_OPEN, - .timeout = 1000, - }; - - pr_debug("entry"); - memcpy(sig.mac_addr, this->bssid, ETH_ALEN); - return wl3501_esbq_exec(this, &sig, sizeof(sig)); -} - -static int wl3501_mgmt_association(struct wl3501_card *this) -{ - struct wl3501_assoc_req sig = { - .sig_id = WL3501_SIG_ASSOC_REQ, - .timeout = 1000, - .listen_interval = 5, - .cap_info = this->cap_info, - }; - - pr_debug("entry"); - memcpy(sig.mac_addr, this->bssid, ETH_ALEN); - return wl3501_esbq_exec(this, &sig, sizeof(sig)); -} - -static void wl3501_mgmt_join_confirm(struct net_device *dev, u16 addr) -{ - struct wl3501_card *this = netdev_priv(dev); - struct wl3501_join_confirm sig; - - pr_debug("entry"); - wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); - if (sig.status == WL3501_STATUS_SUCCESS) { - if (this->net_type == IW_MODE_INFRA) { - if (this->join_sta_bss < this->bss_cnt) { - const int i = this->join_sta_bss; - memcpy(this->bssid, - this->bss_set[i].req.bssid, ETH_ALEN); - this->chan = this->bss_set[i].req.ds_pset.chan; - iw_copy_mgmt_info_element(&this->keep_essid.el, - &this->bss_set[i].req.ssid.el); - wl3501_mgmt_auth(this); - } - } else { - const int i = this->join_sta_bss; - - memcpy(&this->bssid, &this->bss_set[i].req.bssid, ETH_ALEN); - this->chan = this->bss_set[i].req.ds_pset.chan; - iw_copy_mgmt_info_element(&this->keep_essid.el, - &this->bss_set[i].req.ssid.el); - wl3501_online(dev); - } - } else { - int i; - this->join_sta_bss++; - for (i = this->join_sta_bss; i < this->bss_cnt; i++) - if (!wl3501_mgmt_join(this, i)) - break; - this->join_sta_bss = i; - if (this->join_sta_bss == this->bss_cnt) { - if (this->net_type == IW_MODE_INFRA) - wl3501_mgmt_scan(this, 100); - else { - this->adhoc_times++; - if (this->adhoc_times > WL3501_MAX_ADHOC_TRIES) - wl3501_mgmt_start(this); - else - wl3501_mgmt_scan(this, 100); - } - } - } -} - -static inline void wl3501_alarm_interrupt(struct net_device *dev, - struct wl3501_card *this) -{ - if (this->net_type == IW_MODE_INFRA) { - printk(KERN_INFO "Wireless LAN offline\n"); - netif_stop_queue(dev); - wl3501_mgmt_resync(this); - } -} - -static inline void wl3501_md_confirm_interrupt(struct net_device *dev, - struct wl3501_card *this, - u16 addr) -{ - struct wl3501_md_confirm sig; - - pr_debug("entry"); - wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); - wl3501_free_tx_buffer(this, sig.data); - if (netif_queue_stopped(dev)) - netif_wake_queue(dev); -} - -static inline void wl3501_md_ind_interrupt(struct net_device *dev, - struct wl3501_card *this, u16 addr) -{ - struct wl3501_md_ind sig; - struct sk_buff *skb; - u8 rssi, addr4[ETH_ALEN]; - u16 pkt_len; - - wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); - this->start_seg = sig.data; - wl3501_get_from_wla(this, - sig.data + offsetof(struct wl3501_rx_hdr, rssi), - &rssi, sizeof(rssi)); - this->rssi = rssi <= 63 ? (rssi * 100) / 64 : 255; - - wl3501_get_from_wla(this, - sig.data + - offsetof(struct wl3501_rx_hdr, addr4), - &addr4, sizeof(addr4)); - if (!(addr4[0] == 0xAA && addr4[1] == 0xAA && - addr4[2] == 0x03 && addr4[4] == 0x00)) { - printk(KERN_INFO "Unsupported packet type!\n"); - return; - } - pkt_len = sig.size + 12 - 24 - 4 - 6; - - skb = dev_alloc_skb(pkt_len + 5); - - if (!skb) { - printk(KERN_WARNING "%s: Can't alloc a sk_buff of size %d.\n", - dev->name, pkt_len); - dev->stats.rx_dropped++; - } else { - skb->dev = dev; - skb_reserve(skb, 2); /* IP headers on 16 bytes boundaries */ - skb_copy_to_linear_data(skb, (unsigned char *)&sig.addr, - sizeof(sig.addr)); - wl3501_receive(this, skb->data, pkt_len); - skb_put(skb, pkt_len); - skb->protocol = eth_type_trans(skb, dev); - dev->stats.rx_packets++; - dev->stats.rx_bytes += skb->len; - netif_rx(skb); - } -} - -static inline void wl3501_get_confirm_interrupt(struct wl3501_card *this, - u16 addr, void *sig, int size) -{ - pr_debug("entry"); - wl3501_get_from_wla(this, addr, &this->sig_get_confirm, - sizeof(this->sig_get_confirm)); - wake_up(&this->wait); -} - -static inline void wl3501_start_confirm_interrupt(struct net_device *dev, - struct wl3501_card *this, - u16 addr) -{ - struct wl3501_start_confirm sig; - - pr_debug("entry"); - wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); - if (sig.status == WL3501_STATUS_SUCCESS) - netif_wake_queue(dev); -} - -static inline void wl3501_assoc_confirm_interrupt(struct net_device *dev, - u16 addr) -{ - struct wl3501_card *this = netdev_priv(dev); - struct wl3501_assoc_confirm sig; - - pr_debug("entry"); - wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); - - if (sig.status == WL3501_STATUS_SUCCESS) - wl3501_online(dev); -} - -static inline void wl3501_auth_confirm_interrupt(struct wl3501_card *this, - u16 addr) -{ - struct wl3501_auth_confirm sig; - - pr_debug("entry"); - wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); - - if (sig.status == WL3501_STATUS_SUCCESS) - wl3501_mgmt_association(this); - else - wl3501_mgmt_resync(this); -} - -static inline void wl3501_rx_interrupt(struct net_device *dev) -{ - int morepkts; - u16 addr; - u8 sig_id; - struct wl3501_card *this = netdev_priv(dev); - - pr_debug("entry"); -loop: - morepkts = 0; - if (!wl3501_esbq_confirm(this)) - goto free; - wl3501_get_from_wla(this, this->esbq_confirm, &addr, sizeof(addr)); - wl3501_get_from_wla(this, addr + 2, &sig_id, sizeof(sig_id)); - - switch (sig_id) { - case WL3501_SIG_DEAUTH_IND: - case WL3501_SIG_DISASSOC_IND: - case WL3501_SIG_ALARM: - wl3501_alarm_interrupt(dev, this); - break; - case WL3501_SIG_MD_CONFIRM: - wl3501_md_confirm_interrupt(dev, this, addr); - break; - case WL3501_SIG_MD_IND: - wl3501_md_ind_interrupt(dev, this, addr); - break; - case WL3501_SIG_GET_CONFIRM: - wl3501_get_confirm_interrupt(this, addr, - &this->sig_get_confirm, - sizeof(this->sig_get_confirm)); - break; - case WL3501_SIG_PWR_MGMT_CONFIRM: - wl3501_get_confirm_interrupt(this, addr, - &this->sig_pwr_mgmt_confirm, - sizeof(this->sig_pwr_mgmt_confirm)); - break; - case WL3501_SIG_START_CONFIRM: - wl3501_start_confirm_interrupt(dev, this, addr); - break; - case WL3501_SIG_SCAN_CONFIRM: - wl3501_mgmt_scan_confirm(this, addr); - break; - case WL3501_SIG_JOIN_CONFIRM: - wl3501_mgmt_join_confirm(dev, addr); - break; - case WL3501_SIG_ASSOC_CONFIRM: - wl3501_assoc_confirm_interrupt(dev, addr); - break; - case WL3501_SIG_AUTH_CONFIRM: - wl3501_auth_confirm_interrupt(this, addr); - break; - case WL3501_SIG_RESYNC_CONFIRM: - wl3501_mgmt_resync(this); /* FIXME: should be resync_confirm */ - break; - } - wl3501_esbq_confirm_done(this); - morepkts = 1; - /* free request if necessary */ -free: - wl3501_esbq_req_free(this); - if (morepkts) - goto loop; -} - -static inline void wl3501_ack_interrupt(struct wl3501_card *this) -{ - wl3501_outb(WL3501_GCR_ECINT, this->base_addr + WL3501_NIC_GCR); -} - -/** - * wl3501_interrupt - Hardware interrupt from card. - * @irq: Interrupt number - * @dev_id: net_device - * - * We must acknowledge the interrupt as soon as possible, and block the - * interrupt from the same card immediately to prevent re-entry. - * - * Before accessing the Control_Status_Block, we must lock SUTRO first. - * On the other hand, to prevent SUTRO from malfunctioning, we must - * unlock the SUTRO as soon as possible. - */ -static irqreturn_t wl3501_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct wl3501_card *this; - - this = netdev_priv(dev); - spin_lock(&this->lock); - wl3501_ack_interrupt(this); - wl3501_block_interrupt(this); - wl3501_rx_interrupt(dev); - wl3501_unblock_interrupt(this); - spin_unlock(&this->lock); - - return IRQ_HANDLED; -} - -static int wl3501_reset_board(struct wl3501_card *this) -{ - u8 tmp = 0; - int i, rc = 0; - - /* Coreset */ - wl3501_outb_p(WL3501_GCR_CORESET, this->base_addr + WL3501_NIC_GCR); - wl3501_outb_p(0, this->base_addr + WL3501_NIC_GCR); - wl3501_outb_p(WL3501_GCR_CORESET, this->base_addr + WL3501_NIC_GCR); - - /* Reset SRAM 0x480 to zero */ - wl3501_set_to_wla(this, 0x480, &tmp, sizeof(tmp)); - - /* Start up */ - wl3501_outb_p(0, this->base_addr + WL3501_NIC_GCR); - - WL3501_NOPLOOP(1024 * 50); - - wl3501_unblock_interrupt(this); /* acme: was commented */ - - /* Polling Self_Test_Status */ - for (i = 0; i < 10000; i++) { - wl3501_get_from_wla(this, 0x480, &tmp, sizeof(tmp)); - - if (tmp == 'W') { - /* firmware complete all test successfully */ - tmp = 'A'; - wl3501_set_to_wla(this, 0x480, &tmp, sizeof(tmp)); - goto out; - } - WL3501_NOPLOOP(10); - } - printk(KERN_WARNING "%s: failed to reset the board!\n", __func__); - rc = -ENODEV; -out: - return rc; -} - -static int wl3501_init_firmware(struct wl3501_card *this) -{ - u16 ptr, next; - int rc = wl3501_reset_board(this); - - if (rc) - goto fail; - this->card_name[0] = '\0'; - wl3501_get_from_wla(this, 0x1a00, - this->card_name, sizeof(this->card_name)); - this->card_name[sizeof(this->card_name) - 1] = '\0'; - this->firmware_date[0] = '\0'; - wl3501_get_from_wla(this, 0x1a40, - this->firmware_date, sizeof(this->firmware_date)); - this->firmware_date[sizeof(this->firmware_date) - 1] = '\0'; - /* Switch to SRAM Page 0 */ - wl3501_switch_page(this, WL3501_BSS_SPAGE0); - /* Read parameter from card */ - wl3501_get_from_wla(this, 0x482, &this->esbq_req_start, 2); - wl3501_get_from_wla(this, 0x486, &this->esbq_req_end, 2); - wl3501_get_from_wla(this, 0x488, &this->esbq_confirm_start, 2); - wl3501_get_from_wla(this, 0x48c, &this->esbq_confirm_end, 2); - wl3501_get_from_wla(this, 0x48e, &this->tx_buffer_head, 2); - wl3501_get_from_wla(this, 0x492, &this->tx_buffer_size, 2); - this->esbq_req_tail = this->esbq_req_head = this->esbq_req_start; - this->esbq_req_end += this->esbq_req_start; - this->esbq_confirm = this->esbq_confirm_start; - this->esbq_confirm_end += this->esbq_confirm_start; - /* Initial Tx Buffer */ - this->tx_buffer_cnt = 1; - ptr = this->tx_buffer_head; - next = ptr + WL3501_BLKSZ; - while ((next - this->tx_buffer_head) < this->tx_buffer_size) { - this->tx_buffer_cnt++; - wl3501_set_to_wla(this, ptr, &next, sizeof(next)); - ptr = next; - next = ptr + WL3501_BLKSZ; - } - rc = 0; - next = 0; - wl3501_set_to_wla(this, ptr, &next, sizeof(next)); - this->tx_buffer_tail = ptr; -out: - return rc; -fail: - printk(KERN_WARNING "%s: failed!\n", __func__); - goto out; -} - -static int wl3501_close(struct net_device *dev) -{ - struct wl3501_card *this = netdev_priv(dev); - unsigned long flags; - struct pcmcia_device *link; - link = this->p_dev; - - spin_lock_irqsave(&this->lock, flags); - link->open--; - - /* Stop wl3501_hard_start_xmit() from now on */ - netif_stop_queue(dev); - wl3501_ack_interrupt(this); - - /* Mask interrupts from the SUTRO */ - wl3501_block_interrupt(this); - - printk(KERN_INFO "%s: WL3501 closed\n", dev->name); - spin_unlock_irqrestore(&this->lock, flags); - return 0; -} - -/** - * wl3501_reset - Reset the SUTRO. - * @dev: network device - * - * It is almost the same as wl3501_open(). In fact, we may just wl3501_close() - * and wl3501_open() again, but I wouldn't like to free_irq() when the driver - * is running. It seems to be dangerous. - */ -static int wl3501_reset(struct net_device *dev) -{ - struct wl3501_card *this = netdev_priv(dev); - int rc = -ENODEV; - unsigned long flags; - - spin_lock_irqsave(&this->lock, flags); - wl3501_block_interrupt(this); - - if (wl3501_init_firmware(this)) { - printk(KERN_WARNING "%s: Can't initialize Firmware!\n", - dev->name); - /* Free IRQ, and mark IRQ as unused */ - free_irq(dev->irq, dev); - goto out; - } - - /* - * Queue has to be started only when the Card is Started - */ - netif_stop_queue(dev); - this->adhoc_times = 0; - wl3501_ack_interrupt(this); - wl3501_unblock_interrupt(this); - wl3501_mgmt_scan(this, 100); - pr_debug("%s: device reset", dev->name); - rc = 0; -out: - spin_unlock_irqrestore(&this->lock, flags); - return rc; -} - -static void wl3501_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - struct net_device_stats *stats = &dev->stats; - int rc; - - stats->tx_errors++; - rc = wl3501_reset(dev); - if (rc) - printk(KERN_ERR "%s: Error %d resetting card on Tx timeout!\n", - dev->name, rc); - else { - netif_trans_update(dev); /* prevent tx timeout */ - netif_wake_queue(dev); - } -} - -/* - * Return : 0 - OK - * 1 - Could not transmit (dev_queue_xmit will queue it) - * and try to sent it later - */ -static netdev_tx_t wl3501_hard_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - int enabled, rc; - struct wl3501_card *this = netdev_priv(dev); - unsigned long flags; - - spin_lock_irqsave(&this->lock, flags); - enabled = wl3501_block_interrupt(this); - rc = wl3501_send_pkt(this, skb->data, skb->len); - if (enabled) - wl3501_unblock_interrupt(this); - if (rc) { - ++dev->stats.tx_dropped; - netif_stop_queue(dev); - } else { - ++dev->stats.tx_packets; - dev->stats.tx_bytes += skb->len; - dev_kfree_skb_irq(skb); - - if (this->tx_buffer_cnt < 2) - netif_stop_queue(dev); - } - spin_unlock_irqrestore(&this->lock, flags); - return NETDEV_TX_OK; -} - -static int wl3501_open(struct net_device *dev) -{ - int rc = -ENODEV; - struct wl3501_card *this = netdev_priv(dev); - unsigned long flags; - struct pcmcia_device *link; - link = this->p_dev; - - spin_lock_irqsave(&this->lock, flags); - if (!pcmcia_dev_present(link)) - goto out; - netif_device_attach(dev); - link->open++; - - /* Initial WL3501 firmware */ - pr_debug("%s: Initialize WL3501 firmware...", dev->name); - if (wl3501_init_firmware(this)) - goto fail; - /* Initial device variables */ - this->adhoc_times = 0; - /* Acknowledge Interrupt, for cleaning last state */ - wl3501_ack_interrupt(this); - - /* Enable interrupt from card after all */ - wl3501_unblock_interrupt(this); - wl3501_mgmt_scan(this, 100); - rc = 0; - pr_debug("%s: WL3501 opened", dev->name); - printk(KERN_INFO "%s: Card Name: %s\n" - "%s: Firmware Date: %s\n", - dev->name, this->card_name, - dev->name, this->firmware_date); -out: - spin_unlock_irqrestore(&this->lock, flags); - return rc; -fail: - printk(KERN_WARNING "%s: Can't initialize firmware!\n", dev->name); - goto out; -} - -static struct iw_statistics *wl3501_get_wireless_stats(struct net_device *dev) -{ - struct wl3501_card *this = netdev_priv(dev); - struct iw_statistics *wstats = &this->wstats; - u32 value; /* size checked: it is u32 */ - - memset(wstats, 0, sizeof(*wstats)); - wstats->status = netif_running(dev); - if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_ICV_ERROR_COUNT, - &value, sizeof(value))) - wstats->discard.code += value; - if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_UNDECRYPTABLE_COUNT, - &value, sizeof(value))) - wstats->discard.code += value; - if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_EXCLUDED_COUNT, - &value, sizeof(value))) - wstats->discard.code += value; - if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_RETRY_COUNT, - &value, sizeof(value))) - wstats->discard.retries = value; - if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_FAILED_COUNT, - &value, sizeof(value))) - wstats->discard.misc += value; - if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_RTS_FAILURE_COUNT, - &value, sizeof(value))) - wstats->discard.misc += value; - if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_ACK_FAILURE_COUNT, - &value, sizeof(value))) - wstats->discard.misc += value; - if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_FRAME_DUPLICATE_COUNT, - &value, sizeof(value))) - wstats->discard.misc += value; - return wstats; -} - -/** - * wl3501_detach - deletes a driver "instance" - * @link: FILL_IN - * - * This deletes a driver "instance". The device is de-registered with Card - * Services. If it has been released, all local data structures are freed. - * Otherwise, the structures will be freed when the device is released. - */ -static void wl3501_detach(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - /* If the device is currently configured and active, we won't actually - * delete it yet. Instead, it is marked so that when the release() - * function is called, that will trigger a proper detach(). */ - - while (link->open > 0) - wl3501_close(dev); - - netif_device_detach(dev); - wl3501_release(link); - - unregister_netdev(dev); - free_netdev(dev); -} - -static int wl3501_get_name(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - strscpy(wrqu->name, "IEEE 802.11-DS", sizeof(wrqu->name)); - return 0; -} - -static int wl3501_set_freq(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - int channel = wrqu->freq.m; - int rc = -EINVAL; - - if (iw_valid_channel(this->reg_domain, channel)) { - this->chan = channel; - rc = wl3501_reset(dev); - } - return rc; -} - -static int wl3501_get_freq(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - - wrqu->freq.m = 100000 * - ieee80211_channel_to_frequency(this->chan, NL80211_BAND_2GHZ); - wrqu->freq.e = 1; - return 0; -} - -static int wl3501_set_mode(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - int rc = -EINVAL; - - if (wrqu->mode == IW_MODE_INFRA || - wrqu->mode == IW_MODE_ADHOC || - wrqu->mode == IW_MODE_AUTO) { - struct wl3501_card *this = netdev_priv(dev); - - this->net_type = wrqu->mode; - rc = wl3501_reset(dev); - } - return rc; -} - -static int wl3501_get_mode(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - - wrqu->mode = this->net_type; - return 0; -} - -static int wl3501_get_sens(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - - wrqu->sens.value = this->rssi; - wrqu->sens.disabled = !wrqu->sens.value; - wrqu->sens.fixed = 1; - return 0; -} - -static int wl3501_get_range(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_range *range = (struct iw_range *)extra; - - /* Set the length (very important for backward compatibility) */ - wrqu->data.length = sizeof(*range); - - /* Set all the info we don't care or don't know about to zero */ - memset(range, 0, sizeof(*range)); - - /* Set the Wireless Extension versions */ - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 1; - range->throughput = 2 * 1000 * 1000; /* ~2 Mb/s */ - /* FIXME: study the code to fill in more fields... */ - return 0; -} - -static int wl3501_set_wap(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - int rc = -EINVAL; - - /* FIXME: we support other ARPHRDs...*/ - if (wrqu->ap_addr.sa_family != ARPHRD_ETHER) - goto out; - if (is_broadcast_ether_addr(wrqu->ap_addr.sa_data)) { - /* FIXME: rescan? */ - } else - memcpy(this->bssid, wrqu->ap_addr.sa_data, ETH_ALEN); - /* FIXME: rescan? deassoc & scan? */ - rc = 0; -out: - return rc; -} - -static int wl3501_get_wap(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - - wrqu->ap_addr.sa_family = ARPHRD_ETHER; - memcpy(wrqu->ap_addr.sa_data, this->bssid, ETH_ALEN); - return 0; -} - -static int wl3501_set_scan(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - /* - * FIXME: trigger scanning with a reset, yes, I'm lazy - */ - return wl3501_reset(dev); -} - -static int wl3501_get_scan(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - int i; - char *current_ev = extra; - struct iw_event iwe; - - for (i = 0; i < this->bss_cnt; ++i) { - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, this->bss_set[i].req.bssid, ETH_ALEN); - current_ev = iwe_stream_add_event(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, IW_EV_ADDR_LEN); - iwe.cmd = SIOCGIWESSID; - iwe.u.data.flags = 1; - iwe.u.data.length = this->bss_set[i].req.ssid.el.len; - current_ev = iwe_stream_add_point(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, - this->bss_set[i].req.ssid.essid); - iwe.cmd = SIOCGIWMODE; - iwe.u.mode = this->bss_set[i].req.bss_type; - current_ev = iwe_stream_add_event(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, IW_EV_UINT_LEN); - iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = this->bss_set[i].req.ds_pset.chan; - iwe.u.freq.e = 0; - current_ev = iwe_stream_add_event(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, IW_EV_FREQ_LEN); - iwe.cmd = SIOCGIWENCODE; - if (this->bss_set[i].req.cap_info & WL3501_MGMT_CAPABILITY_PRIVACY) - iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - iwe.u.data.length = 0; - current_ev = iwe_stream_add_point(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, NULL); - } - /* Length of data */ - wrqu->data.length = (current_ev - extra); - wrqu->data.flags = 0; /* FIXME: set properly these flags */ - return 0; -} - -static int wl3501_set_essid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - - if (wrqu->data.flags) { - iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID, - &this->essid.el, - extra, wrqu->data.length); - } else { /* We accept any ESSID */ - iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID, - &this->essid.el, "ANY", 3); - } - return wl3501_reset(dev); -} - -static int wl3501_get_essid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - unsigned long flags; - - spin_lock_irqsave(&this->lock, flags); - wrqu->essid.flags = 1; - wrqu->essid.length = this->essid.el.len; - memcpy(extra, this->essid.essid, this->essid.el.len); - spin_unlock_irqrestore(&this->lock, flags); - return 0; -} - -static int wl3501_set_nick(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - - if (wrqu->data.length > sizeof(this->nick)) - return -E2BIG; - strscpy(this->nick, extra, wrqu->data.length); - return 0; -} - -static int wl3501_get_nick(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - - strscpy(extra, this->nick, 32); - wrqu->data.length = strlen(extra); - return 0; -} - -static int wl3501_get_rate(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - /* - * FIXME: have to see from where to get this info, perhaps this card - * works at 1 Mbit/s too... for now leave at 2 Mbit/s that is the most - * common with the Planet Access Points. -acme - */ - wrqu->bitrate.value = 2000000; - wrqu->bitrate.fixed = 1; - return 0; -} - -static int wl3501_get_rts_threshold(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - u16 threshold; /* size checked: it is u16 */ - struct wl3501_card *this = netdev_priv(dev); - int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_RTS_THRESHOLD, - &threshold, sizeof(threshold)); - if (!rc) { - wrqu->rts.value = threshold; - wrqu->rts.disabled = threshold >= 2347; - wrqu->rts.fixed = 1; - } - return rc; -} - -static int wl3501_get_frag_threshold(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - u16 threshold; /* size checked: it is u16 */ - struct wl3501_card *this = netdev_priv(dev); - int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_FRAG_THRESHOLD, - &threshold, sizeof(threshold)); - if (!rc) { - wrqu->frag.value = threshold; - wrqu->frag.disabled = threshold >= 2346; - wrqu->frag.fixed = 1; - } - return rc; -} - -static int wl3501_get_txpow(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - u16 txpow; - struct wl3501_card *this = netdev_priv(dev); - int rc = wl3501_get_mib_value(this, - WL3501_MIB_ATTR_CURRENT_TX_PWR_LEVEL, - &txpow, sizeof(txpow)); - if (!rc) { - wrqu->txpower.value = txpow; - wrqu->txpower.disabled = 0; - /* - * From the MIB values I think this can be configurable, - * as it lists several tx power levels -acme - */ - wrqu->txpower.fixed = 0; - wrqu->txpower.flags = IW_TXPOW_MWATT; - } - return rc; -} - -static int wl3501_get_retry(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - u8 retry; /* size checked: it is u8 */ - struct wl3501_card *this = netdev_priv(dev); - int rc = wl3501_get_mib_value(this, - WL3501_MIB_ATTR_LONG_RETRY_LIMIT, - &retry, sizeof(retry)); - if (rc) - goto out; - if (wrqu->retry.flags & IW_RETRY_LONG) { - wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG; - goto set_value; - } - rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_SHORT_RETRY_LIMIT, - &retry, sizeof(retry)); - if (rc) - goto out; - wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_SHORT; -set_value: - wrqu->retry.value = retry; - wrqu->retry.disabled = 0; -out: - return rc; -} - -static int wl3501_get_encode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - u8 implemented, restricted, keys[100], len_keys, tocopy; - struct wl3501_card *this = netdev_priv(dev); - int rc = wl3501_get_mib_value(this, - WL3501_MIB_ATTR_PRIV_OPT_IMPLEMENTED, - &implemented, sizeof(implemented)); - if (rc) - goto out; - if (!implemented) { - wrqu->encoding.flags = IW_ENCODE_DISABLED; - goto out; - } - rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_EXCLUDE_UNENCRYPTED, - &restricted, sizeof(restricted)); - if (rc) - goto out; - wrqu->encoding.flags = restricted ? IW_ENCODE_RESTRICTED : - IW_ENCODE_OPEN; - rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_KEY_MAPPINGS_LEN, - &len_keys, sizeof(len_keys)); - if (rc) - goto out; - rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_KEY_MAPPINGS, - keys, len_keys); - if (rc) - goto out; - tocopy = min_t(u16, len_keys, wrqu->encoding.length); - tocopy = min_t(u8, tocopy, 100); - wrqu->encoding.length = tocopy; - memcpy(extra, keys, tocopy); -out: - return rc; -} - -static int wl3501_get_power(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - u8 pwr_state; - struct wl3501_card *this = netdev_priv(dev); - int rc = wl3501_get_mib_value(this, - WL3501_MIB_ATTR_CURRENT_PWR_STATE, - &pwr_state, sizeof(pwr_state)); - if (rc) - goto out; - wrqu->power.disabled = !pwr_state; - wrqu->power.flags = IW_POWER_ON; -out: - return rc; -} - -static const iw_handler wl3501_handler[] = { - IW_HANDLER(SIOCGIWNAME, wl3501_get_name), - IW_HANDLER(SIOCSIWFREQ, wl3501_set_freq), - IW_HANDLER(SIOCGIWFREQ, wl3501_get_freq), - IW_HANDLER(SIOCSIWMODE, wl3501_set_mode), - IW_HANDLER(SIOCGIWMODE, wl3501_get_mode), - IW_HANDLER(SIOCGIWSENS, wl3501_get_sens), - IW_HANDLER(SIOCGIWRANGE, wl3501_get_range), - IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy), - IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy), - IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy), - IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy), - IW_HANDLER(SIOCSIWAP, wl3501_set_wap), - IW_HANDLER(SIOCGIWAP, wl3501_get_wap), - IW_HANDLER(SIOCSIWSCAN, wl3501_set_scan), - IW_HANDLER(SIOCGIWSCAN, wl3501_get_scan), - IW_HANDLER(SIOCSIWESSID, wl3501_set_essid), - IW_HANDLER(SIOCGIWESSID, wl3501_get_essid), - IW_HANDLER(SIOCSIWNICKN, wl3501_set_nick), - IW_HANDLER(SIOCGIWNICKN, wl3501_get_nick), - IW_HANDLER(SIOCGIWRATE, wl3501_get_rate), - IW_HANDLER(SIOCGIWRTS, wl3501_get_rts_threshold), - IW_HANDLER(SIOCGIWFRAG, wl3501_get_frag_threshold), - IW_HANDLER(SIOCGIWTXPOW, wl3501_get_txpow), - IW_HANDLER(SIOCGIWRETRY, wl3501_get_retry), - IW_HANDLER(SIOCGIWENCODE, wl3501_get_encode), - IW_HANDLER(SIOCGIWPOWER, wl3501_get_power), -}; - -static const struct iw_handler_def wl3501_handler_def = { - .num_standard = ARRAY_SIZE(wl3501_handler), - .standard = (iw_handler *)wl3501_handler, - .get_wireless_stats = wl3501_get_wireless_stats, -}; - -static const struct net_device_ops wl3501_netdev_ops = { - .ndo_open = wl3501_open, - .ndo_stop = wl3501_close, - .ndo_start_xmit = wl3501_hard_start_xmit, - .ndo_tx_timeout = wl3501_tx_timeout, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -static int wl3501_probe(struct pcmcia_device *p_dev) -{ - struct net_device *dev; - struct wl3501_card *this; - int ret; - - /* The io structure describes IO port mapping */ - p_dev->resource[0]->end = 16; - p_dev->resource[0]->flags = IO_DATA_PATH_WIDTH_8; - - /* General socket configuration */ - p_dev->config_flags = CONF_ENABLE_IRQ; - p_dev->config_index = 1; - - dev = alloc_etherdev(sizeof(struct wl3501_card)); - if (!dev) - return -ENOMEM; - - dev->netdev_ops = &wl3501_netdev_ops; - dev->watchdog_timeo = 5 * HZ; - - this = netdev_priv(dev); - this->wireless_data.spy_data = &this->spy_data; - this->p_dev = p_dev; - dev->wireless_data = &this->wireless_data; - dev->wireless_handlers = &wl3501_handler_def; - netif_stop_queue(dev); - p_dev->priv = dev; - - ret = wl3501_config(p_dev); - if (ret) - goto out_free_etherdev; - - return 0; - -out_free_etherdev: - free_netdev(dev); - return ret; -} - -static int wl3501_config(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - int i = 0, j, ret; - struct wl3501_card *this; - - /* Try allocating IO ports. This tries a few fixed addresses. If you - * want, you can also read the card's config table to pick addresses -- - * see the serial driver for an example. */ - link->io_lines = 5; - - for (j = 0x280; j < 0x400; j += 0x20) { - /* The '^0x300' is so that we probe 0x300-0x3ff first, then - * 0x200-0x2ff, and so on, because this seems safer */ - link->resource[0]->start = j; - link->resource[1]->start = link->resource[0]->start + 0x10; - i = pcmcia_request_io(link); - if (i == 0) - break; - } - if (i != 0) - goto failed; - - /* Now allocate an interrupt line. Note that this does not actually - * assign a handler to the interrupt. */ - - ret = pcmcia_request_irq(link, wl3501_interrupt); - if (ret) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - dev->irq = link->irq; - dev->base_addr = link->resource[0]->start; - SET_NETDEV_DEV(dev, &link->dev); - if (register_netdev(dev)) { - printk(KERN_NOTICE "wl3501_cs: register_netdev() failed\n"); - goto failed; - } - - this = netdev_priv(dev); - - this->base_addr = dev->base_addr; - - if (!wl3501_get_flash_mac_addr(this)) { - printk(KERN_WARNING "%s: Can't read MAC addr in flash ROM?\n", - dev->name); - unregister_netdev(dev); - goto failed; - } - - eth_hw_addr_set(dev, this->mac_addr); - - /* print probe information */ - printk(KERN_INFO "%s: wl3501 @ 0x%3.3x, IRQ %d, " - "MAC addr in flash ROM:%pM\n", - dev->name, this->base_addr, (int)dev->irq, - dev->dev_addr); - /* - * Initialize card parameters - added by jss - */ - this->net_type = IW_MODE_INFRA; - this->bss_cnt = 0; - this->join_sta_bss = 0; - this->adhoc_times = 0; - iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID, &this->essid.el, - "ANY", 3); - this->card_name[0] = '\0'; - this->firmware_date[0] = '\0'; - this->rssi = 255; - this->chan = iw_default_channel(this->reg_domain); - strscpy(this->nick, "Planet WL3501", sizeof(this->nick)); - spin_lock_init(&this->lock); - init_waitqueue_head(&this->wait); - netif_start_queue(dev); - return 0; - -failed: - wl3501_release(link); - return -ENODEV; -} - -static void wl3501_release(struct pcmcia_device *link) -{ - pcmcia_disable_device(link); -} - -static int wl3501_suspend(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - wl3501_pwr_mgmt(netdev_priv(dev), WL3501_SUSPEND); - if (link->open) - netif_device_detach(dev); - - return 0; -} - -static int wl3501_resume(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - wl3501_pwr_mgmt(netdev_priv(dev), WL3501_RESUME); - if (link->open) { - wl3501_reset(dev); - netif_device_attach(dev); - } - - return 0; -} - - -static const struct pcmcia_device_id wl3501_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0001), - PCMCIA_DEVICE_NULL -}; -MODULE_DEVICE_TABLE(pcmcia, wl3501_ids); - -static struct pcmcia_driver wl3501_driver = { - .owner = THIS_MODULE, - .name = "wl3501_cs", - .probe = wl3501_probe, - .remove = wl3501_detach, - .id_table = wl3501_ids, - .suspend = wl3501_suspend, - .resume = wl3501_resume, -}; -module_pcmcia_driver(wl3501_driver); - -MODULE_AUTHOR("Fox Chen , " - "Arnaldo Carvalho de Melo ," - "Gustavo Niemeyer "); -MODULE_DESCRIPTION("Planet wl3501 wireless driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/marvell/libertas/Kconfig b/drivers/net/wireless/marvell/libertas/Kconfig index 6d62ab49aa8d4..56156a021be39 100644 --- a/drivers/net/wireless/marvell/libertas/Kconfig +++ b/drivers/net/wireless/marvell/libertas/Kconfig @@ -1,9 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-only config LIBERTAS tristate "Marvell 8xxx Libertas WLAN driver support" + depends on USB || SDIO || SPI depends on CFG80211 - select WIRELESS_EXT - select WEXT_SPY select LIB80211 select FW_LOADER help @@ -15,12 +14,6 @@ config LIBERTAS_USB help A driver for Marvell Libertas 8388 USB devices. -config LIBERTAS_CS - tristate "Marvell Libertas 8385 CompactFlash 802.11b/g cards" - depends on LIBERTAS && PCMCIA && HAS_IOPORT_MAP - help - A driver for Marvell Libertas 8385 CompactFlash devices. - config LIBERTAS_SDIO tristate "Marvell Libertas 8385/8686/8688 SDIO 802.11b/g cards" depends on LIBERTAS && MMC diff --git a/drivers/net/wireless/marvell/libertas/Makefile b/drivers/net/wireless/marvell/libertas/Makefile index 41b9b440a5422..2ac04f4d61a52 100644 --- a/drivers/net/wireless/marvell/libertas/Makefile +++ b/drivers/net/wireless/marvell/libertas/Makefile @@ -17,6 +17,5 @@ libertas_spi-objs += if_spi.o obj-$(CONFIG_LIBERTAS) += libertas.o obj-$(CONFIG_LIBERTAS_USB) += usb8xxx.o -obj-$(CONFIG_LIBERTAS_CS) += libertas_cs.o obj-$(CONFIG_LIBERTAS_SDIO) += libertas_sdio.o obj-$(CONFIG_LIBERTAS_SPI) += libertas_spi.o diff --git a/drivers/net/wireless/marvell/libertas/if_cs.c b/drivers/net/wireless/marvell/libertas/if_cs.c deleted file mode 100644 index 4103f15bca6bf..0000000000000 --- a/drivers/net/wireless/marvell/libertas/if_cs.c +++ /dev/null @@ -1,957 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - - Driver for the Marvell 8385 based compact flash WLAN cards. - - (C) 2007 by Holger Schurig - - -*/ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#define DRV_NAME "libertas_cs" - -#include "decl.h" -#include "defs.h" -#include "dev.h" - - -/********************************************************************/ -/* Module stuff */ -/********************************************************************/ - -MODULE_AUTHOR("Holger Schurig "); -MODULE_DESCRIPTION("Driver for Marvell 83xx compact flash WLAN cards"); -MODULE_LICENSE("GPL"); - - - -/********************************************************************/ -/* Data structures */ -/********************************************************************/ - -struct if_cs_card { - struct pcmcia_device *p_dev; - struct lbs_private *priv; - void __iomem *iobase; - bool align_regs; - u32 model; -}; - - -enum { - MODEL_UNKNOWN = 0x00, - MODEL_8305 = 0x01, - MODEL_8381 = 0x02, - MODEL_8385 = 0x03 -}; - -static const struct lbs_fw_table fw_table[] = { - { MODEL_8305, "libertas/cf8305.bin", NULL }, - { MODEL_8305, "libertas_cs_helper.fw", NULL }, - { MODEL_8381, "libertas/cf8381_helper.bin", "libertas/cf8381.bin" }, - { MODEL_8381, "libertas_cs_helper.fw", "libertas_cs.fw" }, - { MODEL_8385, "libertas/cf8385_helper.bin", "libertas/cf8385.bin" }, - { MODEL_8385, "libertas_cs_helper.fw", "libertas_cs.fw" }, - { 0, NULL, NULL } -}; -MODULE_FIRMWARE("libertas/cf8305.bin"); -MODULE_FIRMWARE("libertas/cf8381_helper.bin"); -MODULE_FIRMWARE("libertas/cf8381.bin"); -MODULE_FIRMWARE("libertas/cf8385_helper.bin"); -MODULE_FIRMWARE("libertas/cf8385.bin"); -MODULE_FIRMWARE("libertas_cs_helper.fw"); -MODULE_FIRMWARE("libertas_cs.fw"); - - -/********************************************************************/ -/* Hardware access */ -/********************************************************************/ - -/* This define enables wrapper functions which allow you - to dump all register accesses. You normally won't this, - except for development */ -/* #define DEBUG_IO */ - -#ifdef DEBUG_IO -static int debug_output = 0; -#else -/* This way the compiler optimizes the printk's away */ -#define debug_output 0 -#endif - -static inline unsigned int if_cs_read8(struct if_cs_card *card, uint reg) -{ - unsigned int val = ioread8(card->iobase + reg); - if (debug_output) - printk(KERN_INFO "inb %08x<%02x\n", reg, val); - return val; -} -static inline unsigned int if_cs_read16(struct if_cs_card *card, uint reg) -{ - unsigned int val = ioread16(card->iobase + reg); - if (debug_output) - printk(KERN_INFO "inw %08x<%04x\n", reg, val); - return val; -} -static inline void if_cs_read16_rep( - struct if_cs_card *card, - uint reg, - void *buf, - unsigned long count) -{ - if (debug_output) - printk(KERN_INFO "insw %08x<(0x%lx words)\n", - reg, count); - ioread16_rep(card->iobase + reg, buf, count); -} - -static inline void if_cs_write8(struct if_cs_card *card, uint reg, u8 val) -{ - if (debug_output) - printk(KERN_INFO "outb %08x>%02x\n", reg, val); - iowrite8(val, card->iobase + reg); -} - -static inline void if_cs_write16(struct if_cs_card *card, uint reg, u16 val) -{ - if (debug_output) - printk(KERN_INFO "outw %08x>%04x\n", reg, val); - iowrite16(val, card->iobase + reg); -} - -static inline void if_cs_write16_rep( - struct if_cs_card *card, - uint reg, - const void *buf, - unsigned long count) -{ - if (debug_output) - printk(KERN_INFO "outsw %08x>(0x%lx words)\n", - reg, count); - iowrite16_rep(card->iobase + reg, buf, count); -} - - -/* - * I know that polling/delaying is frowned upon. However, this procedure - * with polling is needed while downloading the firmware. At this stage, - * the hardware does unfortunately not create any interrupts. - * - * Fortunately, this function is never used once the firmware is in - * the card. :-) - * - * As a reference, see the "Firmware Specification v5.1", page 18 - * and 19. I did not follow their suggested timing to the word, - * but this works nice & fast anyway. - */ -static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 reg) -{ - int i; - - for (i = 0; i < 100000; i++) { - u8 val = if_cs_read8(card, addr); - if (val == reg) - return 0; - udelay(5); - } - return -ETIME; -} - - - -/* - * First the bitmasks for the host/card interrupt/status registers: - */ -#define IF_CS_BIT_TX 0x0001 -#define IF_CS_BIT_RX 0x0002 -#define IF_CS_BIT_COMMAND 0x0004 -#define IF_CS_BIT_RESP 0x0008 -#define IF_CS_BIT_EVENT 0x0010 -#define IF_CS_BIT_MASK 0x001f - - - -/* - * It's not really clear to me what the host status register is for. It - * needs to be set almost in union with "host int cause". The following - * bits from above are used: - * - * IF_CS_BIT_TX driver downloaded a data packet - * IF_CS_BIT_RX driver got a data packet - * IF_CS_BIT_COMMAND driver downloaded a command - * IF_CS_BIT_RESP not used (has some meaning with powerdown) - * IF_CS_BIT_EVENT driver read a host event - */ -#define IF_CS_HOST_STATUS 0x00000000 - -/* - * With the host int cause register can the host (that is, Linux) cause - * an interrupt in the firmware, to tell the firmware about those events: - * - * IF_CS_BIT_TX a data packet has been downloaded - * IF_CS_BIT_RX a received data packet has retrieved - * IF_CS_BIT_COMMAND a firmware block or a command has been downloaded - * IF_CS_BIT_RESP not used (has some meaning with powerdown) - * IF_CS_BIT_EVENT a host event (link lost etc) has been retrieved - */ -#define IF_CS_HOST_INT_CAUSE 0x00000002 - -/* - * The host int mask register is used to enable/disable interrupt. However, - * I have the suspicion that disabled interrupts are lost. - */ -#define IF_CS_HOST_INT_MASK 0x00000004 - -/* - * Used to send or receive data packets: - */ -#define IF_CS_WRITE 0x00000016 -#define IF_CS_WRITE_LEN 0x00000014 -#define IF_CS_READ 0x00000010 -#define IF_CS_READ_LEN 0x00000024 - -/* - * Used to send commands (and to send firmware block) and to - * receive command responses: - */ -#define IF_CS_CMD 0x0000001A -#define IF_CS_CMD_LEN 0x00000018 -#define IF_CS_RESP 0x00000012 -#define IF_CS_RESP_LEN 0x00000030 - -/* - * The card status registers shows what the card/firmware actually - * accepts: - * - * IF_CS_BIT_TX you may send a data packet - * IF_CS_BIT_RX you may retrieve a data packet - * IF_CS_BIT_COMMAND you may send a command - * IF_CS_BIT_RESP you may retrieve a command response - * IF_CS_BIT_EVENT the card has a event for use (link lost, snr low etc) - * - * When reading this register several times, you will get back the same - * results --- with one exception: the IF_CS_BIT_EVENT clear itself - * automatically. - * - * Not that we don't rely on BIT_RX,_BIT_RESP or BIT_EVENT because - * we handle this via the card int cause register. - */ -#define IF_CS_CARD_STATUS 0x00000020 -#define IF_CS_CARD_STATUS_MASK 0x7f00 - -/* - * The card int cause register is used by the card/firmware to notify us - * about the following events: - * - * IF_CS_BIT_TX a data packet has successfully been sentx - * IF_CS_BIT_RX a data packet has been received and can be retrieved - * IF_CS_BIT_COMMAND not used - * IF_CS_BIT_RESP the firmware has a command response for us - * IF_CS_BIT_EVENT the card has a event for use (link lost, snr low etc) - */ -#define IF_CS_CARD_INT_CAUSE 0x00000022 - -/* - * This is used to for handshaking with the card's bootloader/helper image - * to synchronize downloading of firmware blocks. - */ -#define IF_CS_SQ_READ_LOW 0x00000028 -#define IF_CS_SQ_HELPER_OK 0x10 - -/* - * The scratch register tells us ... - * - * IF_CS_SCRATCH_BOOT_OK the bootloader runs - * IF_CS_SCRATCH_HELPER_OK the helper firmware already runs - */ -#define IF_CS_SCRATCH 0x0000003F -#define IF_CS_SCRATCH_BOOT_OK 0x00 -#define IF_CS_SCRATCH_HELPER_OK 0x5a - -/* - * Used to detect ancient chips: - */ -#define IF_CS_PRODUCT_ID 0x0000001C -#define IF_CS_CF8385_B1_REV 0x12 -#define IF_CS_CF8381_B3_REV 0x04 -#define IF_CS_CF8305_B1_REV 0x03 - -/* - * Used to detect other cards than CF8385 since their revisions of silicon - * doesn't match those from CF8385, eg. CF8381 B3 works with this driver. - */ -#define CF8305_MANFID 0x02db -#define CF8305_CARDID 0x8103 -#define CF8381_MANFID 0x02db -#define CF8381_CARDID 0x6064 -#define CF8385_MANFID 0x02df -#define CF8385_CARDID 0x8103 - -/* - * FIXME: just use the 'driver_info' field of 'struct pcmcia_device_id' when - * that gets fixed. Currently there's no way to access it from the probe hook. - */ -static inline u32 get_model(u16 manf_id, u16 card_id) -{ - /* NOTE: keep in sync with if_cs_ids */ - if (manf_id == CF8305_MANFID && card_id == CF8305_CARDID) - return MODEL_8305; - else if (manf_id == CF8381_MANFID && card_id == CF8381_CARDID) - return MODEL_8381; - else if (manf_id == CF8385_MANFID && card_id == CF8385_CARDID) - return MODEL_8385; - return MODEL_UNKNOWN; -} - -/********************************************************************/ -/* I/O and interrupt handling */ -/********************************************************************/ - -static inline void if_cs_enable_ints(struct if_cs_card *card) -{ - if_cs_write16(card, IF_CS_HOST_INT_MASK, 0); -} - -static inline void if_cs_disable_ints(struct if_cs_card *card) -{ - if_cs_write16(card, IF_CS_HOST_INT_MASK, IF_CS_BIT_MASK); -} - -/* - * Called from if_cs_host_to_card to send a command to the hardware - */ -static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb) -{ - struct if_cs_card *card = (struct if_cs_card *)priv->card; - int ret = -1; - int loops = 0; - - if_cs_disable_ints(card); - - /* Is hardware ready? */ - while (1) { - u16 status = if_cs_read16(card, IF_CS_CARD_STATUS); - if (status & IF_CS_BIT_COMMAND) - break; - if (++loops > 100) { - netdev_err(priv->dev, "card not ready for commands\n"); - goto done; - } - mdelay(1); - } - - if_cs_write16(card, IF_CS_CMD_LEN, nb); - - if_cs_write16_rep(card, IF_CS_CMD, buf, nb / 2); - /* Are we supposed to transfer an odd amount of bytes? */ - if (nb & 1) - if_cs_write8(card, IF_CS_CMD, buf[nb-1]); - - /* "Assert the download over interrupt command in the Host - * status register" */ - if_cs_write16(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND); - - /* "Assert the download over interrupt command in the Card - * interrupt case register" */ - if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND); - ret = 0; - -done: - if_cs_enable_ints(card); - return ret; -} - -/* - * Called from if_cs_host_to_card to send a data to the hardware - */ -static void if_cs_send_data(struct lbs_private *priv, u8 *buf, u16 nb) -{ - struct if_cs_card *card = (struct if_cs_card *)priv->card; - u16 status; - - if_cs_disable_ints(card); - - status = if_cs_read16(card, IF_CS_CARD_STATUS); - BUG_ON((status & IF_CS_BIT_TX) == 0); - - if_cs_write16(card, IF_CS_WRITE_LEN, nb); - - /* write even number of bytes, then odd byte if necessary */ - if_cs_write16_rep(card, IF_CS_WRITE, buf, nb / 2); - if (nb & 1) - if_cs_write8(card, IF_CS_WRITE, buf[nb-1]); - - if_cs_write16(card, IF_CS_HOST_STATUS, IF_CS_BIT_TX); - if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_TX); - if_cs_enable_ints(card); -} - -/* - * Get the command result out of the card. - */ -static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len) -{ - unsigned long flags; - int ret = -1; - u16 status; - - /* is hardware ready? */ - status = if_cs_read16(priv->card, IF_CS_CARD_STATUS); - if ((status & IF_CS_BIT_RESP) == 0) { - netdev_err(priv->dev, "no cmd response in card\n"); - *len = 0; - goto out; - } - - *len = if_cs_read16(priv->card, IF_CS_RESP_LEN); - if ((*len == 0) || (*len > LBS_CMD_BUFFER_SIZE)) { - netdev_err(priv->dev, - "card cmd buffer has invalid # of bytes (%d)\n", - *len); - goto out; - } - - /* read even number of bytes, then odd byte if necessary */ - if_cs_read16_rep(priv->card, IF_CS_RESP, data, *len/sizeof(u16)); - if (*len & 1) - data[*len-1] = if_cs_read8(priv->card, IF_CS_RESP); - - /* This is a workaround for a firmware that reports too much - * bytes */ - *len -= 8; - ret = 0; - - /* Clear this flag again */ - spin_lock_irqsave(&priv->driver_lock, flags); - priv->dnld_sent = DNLD_RES_RECEIVED; - spin_unlock_irqrestore(&priv->driver_lock, flags); - -out: - return ret; -} - -static struct sk_buff *if_cs_receive_data(struct lbs_private *priv) -{ - struct sk_buff *skb = NULL; - u16 len; - u8 *data; - - len = if_cs_read16(priv->card, IF_CS_READ_LEN); - if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) { - netdev_err(priv->dev, - "card data buffer has invalid # of bytes (%d)\n", - len); - priv->dev->stats.rx_dropped++; - goto dat_err; - } - - skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + 2); - if (!skb) - goto out; - skb_put(skb, len); - skb_reserve(skb, 2);/* 16 byte align */ - data = skb->data; - - /* read even number of bytes, then odd byte if necessary */ - if_cs_read16_rep(priv->card, IF_CS_READ, data, len/sizeof(u16)); - if (len & 1) - data[len-1] = if_cs_read8(priv->card, IF_CS_READ); - -dat_err: - if_cs_write16(priv->card, IF_CS_HOST_STATUS, IF_CS_BIT_RX); - if_cs_write16(priv->card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_RX); - -out: - return skb; -} - -static irqreturn_t if_cs_interrupt(int irq, void *data) -{ - struct if_cs_card *card = data; - struct lbs_private *priv = card->priv; - u16 cause; - - /* Ask card interrupt cause register if there is something for us */ - cause = if_cs_read16(card, IF_CS_CARD_INT_CAUSE); - lbs_deb_cs("cause 0x%04x\n", cause); - - if (cause == 0) { - /* Not for us */ - return IRQ_NONE; - } - - if (cause == 0xffff) { - /* Read in junk, the card has probably been removed */ - card->priv->surpriseremoved = 1; - return IRQ_HANDLED; - } - - if (cause & IF_CS_BIT_RX) { - struct sk_buff *skb; - lbs_deb_cs("rx packet\n"); - skb = if_cs_receive_data(priv); - if (skb) - lbs_process_rxed_packet(priv, skb); - } - - if (cause & IF_CS_BIT_TX) { - lbs_deb_cs("tx done\n"); - lbs_host_to_card_done(priv); - } - - if (cause & IF_CS_BIT_RESP) { - unsigned long flags; - u8 i; - - lbs_deb_cs("cmd resp\n"); - spin_lock_irqsave(&priv->driver_lock, flags); - i = (priv->resp_idx == 0) ? 1 : 0; - spin_unlock_irqrestore(&priv->driver_lock, flags); - - BUG_ON(priv->resp_len[i]); - if_cs_receive_cmdres(priv, priv->resp_buf[i], - &priv->resp_len[i]); - - spin_lock_irqsave(&priv->driver_lock, flags); - lbs_notify_command_response(priv, i); - spin_unlock_irqrestore(&priv->driver_lock, flags); - } - - if (cause & IF_CS_BIT_EVENT) { - u16 status = if_cs_read16(priv->card, IF_CS_CARD_STATUS); - if_cs_write16(priv->card, IF_CS_HOST_INT_CAUSE, - IF_CS_BIT_EVENT); - lbs_queue_event(priv, (status & IF_CS_CARD_STATUS_MASK) >> 8); - } - - /* Clear interrupt cause */ - if_cs_write16(card, IF_CS_CARD_INT_CAUSE, cause & IF_CS_BIT_MASK); - - return IRQ_HANDLED; -} - - - - -/********************************************************************/ -/* Firmware */ -/********************************************************************/ - -/* - * Tries to program the helper firmware. - * - * Return 0 on success - */ -static int if_cs_prog_helper(struct if_cs_card *card, const struct firmware *fw) -{ - int ret = 0; - int sent = 0; - u8 scratch; - - /* - * This is the only place where an unaligned register access happens on - * the CF8305 card, therefore for the sake of speed of the driver, we do - * the alignment correction here. - */ - if (card->align_regs) - scratch = if_cs_read16(card, IF_CS_SCRATCH) >> 8; - else - scratch = if_cs_read8(card, IF_CS_SCRATCH); - - /* "If the value is 0x5a, the firmware is already - * downloaded successfully" - */ - if (scratch == IF_CS_SCRATCH_HELPER_OK) - goto done; - - /* "If the value is != 00, it is invalid value of register */ - if (scratch != IF_CS_SCRATCH_BOOT_OK) { - ret = -ENODEV; - goto done; - } - - lbs_deb_cs("helper size %td\n", fw->size); - - /* "Set the 5 bytes of the helper image to 0" */ - /* Not needed, this contains an ARM branch instruction */ - - for (;;) { - /* "the number of bytes to send is 256" */ - int count = 256; - int remain = fw->size - sent; - - if (remain < count) - count = remain; - - /* - * "write the number of bytes to be sent to the I/O Command - * write length register" - */ - if_cs_write16(card, IF_CS_CMD_LEN, count); - - /* "write this to I/O Command port register as 16 bit writes */ - if (count) - if_cs_write16_rep(card, IF_CS_CMD, - &fw->data[sent], - count >> 1); - - /* - * "Assert the download over interrupt command in the Host - * status register" - */ - if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND); - - /* - * "Assert the download over interrupt command in the Card - * interrupt case register" - */ - if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND); - - /* - * "The host polls the Card Status register ... for 50 ms before - * declaring a failure" - */ - ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS, - IF_CS_BIT_COMMAND); - if (ret < 0) { - pr_err("can't download helper at 0x%x, ret %d\n", - sent, ret); - goto done; - } - - if (count == 0) - break; - - sent += count; - } - -done: - return ret; -} - - -static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw) -{ - int ret = 0; - int retry = 0; - int len = 0; - int sent; - - lbs_deb_cs("fw size %td\n", fw->size); - - ret = if_cs_poll_while_fw_download(card, IF_CS_SQ_READ_LOW, - IF_CS_SQ_HELPER_OK); - if (ret < 0) { - pr_err("helper firmware doesn't answer\n"); - goto done; - } - - for (sent = 0; sent < fw->size; sent += len) { - len = if_cs_read16(card, IF_CS_SQ_READ_LOW); - if (len & 1) { - retry++; - pr_info("odd, need to retry this firmware block\n"); - } else { - retry = 0; - } - - if (retry > 20) { - pr_err("could not download firmware\n"); - ret = -ENODEV; - goto done; - } - if (retry) { - sent -= len; - } - - - if_cs_write16(card, IF_CS_CMD_LEN, len); - - if_cs_write16_rep(card, IF_CS_CMD, - &fw->data[sent], - (len+1) >> 1); - if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND); - if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND); - - ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS, - IF_CS_BIT_COMMAND); - if (ret < 0) { - pr_err("can't download firmware at 0x%x\n", sent); - goto done; - } - } - - ret = if_cs_poll_while_fw_download(card, IF_CS_SCRATCH, 0x5a); - if (ret < 0) - pr_err("firmware download failed\n"); - -done: - return ret; -} - -static void if_cs_prog_firmware(struct lbs_private *priv, int ret, - const struct firmware *helper, - const struct firmware *mainfw) -{ - struct if_cs_card *card = priv->card; - - if (ret) { - pr_err("failed to find firmware (%d)\n", ret); - return; - } - - /* Load the firmware */ - ret = if_cs_prog_helper(card, helper); - if (ret == 0 && (card->model != MODEL_8305)) - ret = if_cs_prog_real(card, mainfw); - if (ret) - return; - - /* Now actually get the IRQ */ - ret = request_irq(card->p_dev->irq, if_cs_interrupt, - IRQF_SHARED, DRV_NAME, card); - if (ret) { - pr_err("error in request_irq\n"); - return; - } - - /* - * Clear any interrupt cause that happened while sending - * firmware/initializing card - */ - if_cs_write16(card, IF_CS_CARD_INT_CAUSE, IF_CS_BIT_MASK); - if_cs_enable_ints(card); - - /* And finally bring the card up */ - priv->fw_ready = 1; - if (lbs_start_card(priv) != 0) { - pr_err("could not activate card\n"); - free_irq(card->p_dev->irq, card); - } -} - - -/********************************************************************/ -/* Callback functions for libertas.ko */ -/********************************************************************/ - -/* Send commands or data packets to the card */ -static int if_cs_host_to_card(struct lbs_private *priv, - u8 type, - u8 *buf, - u16 nb) -{ - int ret = -1; - - switch (type) { - case MVMS_DAT: - priv->dnld_sent = DNLD_DATA_SENT; - if_cs_send_data(priv, buf, nb); - ret = 0; - break; - case MVMS_CMD: - priv->dnld_sent = DNLD_CMD_SENT; - ret = if_cs_send_cmd(priv, buf, nb); - break; - default: - netdev_err(priv->dev, "%s: unsupported type %d\n", - __func__, type); - } - - return ret; -} - - -static void if_cs_release(struct pcmcia_device *p_dev) -{ - struct if_cs_card *card = p_dev->priv; - - free_irq(p_dev->irq, card); - pcmcia_disable_device(p_dev); - if (card->iobase) - ioport_unmap(card->iobase); -} - - -static int if_cs_ioprobe(struct pcmcia_device *p_dev, void *priv_data) -{ - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - - if (p_dev->resource[1]->end) { - pr_err("wrong CIS (check number of IO windows)\n"); - return -ENODEV; - } - - /* This reserves IO space but doesn't actually enable it */ - return pcmcia_request_io(p_dev); -} - -static int if_cs_probe(struct pcmcia_device *p_dev) -{ - int ret = -ENOMEM; - unsigned int prod_id; - struct lbs_private *priv; - struct if_cs_card *card; - - card = kzalloc(sizeof(struct if_cs_card), GFP_KERNEL); - if (!card) - goto out; - - card->p_dev = p_dev; - p_dev->priv = card; - - p_dev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; - - if (pcmcia_loop_config(p_dev, if_cs_ioprobe, NULL)) { - pr_err("error in pcmcia_loop_config\n"); - goto out1; - } - - /* - * Allocate an interrupt line. Note that this does not assign - * a handler to the interrupt, unless the 'Handler' member of - * the irq structure is initialized. - */ - if (!p_dev->irq) - goto out1; - - /* Initialize io access */ - card->iobase = ioport_map(p_dev->resource[0]->start, - resource_size(p_dev->resource[0])); - if (!card->iobase) { - pr_err("error in ioport_map\n"); - ret = -EIO; - goto out1; - } - - ret = pcmcia_enable_device(p_dev); - if (ret) { - pr_err("error in pcmcia_enable_device\n"); - goto out2; - } - - /* Finally, report what we've done */ - lbs_deb_cs("irq %d, io %pR", p_dev->irq, p_dev->resource[0]); - - /* - * Most of the libertas cards can do unaligned register access, but some - * weird ones cannot. That's especially true for the CF8305 card. - */ - card->align_regs = false; - - card->model = get_model(p_dev->manf_id, p_dev->card_id); - if (card->model == MODEL_UNKNOWN) { - pr_err("unsupported manf_id 0x%04x / card_id 0x%04x\n", - p_dev->manf_id, p_dev->card_id); - ret = -ENODEV; - goto out2; - } - - /* Check if we have a current silicon */ - prod_id = if_cs_read8(card, IF_CS_PRODUCT_ID); - if (card->model == MODEL_8305) { - card->align_regs = true; - if (prod_id < IF_CS_CF8305_B1_REV) { - pr_err("8305 rev B0 and older are not supported\n"); - ret = -ENODEV; - goto out2; - } - } - - if ((card->model == MODEL_8381) && prod_id < IF_CS_CF8381_B3_REV) { - pr_err("8381 rev B2 and older are not supported\n"); - ret = -ENODEV; - goto out2; - } - - if ((card->model == MODEL_8385) && prod_id < IF_CS_CF8385_B1_REV) { - pr_err("8385 rev B0 and older are not supported\n"); - ret = -ENODEV; - goto out2; - } - - /* Make this card known to the libertas driver */ - priv = lbs_add_card(card, &p_dev->dev); - if (IS_ERR(priv)) { - ret = PTR_ERR(priv); - goto out2; - } - - /* Set up fields in lbs_private */ - card->priv = priv; - priv->card = card; - priv->hw_host_to_card = if_cs_host_to_card; - priv->enter_deep_sleep = NULL; - priv->exit_deep_sleep = NULL; - priv->reset_deep_sleep_wakeup = NULL; - - /* Get firmware */ - ret = lbs_get_firmware_async(priv, &p_dev->dev, card->model, fw_table, - if_cs_prog_firmware); - if (ret) { - pr_err("failed to find firmware (%d)\n", ret); - goto out3; - } - - goto out; - -out3: - lbs_remove_card(priv); -out2: - ioport_unmap(card->iobase); -out1: - pcmcia_disable_device(p_dev); -out: - return ret; -} - - -static void if_cs_detach(struct pcmcia_device *p_dev) -{ - struct if_cs_card *card = p_dev->priv; - - lbs_stop_card(card->priv); - lbs_remove_card(card->priv); - if_cs_disable_ints(card); - if_cs_release(p_dev); - kfree(card); -} - - - -/********************************************************************/ -/* Module initialization */ -/********************************************************************/ - -static const struct pcmcia_device_id if_cs_ids[] = { - PCMCIA_DEVICE_MANF_CARD(CF8305_MANFID, CF8305_CARDID), - PCMCIA_DEVICE_MANF_CARD(CF8381_MANFID, CF8381_CARDID), - PCMCIA_DEVICE_MANF_CARD(CF8385_MANFID, CF8385_CARDID), - /* NOTE: keep in sync with get_model() */ - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, if_cs_ids); - -static struct pcmcia_driver lbs_driver = { - .owner = THIS_MODULE, - .name = DRV_NAME, - .probe = if_cs_probe, - .remove = if_cs_detach, - .id_table = if_cs_ids, -}; -module_pcmcia_driver(lbs_driver); diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c index 3756aa247e77d..9eff29a255445 100644 --- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c +++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c @@ -1244,8 +1244,6 @@ mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *adapter, u8 *pbuf, u32 upld_len) { struct host_cmd_ds_command *cmd = (struct host_cmd_ds_command *) pbuf; - struct mwifiex_private *priv = - mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); uint16_t result = le16_to_cpu(cmd->result); uint16_t command = le16_to_cpu(cmd->command); uint16_t seq_num = le16_to_cpu(cmd->seq_num); @@ -1260,12 +1258,6 @@ mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *adapter, "cmd: CMD_RESP: 0x%x, result %d, len %d, seqno 0x%x\n", command, result, le16_to_cpu(cmd->size), seq_num); - /* Get BSS number and corresponding priv */ - priv = mwifiex_get_priv_by_id(adapter, HostCmd_GET_BSS_NO(seq_num), - HostCmd_GET_BSS_TYPE(seq_num)); - if (!priv) - priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); - /* Update sequence number */ seq_num = HostCmd_GET_SEQ_NO(seq_num); /* Clear RET_BIT from HostCmd */ diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c index da52f91693b5b..ad2509d8c99a4 100644 --- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c +++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c @@ -105,10 +105,9 @@ struct wilc_ch_list_elem { } __packed; static void cfg_scan_result(enum scan_event scan_event, - struct wilc_rcvd_net_info *info, void *user_void) + struct wilc_rcvd_net_info *info, + struct wilc_priv *priv) { - struct wilc_priv *priv = user_void; - if (!priv->cfg_scanning) return; @@ -162,9 +161,8 @@ static void cfg_scan_result(enum scan_event scan_event, } static void cfg_connect_result(enum conn_event conn_disconn_evt, u8 mac_status, - void *priv_data) + struct wilc_priv *priv) { - struct wilc_priv *priv = priv_data; struct net_device *dev = priv->dev; struct wilc_vif *vif = netdev_priv(dev); struct wilc *wl = vif->wilc; @@ -286,9 +284,8 @@ static int scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) else scan_type = WILC_FW_PASSIVE_SCAN; - ret = wilc_scan(vif, WILC_FW_USER_SCAN, scan_type, scan_ch_list, - request->n_channels, cfg_scan_result, (void *)priv, - request); + ret = wilc_scan(vif, WILC_FW_USER_SCAN, scan_type, + scan_ch_list, cfg_scan_result, request); if (ret) { priv->scan_req = NULL; @@ -412,9 +409,8 @@ static int connect(struct wiphy *wiphy, struct net_device *dev, wfi_drv->conn_info.security = security; wfi_drv->conn_info.auth_type = auth_type; - wfi_drv->conn_info.ch = ch; wfi_drv->conn_info.conn_result = cfg_connect_result; - wfi_drv->conn_info.arg = priv; + wfi_drv->conn_info.priv = priv; wfi_drv->conn_info.param = join_params; if (sme->mfp == NL80211_MFP_OPTIONAL) @@ -1094,9 +1090,8 @@ static void wilc_wfi_mgmt_tx_complete(void *priv, int status) kfree(pv_data); } -static void wilc_wfi_remain_on_channel_expired(void *data, u64 cookie) +static void wilc_wfi_remain_on_channel_expired(struct wilc_vif *vif, u64 cookie) { - struct wilc_vif *vif = data; struct wilc_priv *priv = &vif->priv; struct wilc_wfi_p2p_listen_params *params = &priv->remain_on_ch_params; @@ -1128,9 +1123,8 @@ static int remain_on_channel(struct wiphy *wiphy, if (id == 0) id = ++priv->inc_roc_cookie; - ret = wilc_remain_on_channel(vif, id, duration, chan->hw_value, - wilc_wfi_remain_on_channel_expired, - (void *)vif); + ret = wilc_remain_on_channel(vif, id, chan->hw_value, + wilc_wfi_remain_on_channel_expired); if (ret) return ret; diff --git a/drivers/net/wireless/microchip/wilc1000/hif.c b/drivers/net/wireless/microchip/wilc1000/hif.c index a28da59384813..839f142663e86 100644 --- a/drivers/net/wireless/microchip/wilc1000/hif.c +++ b/drivers/net/wireless/microchip/wilc1000/hif.c @@ -144,18 +144,19 @@ static int handle_scan_done(struct wilc_vif *vif, enum scan_event evt) scan_req = &hif_drv->usr_scan_req; if (scan_req->scan_result) { - scan_req->scan_result(evt, NULL, scan_req->arg); + scan_req->scan_result(evt, NULL, scan_req->priv); scan_req->scan_result = NULL; } return result; } -int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type, - u8 *ch_freq_list, u8 ch_list_len, +int wilc_scan(struct wilc_vif *vif, u8 scan_source, + u8 scan_type, u8 *ch_freq_list, void (*scan_result_fn)(enum scan_event, - struct wilc_rcvd_net_info *, void *), - void *user_arg, struct cfg80211_scan_request *request) + struct wilc_rcvd_net_info *, + struct wilc_priv *), + struct cfg80211_scan_request *request) { int result = 0; struct wid wid_list[WILC_SCAN_WID_LIST_SIZE]; @@ -164,6 +165,7 @@ int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type, u8 *buffer; u8 valuesize = 0; u8 *search_ssid_vals = NULL; + const u8 ch_list_len = request->n_channels; struct host_if_drv *hif_drv = vif->hif_drv; if (hif_drv->hif_state >= HOST_IF_SCANNING && @@ -249,7 +251,7 @@ int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type, index++; hif_drv->usr_scan_req.scan_result = scan_result_fn; - hif_drv->usr_scan_req.arg = user_arg; + hif_drv->usr_scan_req.priv = &vif->priv; result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, index); if (result) { @@ -348,7 +350,7 @@ static void handle_connect_timeout(struct work_struct *work) if (hif_drv->conn_info.conn_result) { hif_drv->conn_info.conn_result(CONN_DISCONN_EVENT_CONN_RESP, WILC_MAC_STATUS_DISCONNECTED, - hif_drv->conn_info.arg); + hif_drv->conn_info.priv); } else { netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__); @@ -371,8 +373,9 @@ static void handle_connect_timeout(struct work_struct *work) kfree(msg); } -void *wilc_parse_join_bss_param(struct cfg80211_bss *bss, - struct cfg80211_crypto_settings *crypto) +struct wilc_join_bss_param * +wilc_parse_join_bss_param(struct cfg80211_bss *bss, + struct cfg80211_crypto_settings *crypto) { struct wilc_join_bss_param *param; struct ieee80211_p2p_noa_attr noa_attr; @@ -545,7 +548,7 @@ static void handle_rcvd_ntwrk_info(struct work_struct *work) if (scan_req->scan_result) scan_req->scan_result(SCAN_EVENT_NETWORK_FOUND, rcvd_info, - scan_req->arg); + scan_req->priv); done: kfree(rcvd_info->mgmt); @@ -627,7 +630,7 @@ static inline void host_int_parse_assoc_resp_info(struct wilc_vif *vif, del_timer(&hif_drv->connect_timer); conn_info->conn_result(CONN_DISCONN_EVENT_CONN_RESP, mac_status, - hif_drv->conn_info.arg); + hif_drv->conn_info.priv); if (mac_status == WILC_MAC_STATUS_CONNECTED && conn_info->status == WLAN_STATUS_SUCCESS) { @@ -657,7 +660,7 @@ void wilc_handle_disconnect(struct wilc_vif *vif) if (hif_drv->conn_info.conn_result) hif_drv->conn_info.conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, - 0, hif_drv->conn_info.arg); + 0, hif_drv->conn_info.priv); eth_zero_addr(hif_drv->assoc_bssid); @@ -729,7 +732,7 @@ int wilc_disconnect(struct wilc_vif *vif) if (scan_req->scan_result) { del_timer(&hif_drv->scan_timer); - scan_req->scan_result(SCAN_EVENT_ABORTED, NULL, scan_req->arg); + scan_req->scan_result(SCAN_EVENT_ABORTED, NULL, scan_req->priv); scan_req->scan_result = NULL; } @@ -739,7 +742,7 @@ int wilc_disconnect(struct wilc_vif *vif) del_timer(&hif_drv->connect_timer); conn_info->conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, 0, - conn_info->arg); + conn_info->priv); } else { netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__); } @@ -878,7 +881,7 @@ static int handle_remain_on_chan(struct wilc_vif *vif, if (result) return -EBUSY; - hif_drv->remain_on_ch.arg = hif_remain_ch->arg; + hif_drv->remain_on_ch.vif = hif_remain_ch->vif; hif_drv->remain_on_ch.expired = hif_remain_ch->expired; hif_drv->remain_on_ch.ch = hif_remain_ch->ch; hif_drv->remain_on_ch.cookie = hif_remain_ch->cookie; @@ -915,7 +918,7 @@ static int wilc_handle_roc_expired(struct wilc_vif *vif, u64 cookie) } if (hif_drv->remain_on_ch.expired) { - hif_drv->remain_on_ch.expired(hif_drv->remain_on_ch.arg, + hif_drv->remain_on_ch.expired(hif_drv->remain_on_ch.vif, cookie); } } else { @@ -1538,7 +1541,7 @@ int wilc_deinit(struct wilc_vif *vif) if (hif_drv->usr_scan_req.scan_result) { hif_drv->usr_scan_req.scan_result(SCAN_EVENT_ABORTED, NULL, - hif_drv->usr_scan_req.arg); + hif_drv->usr_scan_req.priv); hif_drv->usr_scan_req.scan_result = NULL; } @@ -1669,18 +1672,15 @@ void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length) } } -int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie, - u32 duration, u16 chan, - void (*expired)(void *, u64), - void *user_arg) +int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie, u16 chan, + void (*expired)(struct wilc_vif *, u64)) { struct wilc_remain_ch roc; int result; roc.ch = chan; roc.expired = expired; - roc.arg = user_arg; - roc.duration = duration; + roc.vif = vif; roc.cookie = cookie; result = handle_remain_on_chan(vif, &roc); if (result) diff --git a/drivers/net/wireless/microchip/wilc1000/hif.h b/drivers/net/wireless/microchip/wilc1000/hif.h index 8e386db72e458..0d380586b1d9c 100644 --- a/drivers/net/wireless/microchip/wilc1000/hif.h +++ b/drivers/net/wireless/microchip/wilc1000/hif.h @@ -95,34 +95,37 @@ struct wilc_rcvd_net_info { struct ieee80211_mgmt *mgmt; }; +struct wilc_priv; struct wilc_user_scan_req { void (*scan_result)(enum scan_event evt, - struct wilc_rcvd_net_info *info, void *priv); - void *arg; + struct wilc_rcvd_net_info *info, + struct wilc_priv *priv); + struct wilc_priv *priv; u32 ch_cnt; }; +struct wilc_join_bss_param; struct wilc_conn_info { u8 bssid[ETH_ALEN]; u8 security; enum authtype auth_type; enum mfptype mfp_type; - u8 ch; u8 *req_ies; size_t req_ies_len; u8 *resp_ies; u16 resp_ies_len; u16 status; - void (*conn_result)(enum conn_event evt, u8 status, void *priv_data); - void *arg; - void *param; + void (*conn_result)(enum conn_event evt, u8 status, + struct wilc_priv *priv); + struct wilc_priv *priv; + struct wilc_join_bss_param *param; }; +struct wilc_vif; struct wilc_remain_ch { u16 ch; - u32 duration; - void (*expired)(void *priv, u64 cookie); - void *arg; + void (*expired)(struct wilc_vif *vif, u64 cookie); + struct wilc_vif *vif; u64 cookie; }; @@ -150,7 +153,6 @@ struct host_if_drv { u8 assoc_resp[WILC_MAX_ASSOC_RESP_FRAME_SIZE]; }; -struct wilc_vif; int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len, const u8 *mac_addr, const u8 *rx_mic, const u8 *tx_mic, u8 mode, u8 cipher_mode, u8 index); @@ -171,11 +173,12 @@ int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ies, int wilc_disconnect(struct wilc_vif *vif); int wilc_set_mac_chnl_num(struct wilc_vif *vif, u8 channel); int wilc_get_rssi(struct wilc_vif *vif, s8 *rssi_level); -int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type, - u8 *ch_freq_list, u8 ch_list_len, +int wilc_scan(struct wilc_vif *vif, u8 scan_source, + u8 scan_type, u8 *ch_freq_list, void (*scan_result_fn)(enum scan_event, - struct wilc_rcvd_net_info *, void *), - void *user_arg, struct cfg80211_scan_request *request); + struct wilc_rcvd_net_info *, + struct wilc_priv *), + struct cfg80211_scan_request *request); int wilc_hif_set_cfg(struct wilc_vif *vif, struct cfg_param_attr *cfg_param); int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler); @@ -192,10 +195,8 @@ int wilc_edit_station(struct wilc_vif *vif, const u8 *mac, int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout); int wilc_setup_multicast_filter(struct wilc_vif *vif, u32 enabled, u32 count, u8 *mc_list); -int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie, - u32 duration, u16 chan, - void (*expired)(void *, u64), - void *user_arg); +int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie, u16 chan, + void (*expired)(struct wilc_vif *, u64)); int wilc_listen_state_expired(struct wilc_vif *vif, u64 cookie); void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg); int wilc_set_operation_mode(struct wilc_vif *vif, int index, u8 mode, @@ -210,8 +211,9 @@ int wilc_set_external_auth_param(struct wilc_vif *vif, void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length); void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length); void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length); -void *wilc_parse_join_bss_param(struct cfg80211_bss *bss, - struct cfg80211_crypto_settings *crypto); +struct wilc_join_bss_param * +wilc_parse_join_bss_param(struct cfg80211_bss *bss, + struct cfg80211_crypto_settings *crypto); int wilc_set_default_mgmt_key_index(struct wilc_vif *vif, u8 index); void wilc_handle_disconnect(struct wilc_vif *vif); diff --git a/drivers/net/wireless/microchip/wilc1000/sdio.c b/drivers/net/wireless/microchip/wilc1000/sdio.c index 87948ba69a222..0d13e3e46e98e 100644 --- a/drivers/net/wireless/microchip/wilc1000/sdio.c +++ b/drivers/net/wireless/microchip/wilc1000/sdio.c @@ -106,9 +106,10 @@ static int wilc_sdio_cmd53(struct wilc *wilc, struct sdio_cmd53 *cmd) size = cmd->count; if (cmd->use_global_buf) { - if (size > sizeof(u32)) - return -EINVAL; - + if (size > sizeof(u32)) { + ret = -EINVAL; + goto out; + } buf = sdio_priv->cmd53_buf; } @@ -123,7 +124,7 @@ static int wilc_sdio_cmd53(struct wilc *wilc, struct sdio_cmd53 *cmd) if (cmd->use_global_buf) memcpy(cmd->buffer, buf, size); } - +out: sdio_release_host(func); if (ret) diff --git a/drivers/net/wireless/purelifi/plfxlc/usb.c b/drivers/net/wireless/purelifi/plfxlc/usb.c index 76d0a778636a4..311676c1ece0a 100644 --- a/drivers/net/wireless/purelifi/plfxlc/usb.c +++ b/drivers/net/wireless/purelifi/plfxlc/usb.c @@ -493,9 +493,12 @@ int plfxlc_usb_wreq_async(struct plfxlc_usb *usb, const u8 *buffer, void *context) { struct usb_device *udev = interface_to_usbdev(usb->ez_usb); - struct urb *urb = usb_alloc_urb(0, GFP_ATOMIC); + struct urb *urb; int r; + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) + return -ENOMEM; usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_DATA_OUT), (void *)buffer, buffer_len, complete_fn, context); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800.h b/drivers/net/wireless/ralink/rt2x00/rt2800.h index 48521e45577de..8930589b4967d 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2800.h @@ -3194,4 +3194,8 @@ enum rt2800_eeprom_word { */ #define BCN_TBTT_OFFSET 64 +/* Watchdog type mask */ +#define RT2800_WATCHDOG_HANG BIT(0) +#define RT2800_WATCHDOG_DMA_BUSY BIT(1) + #endif /* RT2800_H */ diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index ee880f749b3c6..84b218adbaaf1 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -30,9 +30,10 @@ #include "rt2800lib.h" #include "rt2800.h" -static bool modparam_watchdog; -module_param_named(watchdog, modparam_watchdog, bool, S_IRUGO); -MODULE_PARM_DESC(watchdog, "Enable watchdog to detect tx/rx hangs and reset hardware if detected"); +static unsigned int modparam_watchdog = RT2800_WATCHDOG_DMA_BUSY; +module_param_named(watchdog, modparam_watchdog, uint, 0444); +MODULE_PARM_DESC(watchdog, "Enable watchdog to recover tx/rx hangs.\n" + "\t\t(0=disabled, 1=hang watchdog, 2=DMA watchdog(default), 3=both)"); /* * Register access. @@ -1261,15 +1262,12 @@ static void rt2800_update_survey(struct rt2x00_dev *rt2x00dev) chan_survey->time_ext_busy += rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC); } -void rt2800_watchdog(struct rt2x00_dev *rt2x00dev) +static bool rt2800_watchdog_hung(struct rt2x00_dev *rt2x00dev) { struct data_queue *queue; bool hung_tx = false; bool hung_rx = false; - if (test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags)) - return; - rt2800_update_survey(rt2x00dev); queue_for_each(rt2x00dev, queue) { @@ -1297,18 +1295,72 @@ void rt2800_watchdog(struct rt2x00_dev *rt2x00dev) } } + if (!hung_tx && !hung_rx) + return false; + if (hung_tx) rt2x00_warn(rt2x00dev, "Watchdog TX hung detected\n"); if (hung_rx) rt2x00_warn(rt2x00dev, "Watchdog RX hung detected\n"); - if (hung_tx || hung_rx) { - queue_for_each(rt2x00dev, queue) - queue->wd_count = 0; + queue_for_each(rt2x00dev, queue) + queue->wd_count = 0; + + return true; +} + +static bool rt2800_watchdog_dma_busy(struct rt2x00_dev *rt2x00dev) +{ + bool busy_rx, busy_tx; + u32 reg_cfg = rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG); + u32 reg_int = rt2800_register_read(rt2x00dev, INT_SOURCE_CSR); + + if (rt2x00_get_field32(reg_cfg, WPDMA_GLO_CFG_RX_DMA_BUSY) && + rt2x00_get_field32(reg_int, INT_SOURCE_CSR_RX_COHERENT)) + rt2x00dev->rxdma_busy++; + else + rt2x00dev->rxdma_busy = 0; + + if (rt2x00_get_field32(reg_cfg, WPDMA_GLO_CFG_TX_DMA_BUSY) && + rt2x00_get_field32(reg_int, INT_SOURCE_CSR_TX_COHERENT)) + rt2x00dev->txdma_busy++; + else + rt2x00dev->txdma_busy = 0; + + busy_rx = rt2x00dev->rxdma_busy > 30 ? true : false; + busy_tx = rt2x00dev->txdma_busy > 30 ? true : false; + + if (!busy_rx && !busy_tx) + return false; + + if (busy_rx) + rt2x00_warn(rt2x00dev, "Watchdog RX DMA busy detected\n"); + + if (busy_tx) + rt2x00_warn(rt2x00dev, "Watchdog TX DMA busy detected\n"); + + rt2x00dev->rxdma_busy = 0; + rt2x00dev->txdma_busy = 0; + + return true; +} + +void rt2800_watchdog(struct rt2x00_dev *rt2x00dev) +{ + bool reset = false; + + if (test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags)) + return; + + if (modparam_watchdog & RT2800_WATCHDOG_DMA_BUSY) + reset = rt2800_watchdog_dma_busy(rt2x00dev); + if (modparam_watchdog & RT2800_WATCHDOG_HANG) + reset = rt2800_watchdog_hung(rt2x00dev) || reset; + + if (reset) ieee80211_restart_hw(rt2x00dev->hw); - } } EXPORT_SYMBOL_GPL(rt2800_watchdog); @@ -6048,7 +6100,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_MM40, 0); rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_GF20, 1); rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_GF40, 0); - rt2x00_set_field32(®, CCK_PROT_CFG_RTS_TH_EN, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_RTS_TH_EN, 0); rt2800_register_write(rt2x00dev, CCK_PROT_CFG, reg); reg = rt2800_register_read(rt2x00dev, OFDM_PROT_CFG); @@ -6061,7 +6113,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_MM40, 0); rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_GF20, 1); rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_GF40, 0); - rt2x00_set_field32(®, OFDM_PROT_CFG_RTS_TH_EN, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_RTS_TH_EN, 0); rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg); reg = rt2800_register_read(rt2x00dev, MM20_PROT_CFG); @@ -8659,7 +8711,7 @@ static void rt2800_rxdcoc_calibration(struct rt2x00_dev *rt2x00dev) rt2800_rfcsr_write_bank(rt2x00dev, 5, 4, saverfb5r4); rt2800_rfcsr_write_bank(rt2x00dev, 7, 4, saverfb7r4); - rt2800_bbp_write(rt2x00dev, 158, 141); + rt2800_bbp_write(rt2x00dev, 158, 140); bbpreg = rt2800_bbp_read(rt2x00dev, 159); bbpreg = bbpreg & (~0x40); rt2800_bbp_write(rt2x00dev, 159, bbpreg); @@ -12013,6 +12065,9 @@ int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev) __set_bit(REQUIRE_TASKLET_CONTEXT, &rt2x00dev->cap_flags); } + /* USB NICs don't support DMA watchdog as INT_SOURCE_CSR is invalid */ + if (rt2x00_is_usb(rt2x00dev)) + modparam_watchdog &= ~RT2800_WATCHDOG_DMA_BUSY; if (modparam_watchdog) { __set_bit(CAPABILITY_RESTART_HW, &rt2x00dev->cap_flags); rt2x00dev->link.watchdog_interval = msecs_to_jiffies(100); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h index aaaf993319672..62fed38f41c08 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h @@ -926,6 +926,9 @@ struct rt2x00_dev { */ u16 beacon_int; + /* Rx/Tx DMA busy watchdog counter */ + u16 rxdma_busy, txdma_busy; + /** * Timestamp of last received beacon */ diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c index c88ce446e1175..9e7d9dbe954cf 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c @@ -101,6 +101,7 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev) rt2x00link_stop_tuner(rt2x00dev); rt2x00queue_stop_queues(rt2x00dev); rt2x00queue_flush_queues(rt2x00dev, true); + rt2x00queue_stop_queue(rt2x00dev->bcn); /* * Disable radio. @@ -1286,6 +1287,7 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev) rt2x00dev->intf_ap_count = 0; rt2x00dev->intf_sta_count = 0; rt2x00dev->intf_associated = 0; + rt2x00dev->intf_beaconing = 0; /* Enable the radio */ retval = rt2x00lib_enable_radio(rt2x00dev); @@ -1312,6 +1314,7 @@ void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev) rt2x00dev->intf_ap_count = 0; rt2x00dev->intf_sta_count = 0; rt2x00dev->intf_associated = 0; + rt2x00dev->intf_beaconing = 0; } static inline void rt2x00lib_set_if_combinations(struct rt2x00_dev *rt2x00dev) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c index 4202c65177839..75fda72c14ca9 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c @@ -598,6 +598,17 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, */ if (changes & BSS_CHANGED_BEACON_ENABLED) { mutex_lock(&intf->beacon_skb_mutex); + + /* + * Clear the 'enable_beacon' flag and clear beacon because + * the beacon queue has been stopped after hardware reset. + */ + if (test_bit(DEVICE_STATE_RESET, &rt2x00dev->flags) && + intf->enable_beacon) { + intf->enable_beacon = false; + rt2x00queue_clear_beacon(rt2x00dev, vif); + } + if (!bss_conf->enable_beacon && intf->enable_beacon) { rt2x00dev->intf_beaconing--; intf->enable_beacon = false; diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c index 7ce37fb4fdbf1..1a8d715b7c070 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.c +++ b/drivers/net/wireless/realtek/rtlwifi/base.c @@ -1402,10 +1402,6 @@ bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) sta_entry = (struct rtl_sta_info *)sta->drv_priv; - if (!sta_entry) { - rcu_read_unlock(); - return true; - } capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); tid = (capab & @@ -1760,8 +1756,6 @@ int rtl_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return -EINVAL; sta_entry = (struct rtl_sta_info *)sta->drv_priv; - if (!sta_entry) - return -ENXIO; tid_data = &sta_entry->tids[tid]; rtl_dbg(rtlpriv, COMP_SEND, DBG_DMESG, @@ -1818,8 +1812,6 @@ int rtl_rx_agg_start(struct ieee80211_hw *hw, } sta_entry = (struct rtl_sta_info *)sta->drv_priv; - if (!sta_entry) - return -ENXIO; tid_data = &sta_entry->tids[tid]; rtl_dbg(rtlpriv, COMP_RECV, DBG_DMESG, diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index 9886e719739be..b163a069660b8 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -70,7 +70,6 @@ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw) ppsc->support_aspm = false; /*Update PCI ASPM setting */ - ppsc->const_amdpci_aspm = rtlpci->const_amdpci_aspm; switch (rtlpci->const_pci_aspm) { case 0: /*No ASPM */ diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.h b/drivers/net/wireless/realtek/rtlwifi/pci.h index 866861626a0a1..4725d43609fd2 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.h +++ b/drivers/net/wireless/realtek/rtlwifi/pci.h @@ -195,7 +195,6 @@ struct rtl_pci { u32 reg_bcn_ctrl_val; /*ASPM*/ u8 const_pci_aspm; - u8 const_amdpci_aspm; u8 const_hwsw_rfoff_d3; u8 const_support_pciaspm; /*pci-e bridge */ diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c index b77937fe24483..37bb59fa8bfa0 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c @@ -21,9 +21,6 @@ static void rtl88e_init_aspm_vars(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - /*close ASPM for AMD defaultly */ - rtlpci->const_amdpci_aspm = 0; - /* ASPM PS mode. * 0 - Disable ASPM, * 1 - Enable ASPM without Clock Req, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c index 3d29c8dbb2559..d448efe2c2298 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c @@ -1487,12 +1487,8 @@ EXPORT_SYMBOL(rtl92c_phy_lc_calibrate); void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, s8 delta) { - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_phy *rtlphy = &(rtlpriv->phy); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - if (rtlphy->apk_done) - return; if (IS_92C_SERIAL(rtlhal->version)) _rtl92c_phy_ap_calibrate(hw, delta, true); else diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c index e452275d87894..e20f2bec45c49 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c @@ -24,9 +24,6 @@ static void rtl92c_init_aspm_vars(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - /*close ASPM for AMD defaultly */ - rtlpci->const_amdpci_aspm = 0; - /* * ASPM PS mode. * 0 - Disable ASPM, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c index 11f319c97124a..afd685ed460a3 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c @@ -21,9 +21,6 @@ static void rtl92d_init_aspm_vars(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - /*close ASPM for AMD defaultly */ - rtlpci->const_amdpci_aspm = 0; - /* * ASPM PS mode. * 0 - Disable ASPM, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c index 5a828a934fe9b..17486e3f322c7 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c @@ -432,10 +432,8 @@ static void rtl92ee_dm_check_rssi_monitor(struct ieee80211_hw *hw) static void rtl92ee_dm_init_primary_cca_check(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_hal *rtlhal = rtl_hal(rtlpriv); struct dynamic_primary_cca *primarycca = &rtlpriv->primarycca; - rtlhal->rts_en = 0; primarycca->dup_rts_flag = 0; primarycca->intf_flag = 0; primarycca->intf_type = 0; @@ -562,7 +560,7 @@ static void rtl92ee_dm_write_dynamic_cca(struct ieee80211_hw *hw, primarycca->mf_state = cur_mf_state; } -static void rtl92ee_dm_dynamic_primary_cca_ckeck(struct ieee80211_hw *hw) +static void rtl92ee_dm_dynamic_primary_cca_check(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct false_alarm_statistics *falsealm_cnt = &rtlpriv->falsealm_cnt; @@ -615,13 +613,11 @@ static void rtl92ee_dm_dynamic_primary_cca_ckeck(struct ieee80211_hw *hw) rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state); primarycca->pricca_flag = 1; primarycca->dup_rts_flag = 1; - rtlpriv->rtlhal.rts_en = 1; } else { primarycca->intf_type = 0; primarycca->intf_flag = 0; cur_mf_state = MF_USC_LSC; rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state); - rtlpriv->rtlhal.rts_en = 0; primarycca->dup_rts_flag = 0; } } else if (sec_ch_offset == 1) { @@ -642,13 +638,11 @@ static void rtl92ee_dm_dynamic_primary_cca_ckeck(struct ieee80211_hw *hw) rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state); primarycca->pricca_flag = 1; primarycca->dup_rts_flag = 1; - rtlpriv->rtlhal.rts_en = 1; } else { primarycca->intf_type = 0; primarycca->intf_flag = 0; cur_mf_state = MF_USC_LSC; rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state); - rtlpriv->rtlhal.rts_en = 0; primarycca->dup_rts_flag = 0; } } @@ -660,7 +654,6 @@ static void rtl92ee_dm_dynamic_primary_cca_ckeck(struct ieee80211_hw *hw) cur_mf_state = MF_USC_LSC; /* default */ rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state); - rtlpriv->rtlhal.rts_en = 0; primarycca->dup_rts_flag = 0; primarycca->intf_type = 0; primarycca->intf_flag = 0; @@ -1090,7 +1083,7 @@ void rtl92ee_dm_watchdog(struct ieee80211_hw *hw) rtl92ee_dm_refresh_rate_adaptive_mask(hw); rtl92ee_dm_check_edca_turbo(hw); rtl92ee_dm_dynamic_atc_switch(hw); - rtl92ee_dm_dynamic_primary_cca_ckeck(hw); + rtl92ee_dm_dynamic_primary_cca_check(hw); } spin_unlock(&rtlpriv->locks.rf_ps_lock); } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c index ebb7abd0c9adf..d4da5cdc84143 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c @@ -1320,7 +1320,6 @@ int rtl92ee_hw_init(struct ieee80211_hw *hw) err = 1; return err; } - rtlhal->rx_tag = 0; rtl_write_word(rtlpriv, REG_PCIE_CTRL_REG, 0x8000); err = rtl92ee_download_fw(hw, false); if (err) { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c index 011ce82efeff1..7bde20fdbeab1 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c @@ -24,9 +24,6 @@ static void rtl92ee_init_aspm_vars(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - /*close ASPM for AMD defaultly */ - rtlpci->const_amdpci_aspm = 0; - /** * ASPM PS mode. * 0 - Disable ASPM, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c index 30bce381c3bb7..675bdd32feb17 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c @@ -21,9 +21,6 @@ static void rtl92s_init_aspm_vars(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - /*close ASPM for AMD defaultly */ - rtlpci->const_amdpci_aspm = 0; - /* ASPM PS mode. * 0 - Disable ASPM, * 1 - Enable ASPM without Clock Req, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c index c821436a19916..dd7505e2f22c8 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c @@ -26,9 +26,6 @@ static void rtl8723e_init_aspm_vars(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - /*close ASPM for AMD defaultly */ - rtlpci->const_amdpci_aspm = 0; - /** * ASPM PS mode. * 0 - Disable ASPM, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c index 43b611d5288d9..162c34f0e9b7c 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c @@ -26,9 +26,6 @@ static void rtl8723be_init_aspm_vars(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - /*close ASPM for AMD defaultly */ - rtlpci->const_amdpci_aspm = 0; - /* ASPM PS mode. * 0 - Disable ASPM, * 1 - Enable ASPM without Clock Req, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c index 0bca542e103f0..7b911695db337 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c @@ -23,9 +23,6 @@ static void rtl8821ae_init_aspm_vars(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - /*close ASPM for AMD defaultly */ - rtlpci->const_amdpci_aspm = 0; - /** * ASPM PS mode. * 0 - Disable ASPM, diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 31a481f43a07d..ac8dfda7099de 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -1316,7 +1316,6 @@ struct rtl_phy { u8 sw_chnl_stage; u8 sw_chnl_step; u8 current_channel; - u8 h2c_box_num; u8 set_io_inprogress; u8 lck_inprogress; @@ -1329,9 +1328,6 @@ struct rtl_phy { s32 reg_ebc; s32 reg_ec4; s32 reg_ecc; - u8 rfpienable; - u8 reserve_0; - u16 reserve_1; u32 reg_c04, reg_c08, reg_874; u32 adda_backup[16]; u32 iqk_mac_backup[IQK_MAC_REG_NUM]; @@ -1345,7 +1341,6 @@ struct rtl_phy { struct iqk_matrix_regs iqk_matrix[IQK_MATRIX_SETTINGS_NUM]; bool rfpi_enable; - bool iqk_in_progress; u8 pwrgroup_cnt; u8 cck_high_power; @@ -1383,7 +1378,6 @@ struct rtl_phy { [MAX_RF_PATH_NUM]; u32 rfreg_chnlval[2]; - bool apk_done; u32 reg_rf3c[2]; /* pathA / pathB */ u32 backup_rf_0x1a;/*92ee*/ @@ -1395,7 +1389,6 @@ struct rtl_phy { struct phy_parameters hwparam_tables[MAX_TAB]; u16 rf_pathmap; - u8 hw_rof_enable; /*Enable GPIO[9] as WL RF HW PDn source*/ enum rt_polarity_ctl polarity_ctl; }; @@ -1610,7 +1603,6 @@ struct rtl_hal { bool up_first_time; bool first_init; bool being_init_adapter; - bool bbrf_ready; bool mac_func_enable; bool pre_edcca_enable; struct bt_coexist_8723 hal_coex_8723; @@ -1623,9 +1615,7 @@ struct rtl_hal { u8 state; /*stop 0, start 1 */ u8 board_type; u8 package_type; - u8 external_pa; - u8 pa_mode; u8 pa_type_2g; u8 pa_type_5g; u8 lna_type_2g; @@ -1691,14 +1681,9 @@ struct rtl_hal { bool master_of_dmsp; bool slave_of_dmsp; - u16 rx_tag;/*for 92ee*/ - u8 rts_en; - /*for wowlan*/ - bool wow_enable; bool enter_pnp_sleep; bool wake_from_pnp_sleep; - bool wow_enabled; time64_t last_suspend_sec; u32 wowlan_fwsize; u8 *wowlan_firmware; @@ -2023,8 +2008,6 @@ struct rtl_ps_ctl { u32 cur_ps_level; u32 reg_rfps_level; - /*just for PCIE ASPM */ - u8 const_amdpci_aspm; bool pwrdown_mode; enum rf_pwrstate inactive_pwrstate; diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index a99b53d442676..d8d68f16014e3 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -280,9 +280,9 @@ static void rtw_ops_configure_filter(struct ieee80211_hw *hw, if (changed_flags & FIF_ALLMULTI) { if (*new_flags & FIF_ALLMULTI) - rtwdev->hal.rcr |= BIT_AM | BIT_AB; + rtwdev->hal.rcr |= BIT_AM; else - rtwdev->hal.rcr &= ~(BIT_AM | BIT_AB); + rtwdev->hal.rcr &= ~(BIT_AM); } if (changed_flags & FIF_FCSFAIL) { if (*new_flags & FIF_FCSFAIL) diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c index f63900b6621d9..c02ac673be321 100644 --- a/drivers/net/wireless/realtek/rtw88/tx.c +++ b/drivers/net/wireless/realtek/rtw88/tx.c @@ -656,9 +656,8 @@ void __rtw_tx_work(struct rtw_dev *rtwdev) list_for_each_entry_safe(rtwtxq, tmp, &rtwdev->txqs, list) { struct ieee80211_txq *txq = rtwtxq_to_txq(rtwtxq); unsigned long frame_cnt; - unsigned long byte_cnt; - ieee80211_txq_get_depth(txq, &frame_cnt, &byte_cnt); + ieee80211_txq_get_depth(txq, &frame_cnt, NULL); rtw_txq_push(rtwdev, rtwtxq, frame_cnt); list_del_init(&rtwtxq->list); diff --git a/drivers/net/wireless/realtek/rtw89/acpi.c b/drivers/net/wireless/realtek/rtw89/acpi.c index 8aaf83a2a6b48..2e7326a8e3e47 100644 --- a/drivers/net/wireless/realtek/rtw89/acpi.c +++ b/drivers/net/wireless/realtek/rtw89/acpi.c @@ -12,27 +12,74 @@ static const guid_t rtw89_guid = GUID_INIT(0xD2A8C3E8, 0x4B69, 0x4F00, 0x82, 0xBD, 0xFE, 0x86, 0x07, 0x80, 0x3A, 0xA7); -static int rtw89_acpi_dsm_get(struct rtw89_dev *rtwdev, union acpi_object *obj, - u8 *value) +static +int rtw89_acpi_dsm_get_value(struct rtw89_dev *rtwdev, union acpi_object *obj, + u8 *value) { - switch (obj->type) { - case ACPI_TYPE_INTEGER: - *value = (u8)obj->integer.value; - break; - case ACPI_TYPE_BUFFER: - *value = obj->buffer.pointer[0]; - break; - default: - rtw89_debug(rtwdev, RTW89_DBG_UNEXP, - "acpi dsm return unhandled type: %d\n", obj->type); + if (obj->type != ACPI_TYPE_INTEGER) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, + "acpi: expect integer but type: %d\n", obj->type); return -EINVAL; } + *value = (u8)obj->integer.value; + return 0; +} + +static bool chk_acpi_policy_6ghz_sig(const struct rtw89_acpi_policy_6ghz *p) +{ + return p->signature[0] == 0x00 && + p->signature[1] == 0xE0 && + p->signature[2] == 0x4C; +} + +static +int rtw89_acpi_dsm_get_policy_6ghz(struct rtw89_dev *rtwdev, + union acpi_object *obj, + struct rtw89_acpi_policy_6ghz **policy_6ghz) +{ + const struct rtw89_acpi_policy_6ghz *ptr; + u32 expect_len; + u32 len; + + if (obj->type != ACPI_TYPE_BUFFER) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, + "acpi: expect buffer but type: %d\n", obj->type); + return -EINVAL; + } + + len = obj->buffer.length; + if (len < sizeof(*ptr)) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: invalid buffer length: %u\n", + __func__, len); + return -EINVAL; + } + + ptr = (typeof(ptr))obj->buffer.pointer; + if (!chk_acpi_policy_6ghz_sig(ptr)) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: bad signature\n", __func__); + return -EINVAL; + } + + expect_len = struct_size(ptr, country_list, ptr->country_count); + if (len < expect_len) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: expect %u but length: %u\n", + __func__, expect_len, len); + return -EINVAL; + } + + *policy_6ghz = kmemdup(ptr, expect_len, GFP_KERNEL); + if (!*policy_6ghz) + return -ENOMEM; + + rtw89_hex_dump(rtwdev, RTW89_DBG_ACPI, "policy_6ghz: ", *policy_6ghz, + expect_len); return 0; } int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev, - enum rtw89_acpi_dsm_func func, u8 *value) + enum rtw89_acpi_dsm_func func, + struct rtw89_acpi_dsm_result *res) { union acpi_object *obj; int ret; @@ -40,12 +87,16 @@ int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev, obj = acpi_evaluate_dsm(ACPI_HANDLE(rtwdev->dev), &rtw89_guid, 0, func, NULL); if (!obj) { - rtw89_debug(rtwdev, RTW89_DBG_UNEXP, + rtw89_debug(rtwdev, RTW89_DBG_ACPI, "acpi dsm fail to evaluate func: %d\n", func); return -ENOENT; } - ret = rtw89_acpi_dsm_get(rtwdev, obj, value); + if (func == RTW89_ACPI_DSM_FUNC_6G_BP) + ret = rtw89_acpi_dsm_get_policy_6ghz(rtwdev, obj, + &res->u.policy_6ghz); + else + ret = rtw89_acpi_dsm_get_value(rtwdev, obj, &res->u.value); ACPI_FREE(obj); return ret; diff --git a/drivers/net/wireless/realtek/rtw89/acpi.h b/drivers/net/wireless/realtek/rtw89/acpi.h index ed74d8ceb7339..fe85b40cf0769 100644 --- a/drivers/net/wireless/realtek/rtw89/acpi.h +++ b/drivers/net/wireless/realtek/rtw89/acpi.h @@ -15,7 +15,37 @@ enum rtw89_acpi_dsm_func { RTW89_ACPI_DSM_FUNC_59G_EN = 6, }; +enum rtw89_acpi_policy_mode { + RTW89_ACPI_POLICY_BLOCK = 0, + RTW89_ACPI_POLICY_ALLOW = 1, +}; + +struct rtw89_acpi_country_code { + /* below are allowed: + * * ISO alpha2 country code + * * EU for countries in Europe + */ + char alpha2[2]; +} __packed; + +struct rtw89_acpi_policy_6ghz { + u8 signature[3]; + u8 rsvd; + u8 policy_mode; + u8 country_count; + struct rtw89_acpi_country_code country_list[] __counted_by(country_count); +} __packed; + +struct rtw89_acpi_dsm_result { + union { + u8 value; + /* caller needs to free it after using */ + struct rtw89_acpi_policy_6ghz *policy_6ghz; + } u; +}; + int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev, - enum rtw89_acpi_dsm_func func, u8 *value); + enum rtw89_acpi_dsm_func func, + struct rtw89_acpi_dsm_result *res); #endif diff --git a/drivers/net/wireless/realtek/rtw89/cam.c b/drivers/net/wireless/realtek/rtw89/cam.c index f5301c2bbf133..914c94988b2f4 100644 --- a/drivers/net/wireless/realtek/rtw89/cam.c +++ b/drivers/net/wireless/realtek/rtw89/cam.c @@ -488,6 +488,20 @@ static int rtw89_cam_get_avail_addr_cam(struct rtw89_dev *rtwdev, return 0; } +static u8 rtw89_get_addr_cam_entry_size(struct rtw89_dev *rtwdev) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + + switch (chip->chip_id) { + case RTL8852A: + case RTL8852B: + case RTL8851B: + return ADDR_CAM_ENT_SIZE; + default: + return ADDR_CAM_ENT_SHORT_SIZE; + } +} + int rtw89_cam_init_addr_cam(struct rtw89_dev *rtwdev, struct rtw89_addr_cam_entry *addr_cam, const struct rtw89_bssid_cam_entry *bssid_cam) @@ -509,7 +523,7 @@ int rtw89_cam_init_addr_cam(struct rtw89_dev *rtwdev, } addr_cam->addr_cam_idx = addr_cam_idx; - addr_cam->len = ADDR_CAM_ENT_SIZE; + addr_cam->len = rtw89_get_addr_cam_entry_size(rtwdev); addr_cam->offset = 0; addr_cam->valid = true; addr_cam->addr_mask = 0; diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index bdcc172639e4e..b842cd9a86f83 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -1576,13 +1576,13 @@ static void _append_tdma(struct rtw89_dev *rtwdev) if (ver->fcxtdma == 1) { v = (struct rtw89_btc_fbtc_tdma *)&tlv->val[0]; tlv->len = sizeof(*v); - memcpy(v, &dm->tdma, sizeof(*v)); + *v = dm->tdma; btc->policy_len += BTC_TLV_HDR_LEN + sizeof(*v); } else { tlv->len = sizeof(*v3); v3 = (struct rtw89_btc_fbtc_tdma_v3 *)&tlv->val[0]; v3->fver = ver->fcxtdma; - memcpy(&v3->tdma, &dm->tdma, sizeof(v3->tdma)); + v3->tdma = dm->tdma; btc->policy_len += BTC_TLV_HDR_LEN + sizeof(*v3); } diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 3d75165e48bea..74bf296438239 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -1407,29 +1407,65 @@ static int rtw89_core_rx_process_mac_ppdu(struct rtw89_dev *rtwdev, struct sk_buff *skb, struct rtw89_rx_phy_ppdu *phy_ppdu) { + const struct rtw89_chip_info *chip = rtwdev->chip; const struct rtw89_rxinfo *rxinfo = (const struct rtw89_rxinfo *)skb->data; + const struct rtw89_rxinfo_user *user; + enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen; + int rx_cnt_size = RTW89_PPDU_MAC_RX_CNT_SIZE; bool rx_cnt_valid = false; + bool invalid = false; u8 plcp_size = 0; - u8 usr_num = 0; u8 *phy_sts; + u8 usr_num; + int i; + + if (chip_gen == RTW89_CHIP_BE) { + invalid = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_INVALID_V1); + rx_cnt_size = RTW89_PPDU_MAC_RX_CNT_SIZE_V1; + } + + if (invalid) + return -EINVAL; rx_cnt_valid = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_RX_CNT_VLD); - plcp_size = le32_get_bits(rxinfo->w1, RTW89_RXINFO_W1_PLCP_LEN) << 3; - usr_num = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_USR_NUM); - if (usr_num > RTW89_PPDU_MAX_USR) { - rtw89_warn(rtwdev, "Invalid user number in mac info\n"); + if (chip_gen == RTW89_CHIP_BE) { + plcp_size = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_PLCP_LEN_V1) << 3; + usr_num = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_USR_NUM_V1); + } else { + plcp_size = le32_get_bits(rxinfo->w1, RTW89_RXINFO_W1_PLCP_LEN) << 3; + usr_num = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_USR_NUM); + } + if (usr_num > chip->ppdu_max_usr) { + rtw89_warn(rtwdev, "Invalid user number (%d) in mac info\n", + usr_num); return -EINVAL; } + /* For WiFi 7 chips, RXWD.mac_id of PPDU status is not set by hardware, + * so update mac_id by rxinfo_user[].mac_id. + */ + for (i = 0; i < usr_num && chip_gen == RTW89_CHIP_BE; i++) { + user = &rxinfo->user[i]; + if (!le32_get_bits(user->w0, RTW89_RXINFO_USER_MAC_ID_VALID)) + continue; + + phy_ppdu->mac_id = + le32_get_bits(user->w0, RTW89_RXINFO_USER_MACID); + break; + } + phy_sts = skb->data + RTW89_PPDU_MAC_INFO_SIZE; phy_sts += usr_num * RTW89_PPDU_MAC_INFO_USR_SIZE; /* 8-byte alignment */ if (usr_num & BIT(0)) phy_sts += RTW89_PPDU_MAC_INFO_USR_SIZE; if (rx_cnt_valid) - phy_sts += RTW89_PPDU_MAC_RX_CNT_SIZE; + phy_sts += rx_cnt_size; phy_sts += plcp_size; + if (phy_sts > skb->data + skb->len) + return -EINVAL; + phy_ppdu->buf = phy_sts; phy_ppdu->len = skb->data + skb->len - phy_sts; @@ -1477,14 +1513,24 @@ static void rtw89_core_rx_process_phy_ppdu_iter(void *data, static u16 rtw89_core_get_phy_status_ie_len(struct rtw89_dev *rtwdev, const struct rtw89_phy_sts_iehdr *iehdr) { - static const u8 physts_ie_len_tab[32] = { - 16, 32, 24, 24, 8, 8, 8, 8, VAR_LEN, 8, VAR_LEN, 176, VAR_LEN, - VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, 16, 24, VAR_LEN, - VAR_LEN, VAR_LEN, 0, 24, 24, 24, 24, 32, 32, 32, 32 + static const u8 physts_ie_len_tabs[RTW89_CHIP_GEN_NUM][32] = { + [RTW89_CHIP_AX] = { + 16, 32, 24, 24, 8, 8, 8, 8, VAR_LEN, 8, VAR_LEN, 176, VAR_LEN, + VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, 16, 24, VAR_LEN, + VAR_LEN, VAR_LEN, 0, 24, 24, 24, 24, 32, 32, 32, 32 + }, + [RTW89_CHIP_BE] = { + 32, 40, 24, 24, 8, 8, 8, 8, VAR_LEN, 8, VAR_LEN, 176, VAR_LEN, + VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, 16, 24, VAR_LEN, + VAR_LEN, VAR_LEN, 0, 24, 24, 24, 24, 32, 32, 32, 32 + }, }; + const u8 *physts_ie_len_tab; u16 ie_len; u8 ie; + physts_ie_len_tab = physts_ie_len_tabs[rtwdev->chip->chip_gen]; + ie = le32_get_bits(iehdr->w0, RTW89_PHY_STS_IEHDR_TYPE); if (physts_ie_len_tab[ie] != VAR_LEN) ie_len = physts_ie_len_tab[ie]; @@ -1563,9 +1609,17 @@ static int rtw89_core_rx_process_phy_ppdu(struct rtw89_dev *rtwdev, { const struct rtw89_phy_sts_hdr *hdr = phy_ppdu->buf; u32 len_from_header; + bool physts_valid; + + physts_valid = le32_get_bits(hdr->w0, RTW89_PHY_STS_HDR_W0_VALID); + if (!physts_valid) + return -EINVAL; len_from_header = le32_get_bits(hdr->w0, RTW89_PHY_STS_HDR_W0_LEN) << 3; + if (rtwdev->chip->chip_gen == RTW89_CHIP_BE) + len_from_header += PHY_STS_HDR_LEN; + if (len_from_header != phy_ppdu->len) { rtw89_debug(rtwdev, RTW89_DBG_UNEXP, "phy ppdu len mismatch\n"); return -EINVAL; @@ -2052,13 +2106,19 @@ static void rtw89_core_rx_process_ppdu_sts(struct rtw89_dev *rtwdev, .mac_id = desc_info->mac_id}; int ret; - if (desc_info->mac_info_valid) - rtw89_core_rx_process_mac_ppdu(rtwdev, skb, &phy_ppdu); + if (desc_info->mac_info_valid) { + ret = rtw89_core_rx_process_mac_ppdu(rtwdev, skb, &phy_ppdu); + if (ret) + goto out; + } + ret = rtw89_core_rx_process_phy_ppdu(rtwdev, &phy_ppdu); if (ret) - rtw89_debug(rtwdev, RTW89_DBG_TXRX, "process ppdu failed\n"); + goto out; rtw89_core_rx_process_phy_sts(rtwdev, &phy_ppdu); + +out: rtw89_core_rx_pending_skb(rtwdev, &phy_ppdu, desc_info, skb); dev_kfree_skb_any(skb); } @@ -2886,7 +2946,7 @@ void rtw89_roc_end(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) if (hw->conf.flags & IEEE80211_CONF_IDLE) ieee80211_queue_delayed_work(hw, &roc->roc_work, - RTW89_ROC_IDLE_TIMEOUT); + msecs_to_jiffies(RTW89_ROC_IDLE_TIMEOUT)); } void rtw89_roc_work(struct work_struct *work) @@ -4156,17 +4216,18 @@ static void rtw89_core_setup_rfe_parms(struct rtw89_dev *rtwdev) static int rtw89_chip_efuse_info_setup(struct rtw89_dev *rtwdev) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; int ret; ret = rtw89_mac_partial_init(rtwdev, false); if (ret) return ret; - ret = rtw89_parse_efuse_map(rtwdev); + ret = mac->parse_efuse_map(rtwdev); if (ret) return ret; - ret = rtw89_parse_phycap_map(rtwdev); + ret = mac->parse_phycap_map(rtwdev); if (ret) return ret; @@ -4176,6 +4237,8 @@ static int rtw89_chip_efuse_info_setup(struct rtw89_dev *rtwdev) rtw89_core_setup_phycap(rtwdev); + rtw89_hci_mac_pre_deinit(rtwdev); + rtw89_mac_pwr_off(rtwdev); return 0; diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 91e4d4e79eeaf..6948ffe0f2061 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -16,6 +16,7 @@ struct rtw89_dev; struct rtw89_pci_info; struct rtw89_mac_gen_def; struct rtw89_phy_gen_def; +struct rtw89_efuse_block_cfg; extern const struct ieee80211_ops rtw89_ops; @@ -103,6 +104,14 @@ enum rtw89_gain_offset { RTW89_GAIN_OFFSET_5G_LOW, RTW89_GAIN_OFFSET_5G_MID, RTW89_GAIN_OFFSET_5G_HIGH, + RTW89_GAIN_OFFSET_6G_L0, + RTW89_GAIN_OFFSET_6G_L1, + RTW89_GAIN_OFFSET_6G_M0, + RTW89_GAIN_OFFSET_6G_M1, + RTW89_GAIN_OFFSET_6G_H0, + RTW89_GAIN_OFFSET_6G_H1, + RTW89_GAIN_OFFSET_6G_UH0, + RTW89_GAIN_OFFSET_6G_UH1, RTW89_GAIN_OFFSET_NR, }; @@ -2777,6 +2786,20 @@ enum rtw89_rx_frame_type { RTW89_RX_TYPE_RSVD = 3, }; +enum rtw89_efuse_block { + RTW89_EFUSE_BLOCK_SYS = 0, + RTW89_EFUSE_BLOCK_RF = 1, + RTW89_EFUSE_BLOCK_HCI_DIG_PCIE_SDIO = 2, + RTW89_EFUSE_BLOCK_HCI_DIG_USB = 3, + RTW89_EFUSE_BLOCK_HCI_PHY_PCIE = 4, + RTW89_EFUSE_BLOCK_HCI_PHY_USB3 = 5, + RTW89_EFUSE_BLOCK_HCI_PHY_USB2 = 6, + RTW89_EFUSE_BLOCK_ADIE = 7, + + RTW89_EFUSE_BLOCK_NUM, + RTW89_EFUSE_BLOCK_IGNORE, +}; + struct rtw89_ra_info { u8 is_dis_ra:1; /* Bit0 : CCK @@ -2815,10 +2838,10 @@ struct rtw89_ra_info { u8 csi_bw:3; }; -#define RTW89_PPDU_MAX_USR 4 #define RTW89_PPDU_MAC_INFO_USR_SIZE 4 #define RTW89_PPDU_MAC_INFO_SIZE 8 #define RTW89_PPDU_MAC_RX_CNT_SIZE 96 +#define RTW89_PPDU_MAC_RX_CNT_SIZE_V1 128 #define RTW89_MAX_RX_AGG_NUM 64 #define RTW89_MAX_TX_AGG_NUM 128 @@ -3064,6 +3087,7 @@ struct rtw89_hci_ops { void (*write32)(struct rtw89_dev *rtwdev, u32 addr, u32 data); int (*mac_pre_init)(struct rtw89_dev *rtwdev); + int (*mac_pre_deinit)(struct rtw89_dev *rtwdev); int (*mac_post_init)(struct rtw89_dev *rtwdev); int (*deinit)(struct rtw89_dev *rtwdev); @@ -3118,7 +3142,8 @@ struct rtw89_chip_ops { const struct rtw89_chan *chan, enum rtw89_mac_idx mac_idx, enum rtw89_phy_idx phy_idx); - int (*read_efuse)(struct rtw89_dev *rtwdev, u8 *log_map); + int (*read_efuse)(struct rtw89_dev *rtwdev, u8 *log_map, + enum rtw89_efuse_block block); int (*read_phycap)(struct rtw89_dev *rtwdev, u8 *phycap_map); void (*fem_setup)(struct rtw89_dev *rtwdev); void (*rfe_gpio)(struct rtw89_dev *rtwdev); @@ -3644,6 +3669,7 @@ struct rtw89_chip_info { u8 bacam_num; u8 bacam_dynamic_num; enum rtw89_bacam_ver bacam_ver; + u8 ppdu_max_usr; u8 sec_ctrl_efuse_size; u32 physical_efuse_size; @@ -3653,6 +3679,7 @@ struct rtw89_chip_info { u32 dav_log_efuse_size; u32 phycap_addr; u32 phycap_size; + const struct rtw89_efuse_block_cfg *efuse_blocks; const struct rtw89_pwr_cfg * const *pwr_on_seq; const struct rtw89_pwr_cfg * const *pwr_off_seq; @@ -4318,6 +4345,7 @@ struct rtw89_power_trim_info { bool pg_pa_bias_trim; u8 thermal_trim[RF_PATH_MAX]; u8 pa_bias_trim[RF_PATH_MAX]; + u8 pad_bias_trim[RF_PATH_MAX]; }; struct rtw89_regd { @@ -4325,9 +4353,12 @@ struct rtw89_regd { u8 txpwr_regd[RTW89_BAND_NUM]; }; +#define RTW89_REGD_MAX_COUNTRY_NUM U8_MAX + struct rtw89_regulatory_info { const struct rtw89_regd *regd; enum rtw89_reg_6ghz_power reg_6ghz_power; + DECLARE_BITMAP(block_6ghz, RTW89_REGD_MAX_COUNTRY_NUM); }; enum rtw89_ifs_clm_application { @@ -4802,6 +4833,11 @@ static inline void rtw89_hci_tx_kick_off(struct rtw89_dev *rtwdev, u8 txch) return rtwdev->hci.ops->tx_kick_off(rtwdev, txch); } +static inline int rtw89_hci_mac_pre_deinit(struct rtw89_dev *rtwdev) +{ + return rtwdev->hci.ops->mac_pre_deinit(rtwdev); +} + static inline void rtw89_hci_flush_queues(struct rtw89_dev *rtwdev, u32 queues, bool drop) { diff --git a/drivers/net/wireless/realtek/rtw89/debug.h b/drivers/net/wireless/realtek/rtw89/debug.h index 079269bb5251c..b663ee24555a1 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.h +++ b/drivers/net/wireless/realtek/rtw89/debug.h @@ -29,6 +29,7 @@ enum rtw89_debug_mask { RTW89_DBG_WOW = BIT(18), RTW89_DBG_UL_TB = BIT(19), RTW89_DBG_CHAN = BIT(20), + RTW89_DBG_ACPI = BIT(21), RTW89_DBG_UNEXP = BIT(31), }; diff --git a/drivers/net/wireless/realtek/rtw89/efuse.c b/drivers/net/wireless/realtek/rtw89/efuse.c index 2aaf4d013e464..e1236079a84a1 100644 --- a/drivers/net/wireless/realtek/rtw89/efuse.c +++ b/drivers/net/wireless/realtek/rtw89/efuse.c @@ -114,6 +114,11 @@ static int rtw89_dump_physical_efuse_map_ddv(struct rtw89_dev *rtwdev, u8 *map, return 0; } +int rtw89_cnv_efuse_state_ax(struct rtw89_dev *rtwdev, bool idle) +{ + return 0; +} + static int rtw89_dump_physical_efuse_map_dav(struct rtw89_dev *rtwdev, u8 *map, u32 dump_addr, u32 dump_size) { @@ -231,7 +236,7 @@ static int rtw89_dump_logical_efuse_map(struct rtw89_dev *rtwdev, u8 *phy_map, return 0; } -int rtw89_parse_efuse_map(struct rtw89_dev *rtwdev) +int rtw89_parse_efuse_map_ax(struct rtw89_dev *rtwdev) { u32 phy_size = rtwdev->chip->physical_efuse_size; u32 log_size = rtwdev->chip->logical_efuse_size; @@ -286,7 +291,7 @@ int rtw89_parse_efuse_map(struct rtw89_dev *rtwdev) rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "log_map: ", log_map, full_log_size); - ret = rtwdev->chip->ops->read_efuse(rtwdev, log_map); + ret = rtwdev->chip->ops->read_efuse(rtwdev, log_map, RTW89_EFUSE_BLOCK_IGNORE); if (ret) { rtw89_warn(rtwdev, "failed to read efuse map\n"); goto out_free; @@ -300,7 +305,7 @@ int rtw89_parse_efuse_map(struct rtw89_dev *rtwdev) return ret; } -int rtw89_parse_phycap_map(struct rtw89_dev *rtwdev) +int rtw89_parse_phycap_map_ax(struct rtw89_dev *rtwdev) { u32 phycap_addr = rtwdev->chip->phycap_addr; u32 phycap_size = rtwdev->chip->phycap_size; diff --git a/drivers/net/wireless/realtek/rtw89/efuse.h b/drivers/net/wireless/realtek/rtw89/efuse.h index 79071aff28de3..5c6787179bad1 100644 --- a/drivers/net/wireless/realtek/rtw89/efuse.h +++ b/drivers/net/wireless/realtek/rtw89/efuse.h @@ -7,8 +7,21 @@ #include "core.h" -int rtw89_parse_efuse_map(struct rtw89_dev *rtwdev); -int rtw89_parse_phycap_map(struct rtw89_dev *rtwdev); +#define RTW89_EFUSE_BLOCK_ID_MASK GENMASK(31, 16) +#define RTW89_EFUSE_BLOCK_SIZE_MASK GENMASK(15, 0) +#define RTW89_EFUSE_MAX_BLOCK_SIZE 0x10000 + +struct rtw89_efuse_block_cfg { + u32 offset; + u32 size; +}; + +int rtw89_parse_efuse_map_ax(struct rtw89_dev *rtwdev); +int rtw89_parse_phycap_map_ax(struct rtw89_dev *rtwdev); +int rtw89_cnv_efuse_state_ax(struct rtw89_dev *rtwdev, bool idle); +int rtw89_parse_efuse_map_be(struct rtw89_dev *rtwdev); +int rtw89_parse_phycap_map_be(struct rtw89_dev *rtwdev); +int rtw89_cnv_efuse_state_be(struct rtw89_dev *rtwdev, bool idle); int rtw89_read_efuse_ver(struct rtw89_dev *rtwdev, u8 *efv); #endif diff --git a/drivers/net/wireless/realtek/rtw89/efuse_be.c b/drivers/net/wireless/realtek/rtw89/efuse_be.c new file mode 100644 index 0000000000000..8e8b7cd315f7d --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/efuse_be.c @@ -0,0 +1,420 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2023 Realtek Corporation + */ + +#include "debug.h" +#include "efuse.h" +#include "mac.h" +#include "reg.h" + +static void rtw89_enable_efuse_pwr_cut_ddv_be(struct rtw89_dev *rtwdev) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_hal *hal = &rtwdev->hal; + bool aphy_patch = true; + + if (chip->chip_id == RTL8922A && hal->cv == CHIP_CAV) + aphy_patch = false; + + rtw89_write8_set(rtwdev, R_BE_PMC_DBG_CTRL2, B_BE_SYSON_DIS_PMCR_BE_WRMSK); + + if (aphy_patch) { + rtw89_write16_set(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_S); + mdelay(1); + rtw89_write16_set(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_B); + rtw89_write16_clr(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_ISO_EB2CORE); + } + + rtw89_write32_set(rtwdev, R_BE_EFUSE_CTRL_2_V1, B_BE_EF_BURST); +} + +static void rtw89_disable_efuse_pwr_cut_ddv_be(struct rtw89_dev *rtwdev) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_hal *hal = &rtwdev->hal; + bool aphy_patch = true; + + if (chip->chip_id == RTL8922A && hal->cv == CHIP_CAV) + aphy_patch = false; + + if (aphy_patch) { + rtw89_write16_set(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_ISO_EB2CORE); + rtw89_write16_clr(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_B); + mdelay(1); + rtw89_write16_clr(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_S); + } + + rtw89_write8_clr(rtwdev, R_BE_PMC_DBG_CTRL2, B_BE_SYSON_DIS_PMCR_BE_WRMSK); + rtw89_write32_clr(rtwdev, R_BE_EFUSE_CTRL_2_V1, B_BE_EF_BURST); +} + +static int rtw89_dump_physical_efuse_map_ddv_be(struct rtw89_dev *rtwdev, u8 *map, + u32 dump_addr, u32 dump_size) +{ + u32 efuse_ctl; + u32 addr; + u32 data; + int ret; + + if (!IS_ALIGNED(dump_addr, 4) || !IS_ALIGNED(dump_size, 4)) { + rtw89_err(rtwdev, "Efuse addr 0x%x or size 0x%x not aligned\n", + dump_addr, dump_size); + return -EINVAL; + } + + rtw89_enable_efuse_pwr_cut_ddv_be(rtwdev); + + for (addr = dump_addr; addr < dump_addr + dump_size; addr += 4, map += 4) { + efuse_ctl = u32_encode_bits(addr, B_BE_EF_ADDR_MASK); + rtw89_write32(rtwdev, R_BE_EFUSE_CTRL, efuse_ctl & ~B_BE_EF_RDY); + + ret = read_poll_timeout_atomic(rtw89_read32, efuse_ctl, + efuse_ctl & B_BE_EF_RDY, 1, 1000000, + true, rtwdev, R_BE_EFUSE_CTRL); + if (ret) + return -EBUSY; + + data = rtw89_read32(rtwdev, R_BE_EFUSE_CTRL_1_V1); + *((__le32 *)map) = cpu_to_le32(data); + } + + rtw89_disable_efuse_pwr_cut_ddv_be(rtwdev); + + return 0; +} + +static int rtw89_dump_physical_efuse_map_dav_be(struct rtw89_dev *rtwdev, u8 *map, + u32 dump_addr, u32 dump_size) +{ + u32 addr; + u8 val8; + int err; + int ret; + + for (addr = dump_addr; addr < dump_addr + dump_size; addr++) { + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, 0x40, + FULL_BIT_MASK); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_LOW_ADDR, addr & 0xff, + XTAL_SI_LOW_ADDR_MASK); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, addr >> 8, + XTAL_SI_HIGH_ADDR_MASK); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, 0, + XTAL_SI_MODE_SEL_MASK); + if (ret) + return ret; + + ret = read_poll_timeout_atomic(rtw89_mac_read_xtal_si, err, + !err && (val8 & XTAL_SI_RDY), + 1, 10000, false, + rtwdev, XTAL_SI_CTRL, &val8); + if (ret) { + rtw89_warn(rtwdev, "failed to read dav efuse\n"); + return ret; + } + + ret = rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_READ_VAL, &val8); + if (ret) + return ret; + *map++ = val8; + } + + return 0; +} + +int rtw89_cnv_efuse_state_be(struct rtw89_dev *rtwdev, bool idle) +{ + u32 val; + int ret = 0; + + if (idle) { + rtw89_write32_set(rtwdev, R_BE_WL_BT_PWR_CTRL, B_BE_BT_DISN_EN); + } else { + rtw89_write32_clr(rtwdev, R_BE_WL_BT_PWR_CTRL, B_BE_BT_DISN_EN); + + ret = read_poll_timeout(rtw89_read32_mask, val, + val == MAC_AX_SYS_ACT, 50, 5000, + false, rtwdev, R_BE_IC_PWR_STATE, + B_BE_WHOLE_SYS_PWR_STE_MASK); + if (ret) + rtw89_warn(rtwdev, "failed to convert efuse state\n"); + } + + return ret; +} + +static int rtw89_dump_physical_efuse_map_be(struct rtw89_dev *rtwdev, u8 *map, + u32 dump_addr, u32 dump_size, bool dav) +{ + int ret; + + if (!map || dump_size == 0) + return 0; + + rtw89_cnv_efuse_state_be(rtwdev, false); + + if (dav) { + ret = rtw89_dump_physical_efuse_map_dav_be(rtwdev, map, + dump_addr, dump_size); + if (ret) + return ret; + + rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "phy_map dav: ", map, dump_size); + } else { + ret = rtw89_dump_physical_efuse_map_ddv_be(rtwdev, map, + dump_addr, dump_size); + if (ret) + return ret; + + rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "phy_map ddv: ", map, dump_size); + } + + rtw89_cnv_efuse_state_be(rtwdev, true); + + return 0; +} + +#define EFUSE_HDR_CONST_MASK GENMASK(23, 20) +#define EFUSE_HDR_PAGE_MASK GENMASK(19, 17) +#define EFUSE_HDR_OFFSET_MASK GENMASK(16, 4) +#define EFUSE_HDR_OFFSET_DAV_MASK GENMASK(11, 4) +#define EFUSE_HDR_WORD_EN_MASK GENMASK(3, 0) + +#define invalid_efuse_header_be(hdr1, hdr2, hdr3) \ + ((hdr1) == 0xff || (hdr2) == 0xff || (hdr3) == 0xff) +#define invalid_efuse_content_be(word_en, i) \ + (((word_en) & BIT(i)) != 0x0) +#define get_efuse_blk_idx_be(hdr1, hdr2, hdr3) \ + (((hdr1) << 16) | ((hdr2) << 8) | (hdr3)) +#define block_idx_to_logical_idx_be(blk_idx, i) \ + (((blk_idx) << 3) + ((i) << 1)) + +#define invalid_efuse_header_dav_be(hdr1, hdr2) \ + ((hdr1) == 0xff || (hdr2) == 0xff) +#define get_efuse_blk_idx_dav_be(hdr1, hdr2) \ + (((hdr1) << 8) | (hdr2)) + +static int rtw89_eeprom_parser_be(struct rtw89_dev *rtwdev, + const u8 *phy_map, u32 phy_size, u8 *log_map, + const struct rtw89_efuse_block_cfg *efuse_block) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + enum rtw89_efuse_block blk_page, page; + u32 size = efuse_block->size; + u32 phy_idx, log_idx; + u32 hdr, page_offset; + u8 hdr1, hdr2, hdr3; + u8 i, val0, val1; + u32 min, max; + u16 blk_idx; + u8 word_en; + + page = u32_get_bits(efuse_block->offset, RTW89_EFUSE_BLOCK_ID_MASK); + page_offset = u32_get_bits(efuse_block->offset, RTW89_EFUSE_BLOCK_SIZE_MASK); + + min = ALIGN_DOWN(page_offset, 2); + max = ALIGN(page_offset + size, 2); + + memset(log_map, 0xff, size); + + phy_idx = chip->sec_ctrl_efuse_size; + + do { + if (page == RTW89_EFUSE_BLOCK_ADIE) { + hdr1 = phy_map[phy_idx]; + hdr2 = phy_map[phy_idx + 1]; + if (invalid_efuse_header_dav_be(hdr1, hdr2)) + break; + + phy_idx += 2; + + hdr = get_efuse_blk_idx_dav_be(hdr1, hdr2); + + blk_page = RTW89_EFUSE_BLOCK_ADIE; + blk_idx = u32_get_bits(hdr, EFUSE_HDR_OFFSET_DAV_MASK); + word_en = u32_get_bits(hdr, EFUSE_HDR_WORD_EN_MASK); + } else { + hdr1 = phy_map[phy_idx]; + hdr2 = phy_map[phy_idx + 1]; + hdr3 = phy_map[phy_idx + 2]; + if (invalid_efuse_header_be(hdr1, hdr2, hdr3)) + break; + + phy_idx += 3; + + hdr = get_efuse_blk_idx_be(hdr1, hdr2, hdr3); + + blk_page = u32_get_bits(hdr, EFUSE_HDR_PAGE_MASK); + blk_idx = u32_get_bits(hdr, EFUSE_HDR_OFFSET_MASK); + word_en = u32_get_bits(hdr, EFUSE_HDR_WORD_EN_MASK); + } + + if (blk_idx >= RTW89_EFUSE_MAX_BLOCK_SIZE >> 3) { + rtw89_err(rtwdev, "[ERR]efuse idx:0x%X\n", phy_idx - 3); + rtw89_err(rtwdev, "[ERR]read hdr:0x%X\n", hdr); + return -EINVAL; + } + + for (i = 0; i < 4; i++) { + if (invalid_efuse_content_be(word_en, i)) + continue; + + if (phy_idx >= phy_size - 1) + return -EINVAL; + + log_idx = block_idx_to_logical_idx_be(blk_idx, i); + + if (blk_page == page && log_idx >= min && log_idx < max) { + val0 = phy_map[phy_idx]; + val1 = phy_map[phy_idx + 1]; + + if (log_idx == min && page_offset > min) { + log_map[log_idx - page_offset + 1] = val1; + } else if (log_idx + 2 == max && + page_offset + size < max) { + log_map[log_idx - page_offset] = val0; + } else { + log_map[log_idx - page_offset] = val0; + log_map[log_idx - page_offset + 1] = val1; + } + } + phy_idx += 2; + } + } while (phy_idx < phy_size); + + return 0; +} + +static int rtw89_parse_logical_efuse_block_be(struct rtw89_dev *rtwdev, + const u8 *phy_map, u32 phy_size, + enum rtw89_efuse_block block) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + const struct rtw89_efuse_block_cfg *efuse_block; + u8 *log_map; + int ret; + + efuse_block = &chip->efuse_blocks[block]; + + log_map = kmalloc(efuse_block->size, GFP_KERNEL); + if (!log_map) + return -ENOMEM; + + ret = rtw89_eeprom_parser_be(rtwdev, phy_map, phy_size, log_map, efuse_block); + if (ret) { + rtw89_warn(rtwdev, "failed to dump efuse logical block %d\n", block); + goto out_free; + } + + rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "log_map: ", log_map, efuse_block->size); + + ret = rtwdev->chip->ops->read_efuse(rtwdev, log_map, block); + if (ret) { + rtw89_warn(rtwdev, "failed to read efuse map\n"); + goto out_free; + } + +out_free: + kfree(log_map); + + return ret; +} + +int rtw89_parse_efuse_map_be(struct rtw89_dev *rtwdev) +{ + u32 phy_size = rtwdev->chip->physical_efuse_size; + u32 dav_phy_size = rtwdev->chip->dav_phy_efuse_size; + enum rtw89_efuse_block block; + u8 *phy_map = NULL; + u8 *dav_phy_map = NULL; + int ret; + + if (rtw89_read16(rtwdev, R_BE_SYS_WL_EFUSE_CTRL) & B_BE_AUTOLOAD_SUS) + rtwdev->efuse.valid = true; + else + rtw89_warn(rtwdev, "failed to check efuse autoload\n"); + + phy_map = kmalloc(phy_size, GFP_KERNEL); + if (dav_phy_size) + dav_phy_map = kmalloc(dav_phy_size, GFP_KERNEL); + + if (!phy_map || (dav_phy_size && !dav_phy_map)) { + ret = -ENOMEM; + goto out_free; + } + + ret = rtw89_dump_physical_efuse_map_be(rtwdev, phy_map, 0, phy_size, false); + if (ret) { + rtw89_warn(rtwdev, "failed to dump efuse physical map\n"); + goto out_free; + } + ret = rtw89_dump_physical_efuse_map_be(rtwdev, dav_phy_map, 0, dav_phy_size, true); + if (ret) { + rtw89_warn(rtwdev, "failed to dump efuse dav physical map\n"); + goto out_free; + } + + if (rtwdev->hci.type == RTW89_HCI_TYPE_USB) + block = RTW89_EFUSE_BLOCK_HCI_DIG_USB; + else + block = RTW89_EFUSE_BLOCK_HCI_DIG_PCIE_SDIO; + + ret = rtw89_parse_logical_efuse_block_be(rtwdev, phy_map, phy_size, block); + if (ret) { + rtw89_warn(rtwdev, "failed to parse efuse logic block %d\n", + RTW89_EFUSE_BLOCK_HCI_DIG_PCIE_SDIO); + goto out_free; + } + + ret = rtw89_parse_logical_efuse_block_be(rtwdev, phy_map, phy_size, + RTW89_EFUSE_BLOCK_RF); + if (ret) { + rtw89_warn(rtwdev, "failed to parse efuse logic block %d\n", + RTW89_EFUSE_BLOCK_RF); + goto out_free; + } + +out_free: + kfree(dav_phy_map); + kfree(phy_map); + + return ret; +} + +int rtw89_parse_phycap_map_be(struct rtw89_dev *rtwdev) +{ + u32 phycap_addr = rtwdev->chip->phycap_addr; + u32 phycap_size = rtwdev->chip->phycap_size; + u8 *phycap_map = NULL; + int ret = 0; + + if (!phycap_size) + return 0; + + phycap_map = kmalloc(phycap_size, GFP_KERNEL); + if (!phycap_map) + return -ENOMEM; + + ret = rtw89_dump_physical_efuse_map_be(rtwdev, phycap_map, + phycap_addr, phycap_size, false); + if (ret) { + rtw89_warn(rtwdev, "failed to dump phycap map\n"); + goto out_free; + } + + ret = rtwdev->chip->ops->read_phycap(rtwdev, phycap_map); + if (ret) { + rtw89_warn(rtwdev, "failed to read phycap map\n"); + goto out_free; + } + +out_free: + kfree(phycap_map); + + return ret; +} diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 0c5768f41d55d..9ec3070516115 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -5,6 +5,7 @@ #include "cam.h" #include "chan.h" #include "debug.h" +#include "efuse.h" #include "fw.h" #include "mac.h" #include "pci.h" @@ -2626,20 +2627,26 @@ static int cmac_init(struct rtw89_dev *rtwdev, u8 mac_idx) static int rtw89_mac_read_phycap(struct rtw89_dev *rtwdev, struct rtw89_mac_c2h_info *c2h_info) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; struct rtw89_mac_h2c_info h2c_info = {0}; u32 ret; + mac->cnv_efuse_state(rtwdev, false); + h2c_info.id = RTW89_FWCMD_H2CREG_FUNC_GET_FEATURE; h2c_info.content_len = 0; ret = rtw89_fw_msg_reg(rtwdev, &h2c_info, c2h_info); if (ret) - return ret; + goto out; if (c2h_info->id != RTW89_FWCMD_C2HREG_FUNC_PHY_CAP) - return -EINVAL; + ret = -EINVAL; - return 0; +out: + mac->cnv_efuse_state(rtwdev, true); + + return ret; } int rtw89_mac_setup_phycap(struct rtw89_dev *rtwdev) @@ -5775,6 +5782,9 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = { .fwdl_enable_wcpu = rtw89_mac_enable_cpu_ax, .fwdl_get_status = rtw89_fw_get_rdy_ax, .fwdl_check_path_ready = rtw89_fwdl_check_path_ready_ax, + .parse_efuse_map = rtw89_parse_efuse_map_ax, + .parse_phycap_map = rtw89_parse_phycap_map_ax, + .cnv_efuse_state = rtw89_cnv_efuse_state_ax, .get_txpwr_cr = rtw89_mac_get_txpwr_cr_ax, }; diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index c11c904f87fe2..f47a42387a6a6 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -10,6 +10,7 @@ #define MAC_MEM_DUMP_PAGE_SIZE 0x40000 #define ADDR_CAM_ENT_SIZE 0x40 +#define ADDR_CAM_ENT_SHORT_SIZE 0x20 #define BSSID_CAM_ENT_SIZE 0x08 #define HFC_PAGE_UNIT 64 #define RPWM_TRY_CNT 3 @@ -872,6 +873,9 @@ struct rtw89_mac_gen_def { bool dlfw, bool include_bb); u8 (*fwdl_get_status)(struct rtw89_dev *rtwdev, enum rtw89_fwdl_check_type type); int (*fwdl_check_path_ready)(struct rtw89_dev *rtwdev, bool h2c_or_fwdl); + int (*parse_efuse_map)(struct rtw89_dev *rtwdev); + int (*parse_phycap_map)(struct rtw89_dev *rtwdev); + int (*cnv_efuse_state)(struct rtw89_dev *rtwdev, bool idle); bool (*get_txpwr_cr)(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index 3278f241db6e5..1c607316f6525 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -3,6 +3,7 @@ */ #include "debug.h" +#include "efuse.h" #include "fw.h" #include "mac.h" #include "reg.h" @@ -429,6 +430,9 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = { .fwdl_enable_wcpu = rtw89_mac_fwdl_enable_wcpu_be, .fwdl_get_status = fwdl_get_status_be, .fwdl_check_path_ready = rtw89_fwdl_check_path_ready_be, + .parse_efuse_map = rtw89_parse_efuse_map_be, + .parse_phycap_map = rtw89_parse_phycap_map_be, + .cnv_efuse_state = rtw89_cnv_efuse_state_be, .get_txpwr_cr = rtw89_mac_get_txpwr_cr_be, }; diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index 14ddb0d39e637..0ca07ae63594a 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -19,28 +19,25 @@ MODULE_PARM_DESC(disable_clkreq, "Set Y to disable PCI clkreq support"); MODULE_PARM_DESC(disable_aspm_l1, "Set Y to disable PCI ASPM L1 support"); MODULE_PARM_DESC(disable_aspm_l1ss, "Set Y to disable PCI L1SS support"); -static int rtw89_pci_rst_bdram_pcie(struct rtw89_dev *rtwdev) +static int rtw89_pci_rst_bdram_ax(struct rtw89_dev *rtwdev) { u32 val; int ret; - rtw89_write32(rtwdev, R_AX_PCIE_INIT_CFG1, - rtw89_read32(rtwdev, R_AX_PCIE_INIT_CFG1) | B_AX_RST_BDRAM); + rtw89_write32_set(rtwdev, R_AX_PCIE_INIT_CFG1, B_AX_RST_BDRAM); ret = read_poll_timeout_atomic(rtw89_read32, val, !(val & B_AX_RST_BDRAM), 1, RTW89_PCI_POLL_BDRAM_RST_CNT, false, rtwdev, R_AX_PCIE_INIT_CFG1); - if (ret) - return -EBUSY; - - return 0; + return ret; } static u32 rtw89_pci_dma_recalc(struct rtw89_dev *rtwdev, struct rtw89_pci_dma_ring *bd_ring, u32 cur_idx, bool tx) { + const struct rtw89_pci_info *info = rtwdev->pci_info; u32 cnt, cur_rp, wp, rp, len; rp = bd_ring->rp; @@ -48,10 +45,14 @@ static u32 rtw89_pci_dma_recalc(struct rtw89_dev *rtwdev, len = bd_ring->len; cur_rp = FIELD_GET(TXBD_HW_IDX_MASK, cur_idx); - if (tx) + if (tx) { cnt = cur_rp >= rp ? cur_rp - rp : len - (rp - cur_rp); - else + } else { + if (info->rx_ring_eq_is_full) + wp += 1; + cnt = cur_rp >= wp ? cur_rp - wp : len - (wp - cur_rp); + } bd_ring->rp = cur_rp; @@ -226,6 +227,21 @@ rtw89_skb_put_rx_data(struct rtw89_dev *rtwdev, bool fs, bool ls, return true; } +static u32 rtw89_pci_get_rx_skb_idx(struct rtw89_dev *rtwdev, + struct rtw89_pci_dma_ring *bd_ring) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + u32 wp = bd_ring->wp; + + if (!info->rx_ring_eq_is_full) + return wp; + + if (++wp >= bd_ring->len) + wp = 0; + + return wp; +} + static u32 rtw89_pci_rxbd_deliver_skbs(struct rtw89_dev *rtwdev, struct rtw89_pci_rx_ring *rx_ring) { @@ -235,12 +251,14 @@ static u32 rtw89_pci_rxbd_deliver_skbs(struct rtw89_dev *rtwdev, struct sk_buff *new = rx_ring->diliver_skb; struct sk_buff *skb; u32 rxinfo_size = sizeof(struct rtw89_pci_rxbd_info); + u32 skb_idx; u32 offset; u32 cnt = 1; bool fs, ls; int ret; - skb = rx_ring->buf[bd_ring->wp]; + skb_idx = rtw89_pci_get_rx_skb_idx(rtwdev, bd_ring); + skb = rx_ring->buf[skb_idx]; rtw89_pci_sync_skb_for_cpu(rtwdev, skb); ret = rtw89_pci_rxbd_info_update(rtwdev, skb); @@ -525,10 +543,12 @@ static u32 rtw89_pci_release_tx_skbs(struct rtw89_dev *rtwdev, u32 cnt = 0; u32 rpp_size = sizeof(struct rtw89_pci_rpp_fmt); u32 rxinfo_size = sizeof(struct rtw89_pci_rxbd_info); + u32 skb_idx; u32 offset; int ret; - skb = rx_ring->buf[bd_ring->wp]; + skb_idx = rtw89_pci_get_rx_skb_idx(rtwdev, bd_ring); + skb = rx_ring->buf[skb_idx]; rtw89_pci_sync_skb_for_cpu(rtwdev, skb); ret = rtw89_pci_rxbd_info_update(rtwdev, skb); @@ -676,11 +696,26 @@ void rtw89_pci_recognize_intrs_v1(struct rtw89_dev *rtwdev, } EXPORT_SYMBOL(rtw89_pci_recognize_intrs_v1); -static void rtw89_pci_clear_isr0(struct rtw89_dev *rtwdev, u32 isr00) +void rtw89_pci_recognize_intrs_v2(struct rtw89_dev *rtwdev, + struct rtw89_pci *rtwpci, + struct rtw89_pci_isrs *isrs) { - /* write 1 clear */ - rtw89_write32(rtwdev, R_AX_PCIE_HISR00, isr00); + isrs->ind_isrs = rtw89_read32(rtwdev, R_BE_PCIE_HISR) & rtwpci->ind_intrs; + isrs->halt_c2h_isrs = isrs->ind_isrs & B_BE_HS0ISR_IND_INT ? + rtw89_read32(rtwdev, R_BE_HISR0) & rtwpci->halt_c2h_intrs : 0; + isrs->isrs[0] = isrs->ind_isrs & B_BE_HCI_AXIDMA_INT ? + rtw89_read32(rtwdev, R_BE_HAXI_HISR00) & rtwpci->intrs[0] : 0; + isrs->isrs[1] = rtw89_read32(rtwdev, R_BE_PCIE_DMA_ISR); + + if (isrs->halt_c2h_isrs) + rtw89_write32(rtwdev, R_BE_HISR0, isrs->halt_c2h_isrs); + if (isrs->isrs[0]) + rtw89_write32(rtwdev, R_BE_HAXI_HISR00, isrs->isrs[0]); + if (isrs->isrs[1]) + rtw89_write32(rtwdev, R_BE_PCIE_DMA_ISR, isrs->isrs[1]); + rtw89_write32(rtwdev, R_BE_PCIE_HISR, isrs->ind_isrs); } +EXPORT_SYMBOL(rtw89_pci_recognize_intrs_v2); void rtw89_pci_enable_intr(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci) { @@ -713,6 +748,22 @@ void rtw89_pci_disable_intr_v1(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpc } EXPORT_SYMBOL(rtw89_pci_disable_intr_v1); +void rtw89_pci_enable_intr_v2(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci) +{ + rtw89_write32(rtwdev, R_BE_HIMR0, rtwpci->halt_c2h_intrs); + rtw89_write32(rtwdev, R_BE_HAXI_HIMR00, rtwpci->intrs[0]); + rtw89_write32(rtwdev, R_BE_PCIE_DMA_IMR_0_V1, rtwpci->intrs[1]); + rtw89_write32(rtwdev, R_BE_PCIE_HIMR0, rtwpci->ind_intrs); +} +EXPORT_SYMBOL(rtw89_pci_enable_intr_v2); + +void rtw89_pci_disable_intr_v2(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci) +{ + rtw89_write32(rtwdev, R_BE_PCIE_HIMR0, 0); + rtw89_write32(rtwdev, R_BE_PCIE_DMA_IMR_0_V1, 0); +} +EXPORT_SYMBOL(rtw89_pci_disable_intr_v2); + static void rtw89_pci_ops_recovery_start(struct rtw89_dev *rtwdev) { struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; @@ -753,6 +804,8 @@ static irqreturn_t rtw89_pci_interrupt_threadfn(int irq, void *dev) { struct rtw89_dev *rtwdev = dev; struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_pci_gen_def *gen_def = info->gen_def; struct rtw89_pci_isrs isrs; unsigned long flags; @@ -760,13 +813,13 @@ static irqreturn_t rtw89_pci_interrupt_threadfn(int irq, void *dev) rtw89_chip_recognize_intrs(rtwdev, rtwpci, &isrs); spin_unlock_irqrestore(&rtwpci->irq_lock, flags); - if (unlikely(isrs.isrs[0] & B_AX_RDU_INT)) + if (unlikely(isrs.isrs[0] & gen_def->isr_rdu)) rtw89_pci_isr_rxd_unavail(rtwdev, rtwpci); - if (unlikely(isrs.halt_c2h_isrs & B_AX_HALT_C2H_INT_EN)) + if (unlikely(isrs.halt_c2h_isrs & gen_def->isr_halt_c2h)) rtw89_ser_notify(rtwdev, rtw89_mac_get_err_status(rtwdev)); - if (unlikely(isrs.halt_c2h_isrs & B_AX_WDT_TIMEOUT_INT_EN)) + if (unlikely(isrs.halt_c2h_isrs & gen_def->isr_wdt_timeout)) rtw89_ser_notify(rtwdev, MAC_AX_ERR_L2_ERR_WDT_TIMEOUT_INT); if (unlikely(rtwpci->under_recovery)) @@ -817,6 +870,15 @@ static irqreturn_t rtw89_pci_interrupt_handler(int irq, void *dev) return irqret; } +#define DEF_TXCHADDRS_TYPE2(gen, ch_idx, txch, v...) \ + [RTW89_TXCH_##ch_idx] = { \ + .num = R_##gen##_##txch##_TXBD_NUM ##v, \ + .idx = R_##gen##_##txch##_TXBD_IDX ##v, \ + .bdram = 0, \ + .desa_l = R_##gen##_##txch##_TXBD_DESA_L ##v, \ + .desa_h = R_##gen##_##txch##_TXBD_DESA_H ##v, \ + } + #define DEF_TXCHADDRS_TYPE1(info, txch, v...) \ [RTW89_TXCH_##txch] = { \ .num = R_AX_##txch##_TXBD_NUM ##v, \ @@ -835,12 +897,12 @@ static irqreturn_t rtw89_pci_interrupt_handler(int irq, void *dev) .desa_h = R_AX_##txch##_TXBD_DESA_H ##v, \ } -#define DEF_RXCHADDRS(info, rxch, v...) \ - [RTW89_RXCH_##rxch] = { \ - .num = R_AX_##rxch##_RXBD_NUM ##v, \ - .idx = R_AX_##rxch##_RXBD_IDX ##v, \ - .desa_l = R_AX_##rxch##_RXBD_DESA_L ##v, \ - .desa_h = R_AX_##rxch##_RXBD_DESA_H ##v, \ +#define DEF_RXCHADDRS(gen, ch_idx, rxch, v...) \ + [RTW89_RXCH_##ch_idx] = { \ + .num = R_##gen##_##rxch##_RXBD_NUM ##v, \ + .idx = R_##gen##_##rxch##_RXBD_IDX ##v, \ + .desa_l = R_##gen##_##rxch##_RXBD_DESA_L ##v, \ + .desa_h = R_##gen##_##rxch##_RXBD_DESA_H ##v, \ } const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set = { @@ -860,8 +922,8 @@ const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set = { DEF_TXCHADDRS(info, CH12), }, .rx = { - DEF_RXCHADDRS(info, RXQ), - DEF_RXCHADDRS(info, RPQ), + DEF_RXCHADDRS(AX, RXQ, RXQ), + DEF_RXCHADDRS(AX, RPQ, RPQ), }, }; EXPORT_SYMBOL(rtw89_pci_ch_dma_addr_set); @@ -883,12 +945,35 @@ const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_v1 = { DEF_TXCHADDRS(info, CH12, _V1), }, .rx = { - DEF_RXCHADDRS(info, RXQ, _V1), - DEF_RXCHADDRS(info, RPQ, _V1), + DEF_RXCHADDRS(AX, RXQ, RXQ, _V1), + DEF_RXCHADDRS(AX, RPQ, RPQ, _V1), }, }; EXPORT_SYMBOL(rtw89_pci_ch_dma_addr_set_v1); +const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_be = { + .tx = { + DEF_TXCHADDRS_TYPE2(BE, ACH0, CH0, _V1), + DEF_TXCHADDRS_TYPE2(BE, ACH1, CH1, _V1), + DEF_TXCHADDRS_TYPE2(BE, ACH2, CH2, _V1), + DEF_TXCHADDRS_TYPE2(BE, ACH3, CH3, _V1), + DEF_TXCHADDRS_TYPE2(BE, ACH4, CH4, _V1), + DEF_TXCHADDRS_TYPE2(BE, ACH5, CH5, _V1), + DEF_TXCHADDRS_TYPE2(BE, ACH6, CH6, _V1), + DEF_TXCHADDRS_TYPE2(BE, ACH7, CH7, _V1), + DEF_TXCHADDRS_TYPE2(BE, CH8, CH8, _V1), + DEF_TXCHADDRS_TYPE2(BE, CH9, CH9, _V1), + DEF_TXCHADDRS_TYPE2(BE, CH10, CH10, _V1), + DEF_TXCHADDRS_TYPE2(BE, CH11, CH11, _V1), + DEF_TXCHADDRS_TYPE2(BE, CH12, CH12, _V1), + }, + .rx = { + DEF_RXCHADDRS(BE, RXQ, RXQ0, _V1), + DEF_RXCHADDRS(BE, RPQ, RPQ0, _V1), + }, +}; +EXPORT_SYMBOL(rtw89_pci_ch_dma_addr_set_be); + #undef DEF_TXCHADDRS_TYPE1 #undef DEF_TXCHADDRS #undef DEF_RXCHADDRS @@ -1422,6 +1507,7 @@ static void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev) struct rtw89_pci_dma_ring *bd_ring; const struct rtw89_pci_bd_ram *bd_ram; u32 addr_num; + u32 addr_idx; u32 addr_bdram; u32 addr_desa_l; u32 val32; @@ -1433,19 +1519,21 @@ static void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev) tx_ring = &rtwpci->tx_rings[i]; bd_ring = &tx_ring->bd_ring; - bd_ram = &bd_ram_table[i]; + bd_ram = bd_ram_table ? &bd_ram_table[i] : NULL; addr_num = bd_ring->addr.num; addr_bdram = bd_ring->addr.bdram; addr_desa_l = bd_ring->addr.desa_l; bd_ring->wp = 0; bd_ring->rp = 0; - val32 = FIELD_PREP(BDRAM_SIDX_MASK, bd_ram->start_idx) | - FIELD_PREP(BDRAM_MAX_MASK, bd_ram->max_num) | - FIELD_PREP(BDRAM_MIN_MASK, bd_ram->min_num); - rtw89_write16(rtwdev, addr_num, bd_ring->len); - rtw89_write32(rtwdev, addr_bdram, val32); + if (addr_bdram && bd_ram) { + val32 = FIELD_PREP(BDRAM_SIDX_MASK, bd_ram->start_idx) | + FIELD_PREP(BDRAM_MAX_MASK, bd_ram->max_num) | + FIELD_PREP(BDRAM_MIN_MASK, bd_ram->min_num); + + rtw89_write32(rtwdev, addr_bdram, val32); + } rtw89_write32(rtwdev, addr_desa_l, bd_ring->dma); } @@ -1453,14 +1541,21 @@ static void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev) rx_ring = &rtwpci->rx_rings[i]; bd_ring = &rx_ring->bd_ring; addr_num = bd_ring->addr.num; + addr_idx = bd_ring->addr.idx; addr_desa_l = bd_ring->addr.desa_l; - bd_ring->wp = 0; + if (info->rx_ring_eq_is_full) + bd_ring->wp = bd_ring->len - 1; + else + bd_ring->wp = 0; bd_ring->rp = 0; rx_ring->diliver_skb = NULL; rx_ring->diliver_desc.ready = false; rtw89_write16(rtwdev, addr_num, bd_ring->len); rtw89_write32(rtwdev, addr_desa_l, bd_ring->dma); + + if (info->rx_ring_eq_is_full) + rtw89_write16(rtwdev, addr_idx, bd_ring->wp); } } @@ -1471,7 +1566,7 @@ static void rtw89_pci_release_tx_ring(struct rtw89_dev *rtwdev, rtw89_pci_release_pending_txwd_skb(rtwdev, tx_ring); } -static void rtw89_pci_ops_reset(struct rtw89_dev *rtwdev) +void rtw89_pci_ops_reset(struct rtw89_dev *rtwdev) { struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; const struct rtw89_pci_info *info = rtwdev->pci_info; @@ -1684,24 +1779,16 @@ static void rtw89_pci_ctrl_dma_trx(struct rtw89_dev *rtwdev, bool enable) static void rtw89_pci_ctrl_dma_io(struct rtw89_dev *rtwdev, bool enable) { - enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; - u32 reg, mask; - - if (chip_id == RTL8852C) { - reg = R_AX_HAXI_INIT_CFG1; - mask = B_AX_STOP_AXI_MST; - } else { - reg = R_AX_PCIE_DMA_STOP1; - mask = B_AX_STOP_PCIEIO; - } + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_reg_def *reg = &info->dma_io_stop; if (enable) - rtw89_write32_clr(rtwdev, reg, mask); + rtw89_write32_clr(rtwdev, reg->addr, reg->mask); else - rtw89_write32_set(rtwdev, reg, mask); + rtw89_write32_set(rtwdev, reg->addr, reg->mask); } -static void rtw89_pci_ctrl_dma_all(struct rtw89_dev *rtwdev, bool enable) +void rtw89_pci_ctrl_dma_all(struct rtw89_dev *rtwdev, bool enable) { rtw89_pci_ctrl_dma_io(rtwdev, enable); rtw89_pci_ctrl_dma_trx(rtwdev, enable); @@ -2303,7 +2390,7 @@ static void rtw89_pci_set_keep_reg(struct rtw89_dev *rtwdev) B_AX_PCIE_TXRST_KEEP_REG | B_AX_PCIE_RXRST_KEEP_REG); } -static void rtw89_pci_clr_idx_all(struct rtw89_dev *rtwdev) +static void rtw89_pci_clr_idx_all_ax(struct rtw89_dev *rtwdev) { const struct rtw89_pci_info *info = rtwdev->pci_info; enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; @@ -2491,7 +2578,7 @@ static int rtw89_pci_ops_deinit(struct rtw89_dev *rtwdev) return 0; } -static int rtw89_pci_ops_mac_pre_init(struct rtw89_dev *rtwdev) +static int rtw89_pci_ops_mac_pre_init_ax(struct rtw89_dev *rtwdev) { const struct rtw89_pci_info *info = rtwdev->pci_info; int ret; @@ -2550,7 +2637,7 @@ static int rtw89_pci_ops_mac_pre_init(struct rtw89_dev *rtwdev) /* fill TRX BD indexes */ rtw89_pci_ops_reset(rtwdev); - ret = rtw89_pci_rst_bdram_pcie(rtwdev); + ret = rtw89_pci_rst_bdram_ax(rtwdev); if (ret) { rtw89_warn(rtwdev, "reset bdram busy\n"); return ret; @@ -2648,7 +2735,7 @@ int rtw89_pci_ltr_set_v1(struct rtw89_dev *rtwdev, bool en) } EXPORT_SYMBOL(rtw89_pci_ltr_set_v1); -static int rtw89_pci_ops_mac_post_init(struct rtw89_dev *rtwdev) +static int rtw89_pci_ops_mac_post_init_ax(struct rtw89_dev *rtwdev) { const struct rtw89_pci_info *info = rtwdev->pci_info; enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; @@ -3026,6 +3113,7 @@ static int rtw89_pci_alloc_rx_ring(struct rtw89_dev *rtwdev, struct rtw89_pci_rx_ring *rx_ring, u32 desc_size, u32 len, u32 rxch) { + const struct rtw89_pci_info *info = rtwdev->pci_info; const struct rtw89_pci_ch_dma_addr *rxch_addr; struct sk_buff *skb; u8 *head; @@ -3052,7 +3140,10 @@ static int rtw89_pci_alloc_rx_ring(struct rtw89_dev *rtwdev, rx_ring->bd_ring.len = len; rx_ring->bd_ring.desc_size = desc_size; rx_ring->bd_ring.addr = *rxch_addr; - rx_ring->bd_ring.wp = 0; + if (info->rx_ring_eq_is_full) + rx_ring->bd_ring.wp = len - 1; + else + rx_ring->bd_ring.wp = 0; rx_ring->bd_ring.rp = 0; rx_ring->buf_sz = buf_sz; rx_ring->diliver_skb = NULL; @@ -3289,6 +3380,55 @@ void rtw89_pci_config_intr_mask_v1(struct rtw89_dev *rtwdev) } EXPORT_SYMBOL(rtw89_pci_config_intr_mask_v1); +static void rtw89_pci_recovery_intr_mask_v2(struct rtw89_dev *rtwdev) +{ + struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + + rtwpci->ind_intrs = B_BE_HS0_IND_INT_EN0; + rtwpci->halt_c2h_intrs = B_BE_HALT_C2H_INT_EN | B_BE_WDT_TIMEOUT_INT_EN; + rtwpci->intrs[0] = 0; + rtwpci->intrs[1] = B_BE_PCIE_RX_RX0P2_IMR0_V1 | + B_BE_PCIE_RX_RPQ0_IMR0_V1; +} + +static void rtw89_pci_default_intr_mask_v2(struct rtw89_dev *rtwdev) +{ + struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + + rtwpci->ind_intrs = B_BE_HCI_AXIDMA_INT_EN0 | + B_BE_HS0_IND_INT_EN0; + rtwpci->halt_c2h_intrs = B_BE_HALT_C2H_INT_EN | B_BE_WDT_TIMEOUT_INT_EN; + rtwpci->intrs[0] = B_BE_RDU_CH1_INT_IMR_V1 | + B_BE_RDU_CH0_INT_IMR_V1; + rtwpci->intrs[1] = B_BE_PCIE_RX_RX0P2_IMR0_V1 | + B_BE_PCIE_RX_RPQ0_IMR0_V1; +} + +static void rtw89_pci_low_power_intr_mask_v2(struct rtw89_dev *rtwdev) +{ + struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + + rtwpci->ind_intrs = B_BE_HS0_IND_INT_EN0 | + B_BE_HS1_IND_INT_EN0; + rtwpci->halt_c2h_intrs = B_BE_HALT_C2H_INT_EN | B_BE_WDT_TIMEOUT_INT_EN; + rtwpci->intrs[0] = 0; + rtwpci->intrs[1] = B_BE_PCIE_RX_RX0P2_IMR0_V1 | + B_BE_PCIE_RX_RPQ0_IMR0_V1; +} + +void rtw89_pci_config_intr_mask_v2(struct rtw89_dev *rtwdev) +{ + struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + + if (rtwpci->under_recovery) + rtw89_pci_recovery_intr_mask_v2(rtwdev); + else if (rtwpci->low_power) + rtw89_pci_low_power_intr_mask_v2(rtwdev); + else + rtw89_pci_default_intr_mask_v2(rtwdev); +} +EXPORT_SYMBOL(rtw89_pci_config_intr_mask_v2); + static int rtw89_pci_request_irq(struct rtw89_dev *rtwdev, struct pci_dev *pdev) { @@ -3480,19 +3620,27 @@ static void rtw89_pci_aspm_set(struct rtw89_dev *rtwdev, bool enable) static void rtw89_pci_recalc_int_mit(struct rtw89_dev *rtwdev) { + enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen; + const struct rtw89_pci_info *info = rtwdev->pci_info; struct rtw89_traffic_stats *stats = &rtwdev->stats; enum rtw89_tfc_lv tx_tfc_lv = stats->tx_tfc_lv; enum rtw89_tfc_lv rx_tfc_lv = stats->rx_tfc_lv; u32 val = 0; - if (!rtwdev->scanning && - (tx_tfc_lv >= RTW89_TFC_HIGH || rx_tfc_lv >= RTW89_TFC_HIGH)) + if (rtwdev->scanning || + (tx_tfc_lv < RTW89_TFC_HIGH && rx_tfc_lv < RTW89_TFC_HIGH)) + goto out; + + if (chip_gen == RTW89_CHIP_BE) + val = B_BE_PCIE_MIT_RX0P2_EN | B_BE_PCIE_MIT_RX0P1_EN; + else val = B_AX_RXMIT_RXP2_SEL | B_AX_RXMIT_RXP1_SEL | FIELD_PREP(B_AX_RXCOUNTER_MATCH_MASK, RTW89_PCI_RXBD_NUM_MAX / 2) | FIELD_PREP(B_AX_RXTIMER_UNIT_MASK, AX_RXTIMER_UNIT_64US) | FIELD_PREP(B_AX_RXTIMER_MATCH_MASK, 2048 / 64); - rtw89_write32(rtwdev, R_AX_INT_MIT_RX, val); +out: + rtw89_write32(rtwdev, info->mit_addr, val); } static void rtw89_pci_link_cfg(struct rtw89_dev *rtwdev) @@ -3582,7 +3730,7 @@ static void rtw89_pci_l1ss_cfg(struct rtw89_dev *rtwdev) rtw89_pci_l1ss_set(rtwdev, true); } -static int rtw89_pci_poll_io_idle(struct rtw89_dev *rtwdev) +static int rtw89_pci_poll_io_idle_ax(struct rtw89_dev *rtwdev) { int ret = 0; u32 sts; @@ -3599,7 +3747,7 @@ static int rtw89_pci_poll_io_idle(struct rtw89_dev *rtwdev) return ret; } -static int rtw89_pci_lv1rst_stop_dma(struct rtw89_dev *rtwdev) +static int rtw89_pci_lv1rst_stop_dma_ax(struct rtw89_dev *rtwdev) { u32 val; int ret; @@ -3608,7 +3756,7 @@ static int rtw89_pci_lv1rst_stop_dma(struct rtw89_dev *rtwdev) return 0; rtw89_pci_ctrl_dma_all(rtwdev, false); - ret = rtw89_pci_poll_io_idle(rtwdev); + ret = rtw89_pci_poll_io_idle_ax(rtwdev); if (ret) { val = rtw89_read32(rtwdev, R_AX_DBG_ERR_FLAG); rtw89_debug(rtwdev, RTW89_DBG_HCI, @@ -3619,7 +3767,7 @@ static int rtw89_pci_lv1rst_stop_dma(struct rtw89_dev *rtwdev) if (val & B_AX_RX_STUCK) rtw89_mac_ctrl_hci_dma_rx(rtwdev, false); rtw89_mac_ctrl_hci_dma_trx(rtwdev, true); - ret = rtw89_pci_poll_io_idle(rtwdev); + ret = rtw89_pci_poll_io_idle_ax(rtwdev); val = rtw89_read32(rtwdev, R_AX_DBG_ERR_FLAG); rtw89_debug(rtwdev, RTW89_DBG_HCI, "[PCIe] poll_io_idle fail, after 0x%08x: 0x%08x\n", @@ -3629,23 +3777,7 @@ static int rtw89_pci_lv1rst_stop_dma(struct rtw89_dev *rtwdev) return ret; } - - -static int rtw89_pci_rst_bdram(struct rtw89_dev *rtwdev) -{ - int ret = 0; - u32 val32, sts; - - val32 = B_AX_RST_BDRAM; - rtw89_write32_set(rtwdev, R_AX_PCIE_INIT_CFG1, val32); - - ret = read_poll_timeout_atomic(rtw89_read32, sts, - (sts & B_AX_RST_BDRAM) == 0x0, 1, 100, - true, rtwdev, R_AX_PCIE_INIT_CFG1); - return ret; -} - -static int rtw89_pci_lv1rst_start_dma(struct rtw89_dev *rtwdev) +static int rtw89_pci_lv1rst_start_dma_ax(struct rtw89_dev *rtwdev) { u32 ret; @@ -3656,7 +3788,7 @@ static int rtw89_pci_lv1rst_start_dma(struct rtw89_dev *rtwdev) rtw89_mac_ctrl_hci_dma_trx(rtwdev, true); rtw89_pci_clr_idx_all(rtwdev); - ret = rtw89_pci_rst_bdram(rtwdev); + ret = rtw89_pci_rst_bdram_ax(rtwdev); if (ret) return ret; @@ -3667,18 +3799,20 @@ static int rtw89_pci_lv1rst_start_dma(struct rtw89_dev *rtwdev) static int rtw89_pci_ops_mac_lv1_recovery(struct rtw89_dev *rtwdev, enum rtw89_lv1_rcvy_step step) { + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_pci_gen_def *gen_def = info->gen_def; int ret; switch (step) { case RTW89_LV1_RCVY_STEP_1: - ret = rtw89_pci_lv1rst_stop_dma(rtwdev); + ret = gen_def->lv1rst_stop_dma(rtwdev); if (ret) rtw89_err(rtwdev, "lv1 rcvy pci stop dma fail\n"); break; case RTW89_LV1_RCVY_STEP_2: - ret = rtw89_pci_lv1rst_start_dma(rtwdev); + ret = gen_def->lv1rst_start_dma(rtwdev); if (ret) rtw89_err(rtwdev, "lv1 rcvy pci start dma fail\n"); break; @@ -3704,17 +3838,19 @@ static int rtw89_pci_napi_poll(struct napi_struct *napi, int budget) { struct rtw89_dev *rtwdev = container_of(napi, struct rtw89_dev, napi); struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_pci_gen_def *gen_def = info->gen_def; unsigned long flags; int work_done; rtwdev->napi_budget_countdown = budget; - rtw89_pci_clear_isr0(rtwdev, B_AX_RPQDMA_INT | B_AX_RPQBD_FULL_INT); + rtw89_write32(rtwdev, gen_def->isr_clear_rpq.addr, gen_def->isr_clear_rpq.data); work_done = rtw89_pci_poll_rpq_dma(rtwdev, rtwpci, rtwdev->napi_budget_countdown); if (work_done == budget) return budget; - rtw89_pci_clear_isr0(rtwdev, B_AX_RXP1DMA_INT | B_AX_RXDMA_INT | B_AX_RDU_INT); + rtw89_write32(rtwdev, gen_def->isr_clear_rxq.addr, gen_def->isr_clear_rxq.data); work_done += rtw89_pci_poll_rxq_dma(rtwdev, rtwpci, rtwdev->napi_budget_countdown); if (work_done < budget && napi_complete_done(napi, work_done)) { spin_lock_irqsave(&rtwpci->irq_lock, flags); @@ -3791,6 +3927,26 @@ static int __maybe_unused rtw89_pci_resume(struct device *dev) SIMPLE_DEV_PM_OPS(rtw89_pm_ops, rtw89_pci_suspend, rtw89_pci_resume); EXPORT_SYMBOL(rtw89_pm_ops); +const struct rtw89_pci_gen_def rtw89_pci_gen_ax = { + .isr_rdu = B_AX_RDU_INT, + .isr_halt_c2h = B_AX_HALT_C2H_INT_EN, + .isr_wdt_timeout = B_AX_WDT_TIMEOUT_INT_EN, + .isr_clear_rpq = {R_AX_PCIE_HISR00, B_AX_RPQDMA_INT | B_AX_RPQBD_FULL_INT}, + .isr_clear_rxq = {R_AX_PCIE_HISR00, B_AX_RXP1DMA_INT | B_AX_RXDMA_INT | + B_AX_RDU_INT}, + + .mac_pre_init = rtw89_pci_ops_mac_pre_init_ax, + .mac_pre_deinit = NULL, + .mac_post_init = rtw89_pci_ops_mac_post_init_ax, + + .clr_idx_all = rtw89_pci_clr_idx_all_ax, + .rst_bdram = rtw89_pci_rst_bdram_ax, + + .lv1rst_stop_dma = rtw89_pci_lv1rst_stop_dma_ax, + .lv1rst_start_dma = rtw89_pci_lv1rst_start_dma_ax, +}; +EXPORT_SYMBOL(rtw89_pci_gen_ax); + static const struct rtw89_hci_ops rtw89_pci_ops = { .tx_write = rtw89_pci_ops_tx_write, .tx_kick_off = rtw89_pci_ops_tx_kick_off, @@ -3810,6 +3966,7 @@ static const struct rtw89_hci_ops rtw89_pci_ops = { .write32 = rtw89_pci_ops_write32, .mac_pre_init = rtw89_pci_ops_mac_pre_init, + .mac_pre_deinit = rtw89_pci_ops_mac_pre_deinit, .mac_post_init = rtw89_pci_ops_mac_post_init, .deinit = rtw89_pci_ops_deinit, @@ -3829,7 +3986,7 @@ static const struct rtw89_hci_ops rtw89_pci_ops = { .clear = rtw89_pci_clear_resource, .disable_intr = rtw89_pci_disable_intr_lock, .enable_intr = rtw89_pci_enable_intr_lock, - .rst_bdram = rtw89_pci_rst_bdram_pcie, + .rst_bdram = rtw89_pci_reset_bdram, }; int rtw89_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index 2f3d1ad3b0f7d..e2d8eef52b20e 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -245,6 +245,203 @@ #define B_AX_HS1ISR_IND_INT BIT(25) #define B_AX_PCIE_DBG_STE_INT BIT(13) +#define R_BE_PCIE_FRZ_CLK 0x3004 +#define B_BE_PCIE_FRZ_MAC_HW_RST BIT(31) +#define B_BE_PCIE_FRZ_CFG_SPC_RST BIT(30) +#define B_BE_PCIE_FRZ_ELBI_RST BIT(29) +#define B_BE_PCIE_MAC_IS_ACTIVE BIT(28) +#define B_BE_PCIE_FRZ_RTK_HW_RST BIT(27) +#define B_BE_PCIE_FRZ_REG_RST BIT(26) +#define B_BE_PCIE_FRZ_ANA_RST BIT(25) +#define B_BE_PCIE_FRZ_WLAN_RST BIT(24) +#define B_BE_PCIE_FRZ_FLR_RST BIT(23) +#define B_BE_PCIE_FRZ_RET_NON_STKY_RST BIT(22) +#define B_BE_PCIE_FRZ_RET_STKY_RST BIT(21) +#define B_BE_PCIE_FRZ_NON_STKY_RST BIT(20) +#define B_BE_PCIE_FRZ_STKY_RST BIT(19) +#define B_BE_PCIE_FRZ_RET_CORE_RST BIT(18) +#define B_BE_PCIE_FRZ_PWR_RST BIT(17) +#define B_BE_PCIE_FRZ_PERST_RST BIT(16) +#define B_BE_PCIE_FRZ_PHY_ALOAD BIT(15) +#define B_BE_PCIE_FRZ_PHY_HW_RST BIT(14) +#define B_BE_PCIE_DBG_CLK BIT(4) +#define B_BE_PCIE_EN_CLK BIT(3) +#define B_BE_PCIE_DBI_ACLK_ACT BIT(2) +#define B_BE_PCIE_S1_ACLK_ACT BIT(1) +#define B_BE_PCIE_EN_AUX_CLK BIT(0) + +#define R_BE_PCIE_PS_CTRL 0x3008 +#define B_BE_RSM_L0S_EN BIT(8) +#define B_BE_CMAC_EXIT_L1_EN BIT(7) +#define B_BE_DMAC0_EXIT_L1_EN BIT(6) +#define B_BE_FORCE_L0 BIT(5) +#define B_BE_DBI_RO_WR_DISABLE BIT(4) +#define B_BE_SEL_XFER_PENDING BIT(3) +#define B_BE_SEL_REQ_ENTR_L1 BIT(2) +#define B_BE_PCIE_EN_SWENT_L23 BIT(1) +#define B_BE_SEL_REQ_EXIT_L1 BIT(0) + +#define R_BE_PCIE_LAT_CTRL 0x3044 +#define B_BE_ELBI_PHY_REMAP_MASK GENMASK(29, 24) +#define B_BE_SYS_SUS_L12_EN BIT(17) +#define B_BE_MDIO_S_EN BIT(16) +#define B_BE_SYM_AUX_CLK_SEL BIT(15) +#define B_BE_RTK_LDO_POWER_LATENCY_MASK GENMASK(11, 10) +#define B_BE_RTK_LDO_BIAS_LATENCY_MASK GENMASK(9, 8) +#define B_BE_CLK_REQ_LAT_MASK GENMASK(7, 4) + +#define R_BE_PCIE_HIMR0 0x30B0 +#define B_BE_PCIE_HB1_IND_INTA_IMR BIT(31) +#define B_BE_PCIE_HB0_IND_INTA_IMR BIT(30) +#define B_BE_HCI_AXIDMA_INTA_IMR BIT(29) +#define B_BE_HC0_IND_INTA_IMR BIT(28) +#define B_BE_HD1_IND_INTA_IMR BIT(27) +#define B_BE_HD0_IND_INTA_IMR BIT(26) +#define B_BE_HS1_IND_INTA_IMR BIT(25) +#define B_BE_HS0_IND_INTA_IMR BIT(24) +#define B_BE_PCIE_HOTRST_INT_EN BIT(16) +#define B_BE_PCIE_FLR_INT_EN BIT(15) +#define B_BE_PCIE_PERST_INT_EN BIT(14) +#define B_BE_PCIE_DBG_STE_INT_EN BIT(13) +#define B_BE_HB1_IND_INT_EN0 BIT(9) +#define B_BE_HB0_IND_INT_EN0 BIT(8) +#define B_BE_HC1_IND_INT_EN0 BIT(7) +#define B_BE_HCI_AXIDMA_INT_EN0 BIT(5) +#define B_BE_HC0_IND_INT_EN0 BIT(4) +#define B_BE_HD1_IND_INT_EN0 BIT(3) +#define B_BE_HD0_IND_INT_EN0 BIT(2) +#define B_BE_HS1_IND_INT_EN0 BIT(1) +#define B_BE_HS0_IND_INT_EN0 BIT(0) + +#define R_BE_PCIE_HISR 0x30B4 +#define B_BE_PCIE_HOTRST_INT BIT(16) +#define B_BE_PCIE_FLR_INT BIT(15) +#define B_BE_PCIE_PERST_INT BIT(14) +#define B_BE_PCIE_DBG_STE_INT BIT(13) +#define B_BE_HB1IMR_IND BIT(9) +#define B_BE_HB0IMR_IND BIT(8) +#define B_BE_HC1ISR_IND_INT BIT(7) +#define B_BE_HCI_AXIDMA_INT BIT(5) +#define B_BE_HC0ISR_IND_INT BIT(4) +#define B_BE_HD1ISR_IND_INT BIT(3) +#define B_BE_HD0ISR_IND_INT BIT(2) +#define B_BE_HS1ISR_IND_INT BIT(1) +#define B_BE_HS0ISR_IND_INT BIT(0) + +#define R_BE_PCIE_DMA_IMR_0_V1 0x30B8 +#define B_BE_PCIE_RX_RX1P1_IMR0_V1 BIT(23) +#define B_BE_PCIE_RX_RX0P1_IMR0_V1 BIT(22) +#define B_BE_PCIE_RX_ROQ1_IMR0_V1 BIT(21) +#define B_BE_PCIE_RX_RPQ1_IMR0_V1 BIT(20) +#define B_BE_PCIE_RX_RX1P2_IMR0_V1 BIT(19) +#define B_BE_PCIE_RX_ROQ0_IMR0_V1 BIT(18) +#define B_BE_PCIE_RX_RPQ0_IMR0_V1 BIT(17) +#define B_BE_PCIE_RX_RX0P2_IMR0_V1 BIT(16) +#define B_BE_PCIE_TX_CH14_IMR0 BIT(14) +#define B_BE_PCIE_TX_CH13_IMR0 BIT(13) +#define B_BE_PCIE_TX_CH12_IMR0 BIT(12) +#define B_BE_PCIE_TX_CH11_IMR0 BIT(11) +#define B_BE_PCIE_TX_CH10_IMR0 BIT(10) +#define B_BE_PCIE_TX_CH9_IMR0 BIT(9) +#define B_BE_PCIE_TX_CH8_IMR0 BIT(8) +#define B_BE_PCIE_TX_CH7_IMR0 BIT(7) +#define B_BE_PCIE_TX_CH6_IMR0 BIT(6) +#define B_BE_PCIE_TX_CH5_IMR0 BIT(5) +#define B_BE_PCIE_TX_CH4_IMR0 BIT(4) +#define B_BE_PCIE_TX_CH3_IMR0 BIT(3) +#define B_BE_PCIE_TX_CH2_IMR0 BIT(2) +#define B_BE_PCIE_TX_CH1_IMR0 BIT(1) +#define B_BE_PCIE_TX_CH0_IMR0 BIT(0) + +#define R_BE_PCIE_DMA_ISR 0x30BC +#define B_BE_PCIE_RX_RX1P1_ISR_V1 BIT(23) +#define B_BE_PCIE_RX_RX0P1_ISR_V1 BIT(22) +#define B_BE_PCIE_RX_ROQ1_ISR_V1 BIT(21) +#define B_BE_PCIE_RX_RPQ1_ISR_V1 BIT(20) +#define B_BE_PCIE_RX_RX1P2_ISR_V1 BIT(19) +#define B_BE_PCIE_RX_ROQ0_ISR_V1 BIT(18) +#define B_BE_PCIE_RX_RPQ0_ISR_V1 BIT(17) +#define B_BE_PCIE_RX_RX0P2_ISR_V1 BIT(16) +#define B_BE_PCIE_TX_CH14_ISR BIT(14) +#define B_BE_PCIE_TX_CH13_ISR BIT(13) +#define B_BE_PCIE_TX_CH12_ISR BIT(12) +#define B_BE_PCIE_TX_CH11_ISR BIT(11) +#define B_BE_PCIE_TX_CH10_ISR BIT(10) +#define B_BE_PCIE_TX_CH9_ISR BIT(9) +#define B_BE_PCIE_TX_CH8_ISR BIT(8) +#define B_BE_PCIE_TX_CH7_ISR BIT(7) +#define B_BE_PCIE_TX_CH6_ISR BIT(6) +#define B_BE_PCIE_TX_CH5_ISR BIT(5) +#define B_BE_PCIE_TX_CH4_ISR BIT(4) +#define B_BE_PCIE_TX_CH3_ISR BIT(3) +#define B_BE_PCIE_TX_CH2_ISR BIT(2) +#define B_BE_PCIE_TX_CH1_ISR BIT(1) +#define B_BE_PCIE_TX_CH0_ISR BIT(0) + +#define R_BE_HAXI_HIMR00 0xB0B0 +#define B_BE_RDU_CH5_INT_IMR_V1 BIT(30) +#define B_BE_RDU_CH4_INT_IMR_V1 BIT(29) +#define B_BE_RDU_CH3_INT_IMR_V1 BIT(28) +#define B_BE_RDU_CH2_INT_IMR_V1 BIT(27) +#define B_BE_RDU_CH1_INT_IMR_V1 BIT(26) +#define B_BE_RDU_CH0_INT_IMR_V1 BIT(25) +#define B_BE_RXDMA_STUCK_INT_EN_V1 BIT(24) +#define B_BE_TXDMA_STUCK_INT_EN_V1 BIT(23) +#define B_BE_TXDMA_CH14_INT_EN_V1 BIT(22) +#define B_BE_TXDMA_CH13_INT_EN_V1 BIT(21) +#define B_BE_TXDMA_CH12_INT_EN_V1 BIT(20) +#define B_BE_TXDMA_CH11_INT_EN_V1 BIT(19) +#define B_BE_TXDMA_CH10_INT_EN_V1 BIT(18) +#define B_BE_TXDMA_CH9_INT_EN_V1 BIT(17) +#define B_BE_TXDMA_CH8_INT_EN_V1 BIT(16) +#define B_BE_TXDMA_CH7_INT_EN_V1 BIT(15) +#define B_BE_TXDMA_CH6_INT_EN_V1 BIT(14) +#define B_BE_TXDMA_CH5_INT_EN_V1 BIT(13) +#define B_BE_TXDMA_CH4_INT_EN_V1 BIT(12) +#define B_BE_TXDMA_CH3_INT_EN_V1 BIT(11) +#define B_BE_TXDMA_CH2_INT_EN_V1 BIT(10) +#define B_BE_TXDMA_CH1_INT_EN_V1 BIT(9) +#define B_BE_TXDMA_CH0_INT_EN_V1 BIT(8) +#define B_BE_RX1P1DMA_INT_EN_V1 BIT(7) +#define B_BE_RX0P1DMA_INT_EN_V1 BIT(6) +#define B_BE_RO1DMA_INT_EN BIT(5) +#define B_BE_RP1DMA_INT_EN BIT(4) +#define B_BE_RX1DMA_INT_EN BIT(3) +#define B_BE_RO0DMA_INT_EN BIT(2) +#define B_BE_RP0DMA_INT_EN BIT(1) +#define B_BE_RX0DMA_INT_EN BIT(0) + +#define R_BE_HAXI_HISR00 0xB0B4 +#define B_BE_RDU_CH6_INT BIT(28) +#define B_BE_RDU_CH5_INT BIT(27) +#define B_BE_RDU_CH4_INT BIT(26) +#define B_BE_RDU_CH2_INT BIT(25) +#define B_BE_RDU_CH1_INT BIT(24) +#define B_BE_RDU_CH0_INT BIT(23) +#define B_BE_RXDMA_STUCK_INT BIT(22) +#define B_BE_TXDMA_STUCK_INT BIT(21) +#define B_BE_TXDMA_CH14_INT BIT(20) +#define B_BE_TXDMA_CH13_INT BIT(19) +#define B_BE_TXDMA_CH12_INT BIT(18) +#define B_BE_TXDMA_CH11_INT BIT(17) +#define B_BE_TXDMA_CH10_INT BIT(16) +#define B_BE_TXDMA_CH9_INT BIT(15) +#define B_BE_TXDMA_CH8_INT BIT(14) +#define B_BE_TXDMA_CH7_INT BIT(13) +#define B_BE_TXDMA_CH6_INT BIT(12) +#define B_BE_TXDMA_CH5_INT BIT(11) +#define B_BE_TXDMA_CH4_INT BIT(10) +#define B_BE_TXDMA_CH3_INT BIT(9) +#define B_BE_TXDMA_CH2_INT BIT(8) +#define B_BE_TXDMA_CH1_INT BIT(7) +#define B_BE_TXDMA_CH0_INT BIT(6) +#define B_BE_RPQ1DMA_INT BIT(5) +#define B_BE_RX1P1DMA_INT BIT(4) +#define B_BE_RX1DMA_INT BIT(3) +#define B_BE_RPQ0DMA_INT BIT(2) +#define B_BE_RX0P1DMA_INT BIT(1) +#define B_BE_RX0DMA_INT BIT(0) + /* TX/RX */ #define R_AX_DRV_FW_HSK_0 0x01B0 #define R_AX_DRV_FW_HSK_1 0x01B4 @@ -496,6 +693,105 @@ #define B_AX_CH11_BUSY BIT(1) #define B_AX_CH10_BUSY BIT(0) +#define R_BE_HAXI_DMA_STOP1 0xB010 +#define B_BE_STOP_WPDMA BIT(31) +#define B_BE_STOP_CH14 BIT(14) +#define B_BE_STOP_CH13 BIT(13) +#define B_BE_STOP_CH12 BIT(12) +#define B_BE_STOP_CH11 BIT(11) +#define B_BE_STOP_CH10 BIT(10) +#define B_BE_STOP_CH9 BIT(9) +#define B_BE_STOP_CH8 BIT(8) +#define B_BE_STOP_CH7 BIT(7) +#define B_BE_STOP_CH6 BIT(6) +#define B_BE_STOP_CH5 BIT(5) +#define B_BE_STOP_CH4 BIT(4) +#define B_BE_STOP_CH3 BIT(3) +#define B_BE_STOP_CH2 BIT(2) +#define B_BE_STOP_CH1 BIT(1) +#define B_BE_STOP_CH0 BIT(0) +#define B_BE_TX_STOP1_MASK (B_BE_STOP_CH0 | B_BE_STOP_CH1 | \ + B_BE_STOP_CH2 | B_BE_STOP_CH3 | \ + B_BE_STOP_CH4 | B_BE_STOP_CH5 | \ + B_BE_STOP_CH6 | B_BE_STOP_CH7 | \ + B_BE_STOP_CH8 | B_BE_STOP_CH9 | \ + B_BE_STOP_CH10 | B_BE_STOP_CH11 | \ + B_BE_STOP_CH12) + +#define R_BE_CH0_TXBD_NUM_V1 0xB030 +#define R_BE_CH1_TXBD_NUM_V1 0xB032 +#define R_BE_CH2_TXBD_NUM_V1 0xB034 +#define R_BE_CH3_TXBD_NUM_V1 0xB036 +#define R_BE_CH4_TXBD_NUM_V1 0xB038 +#define R_BE_CH5_TXBD_NUM_V1 0xB03A +#define R_BE_CH6_TXBD_NUM_V1 0xB03C +#define R_BE_CH7_TXBD_NUM_V1 0xB03E +#define R_BE_CH8_TXBD_NUM_V1 0xB040 +#define R_BE_CH9_TXBD_NUM_V1 0xB042 +#define R_BE_CH10_TXBD_NUM_V1 0xB044 +#define R_BE_CH11_TXBD_NUM_V1 0xB046 +#define R_BE_CH12_TXBD_NUM_V1 0xB048 +#define R_BE_CH13_TXBD_NUM_V1 0xB04C +#define R_BE_CH14_TXBD_NUM_V1 0xB04E + +#define R_BE_RXQ0_RXBD_NUM_V1 0xB050 +#define R_BE_RPQ0_RXBD_NUM_V1 0xB052 + +#define R_BE_CH0_TXBD_IDX_V1 0xB100 +#define R_BE_CH1_TXBD_IDX_V1 0xB104 +#define R_BE_CH2_TXBD_IDX_V1 0xB108 +#define R_BE_CH3_TXBD_IDX_V1 0xB10C +#define R_BE_CH4_TXBD_IDX_V1 0xB110 +#define R_BE_CH5_TXBD_IDX_V1 0xB114 +#define R_BE_CH6_TXBD_IDX_V1 0xB118 +#define R_BE_CH7_TXBD_IDX_V1 0xB11C +#define R_BE_CH8_TXBD_IDX_V1 0xB120 +#define R_BE_CH9_TXBD_IDX_V1 0xB124 +#define R_BE_CH10_TXBD_IDX_V1 0xB128 +#define R_BE_CH11_TXBD_IDX_V1 0xB12C +#define R_BE_CH12_TXBD_IDX_V1 0xB130 +#define R_BE_CH13_TXBD_IDX_V1 0xB134 +#define R_BE_CH14_TXBD_IDX_V1 0xB138 + +#define R_BE_RXQ0_RXBD_IDX_V1 0xB160 +#define R_BE_RPQ0_RXBD_IDX_V1 0xB164 + +#define R_BE_CH0_TXBD_DESA_L_V1 0xB200 +#define R_BE_CH0_TXBD_DESA_H_V1 0xB204 +#define R_BE_CH1_TXBD_DESA_L_V1 0xB208 +#define R_BE_CH1_TXBD_DESA_H_V1 0xB20C +#define R_BE_CH2_TXBD_DESA_L_V1 0xB210 +#define R_BE_CH2_TXBD_DESA_H_V1 0xB214 +#define R_BE_CH3_TXBD_DESA_L_V1 0xB218 +#define R_BE_CH3_TXBD_DESA_H_V1 0xB21C +#define R_BE_CH4_TXBD_DESA_L_V1 0xB220 +#define R_BE_CH4_TXBD_DESA_H_V1 0xB224 +#define R_BE_CH5_TXBD_DESA_L_V1 0xB228 +#define R_BE_CH5_TXBD_DESA_H_V1 0xB22C +#define R_BE_CH6_TXBD_DESA_L_V1 0xB230 +#define R_BE_CH6_TXBD_DESA_H_V1 0xB234 +#define R_BE_CH7_TXBD_DESA_L_V1 0xB238 +#define R_BE_CH7_TXBD_DESA_H_V1 0xB23C +#define R_BE_CH8_TXBD_DESA_L_V1 0xB240 +#define R_BE_CH8_TXBD_DESA_H_V1 0xB244 +#define R_BE_CH9_TXBD_DESA_L_V1 0xB248 +#define R_BE_CH9_TXBD_DESA_H_V1 0xB24C +#define R_BE_CH10_TXBD_DESA_L_V1 0xB250 +#define R_BE_CH10_TXBD_DESA_H_V1 0xB254 +#define R_BE_CH11_TXBD_DESA_L_V1 0xB258 +#define R_BE_CH11_TXBD_DESA_H_V1 0xB25C +#define R_BE_CH12_TXBD_DESA_L_V1 0xB260 +#define R_BE_CH12_TXBD_DESA_H_V1 0xB264 +#define R_BE_CH13_TXBD_DESA_L_V1 0xB268 +#define R_BE_CH13_TXBD_DESA_H_V1 0xB26C +#define R_BE_CH14_TXBD_DESA_L_V1 0xB270 +#define R_BE_CH14_TXBD_DESA_H_V1 0xB274 + +#define R_BE_RXQ0_RXBD_DESA_L_V1 0xB300 +#define R_BE_RXQ0_RXBD_DESA_H_V1 0xB304 +#define R_BE_RPQ0_RXBD_DESA_L_V1 0xB308 +#define R_BE_RPQ0_RXBD_DESA_H_V1 0xB30C + /* Configure */ #define R_AX_PCIE_INIT_CFG2 0x1004 #define B_AX_WD_ITVL_IDLE GENMASK(27, 24) @@ -516,6 +812,13 @@ #define B_AX_RXCOUNTER_MATCH_MASK GENMASK(15, 8) #define B_AX_RXTIMER_MATCH_MASK GENMASK(7, 0) +#define R_AX_INT_MIT_RX_V1 0x1184 +#define B_AX_RXMIT_RXP2_SEL_V1 BIT(19) +#define B_AX_RXMIT_RXP1_SEL_V1 BIT(18) +#define B_AX_MIT_RXTIMER_UNIT_MASK GENMASK(17, 16) +#define B_AX_MIT_RXCOUNTER_MATCH_MASK GENMASK(15, 8) +#define B_AX_MIT_RXTIMER_MATCH_MASK GENMASK(7, 0) + #define R_AX_DBG_ERR_FLAG 0x11C4 #define B_AX_PCIE_RPQ_FULL BIT(29) #define B_AX_PCIE_RXQ_FULL BIT(28) @@ -554,6 +857,136 @@ #define R_AX_PCIE_HRPWM_V1 0x30C0 #define R_AX_PCIE_CRPWM 0x30C4 +#define R_BE_PCIE_HRPWM 0x30C0 +#define R_BE_PCIE_CRPWM 0x30C4 + +#define R_BE_L1_2_CTRL_HCILDO 0x3110 +#define B_BE_PCIE_DIS_L1_2_CTRL_HCILDO BIT(0) + +#define R_BE_PL1_DBG_INFO 0x3120 +#define B_BE_END_PL1_CNT_MASK GENMASK(23, 16) +#define B_BE_START_PL1_CNT_MASK GENMASK(7, 0) + +#define R_BE_PCIE_MIT0_TMR 0x3330 +#define B_BE_PCIE_MIT0_RX_TMR_MASK GENMASK(5, 4) +#define BE_MIT0_TMR_UNIT_1MS 0 +#define BE_MIT0_TMR_UNIT_2MS 1 +#define BE_MIT0_TMR_UNIT_4MS 2 +#define BE_MIT0_TMR_UNIT_8MS 3 +#define B_BE_PCIE_MIT0_TX_TMR_MASK GENMASK(1, 0) + +#define R_BE_PCIE_MIT0_CNT 0x3334 +#define B_BE_PCIE_RX_MIT0_CNT_MASK GENMASK(31, 24) +#define B_BE_PCIE_TX_MIT0_CNT_MASK GENMASK(23, 16) +#define B_BE_PCIE_RX_MIT0_TMR_CNT_MASK GENMASK(15, 8) +#define B_BE_PCIE_TX_MIT0_TMR_CNT_MASK GENMASK(7, 0) + +#define R_BE_PCIE_MIT_CH_EN 0x3338 +#define B_BE_PCIE_MIT_RX1P1_EN BIT(23) +#define B_BE_PCIE_MIT_RX0P1_EN BIT(22) +#define B_BE_PCIE_MIT_ROQ1_EN BIT(21) +#define B_BE_PCIE_MIT_RPQ1_EN BIT(20) +#define B_BE_PCIE_MIT_RX1P2_EN BIT(19) +#define B_BE_PCIE_MIT_ROQ0_EN BIT(18) +#define B_BE_PCIE_MIT_RPQ0_EN BIT(17) +#define B_BE_PCIE_MIT_RX0P2_EN BIT(16) +#define B_BE_PCIE_MIT_TXCH14_EN BIT(14) +#define B_BE_PCIE_MIT_TXCH13_EN BIT(13) +#define B_BE_PCIE_MIT_TXCH12_EN BIT(12) +#define B_BE_PCIE_MIT_TXCH11_EN BIT(11) +#define B_BE_PCIE_MIT_TXCH10_EN BIT(10) +#define B_BE_PCIE_MIT_TXCH9_EN BIT(9) +#define B_BE_PCIE_MIT_TXCH8_EN BIT(8) +#define B_BE_PCIE_MIT_TXCH7_EN BIT(7) +#define B_BE_PCIE_MIT_TXCH6_EN BIT(6) +#define B_BE_PCIE_MIT_TXCH5_EN BIT(5) +#define B_BE_PCIE_MIT_TXCH4_EN BIT(4) +#define B_BE_PCIE_MIT_TXCH3_EN BIT(3) +#define B_BE_PCIE_MIT_TXCH2_EN BIT(2) +#define B_BE_PCIE_MIT_TXCH1_EN BIT(1) +#define B_BE_PCIE_MIT_TXCH0_EN BIT(0) + +#define R_BE_SER_PL1_CTRL 0x34A8 +#define B_BE_PL1_SER_PL1_EN BIT(31) +#define B_BE_PL1_IGNORE_HOT_RST BIT(30) +#define B_BE_PL1_TIMER_UNIT_MASK GENMASK(19, 17) +#define B_BE_PL1_TIMER_CLEAR BIT(0) + +#define R_BE_REG_PL1_MASK 0x34B0 +#define B_BE_SER_PCLKREQ_ACK_MASK BIT(5) +#define B_BE_SER_PM_CLK_MASK BIT(4) +#define B_BE_SER_LTSSM_IMR BIT(3) +#define B_BE_SER_PM_MASTER_IMR BIT(2) +#define B_BE_SER_L1SUB_IMR BIT(1) +#define B_BE_SER_PMU_IMR BIT(0) + +#define R_BE_RX_APPEND_MODE 0x8920 +#define B_BE_APPEND_OFFSET_MASK GENMASK(23, 16) +#define B_BE_APPEND_LEN_MASK GENMASK(15, 0) + +#define R_BE_TXBD_RWPTR_CLR1 0xB014 +#define B_BE_CLR_CH14_IDX BIT(14) +#define B_BE_CLR_CH13_IDX BIT(13) +#define B_BE_CLR_CH12_IDX BIT(12) +#define B_BE_CLR_CH11_IDX BIT(11) +#define B_BE_CLR_CH10_IDX BIT(10) +#define B_BE_CLR_CH9_IDX BIT(9) +#define B_BE_CLR_CH8_IDX BIT(8) +#define B_BE_CLR_CH7_IDX BIT(7) +#define B_BE_CLR_CH6_IDX BIT(6) +#define B_BE_CLR_CH5_IDX BIT(5) +#define B_BE_CLR_CH4_IDX BIT(4) +#define B_BE_CLR_CH3_IDX BIT(3) +#define B_BE_CLR_CH2_IDX BIT(2) +#define B_BE_CLR_CH1_IDX BIT(1) +#define B_BE_CLR_CH0_IDX BIT(0) + +#define R_BE_RXBD_RWPTR_CLR1_V1 0xB018 +#define B_BE_CLR_ROQ1_IDX_V1 BIT(5) +#define B_BE_CLR_RPQ1_IDX_V1 BIT(4) +#define B_BE_CLR_RXQ1_IDX_V1 BIT(3) +#define B_BE_CLR_ROQ0_IDX BIT(2) +#define B_BE_CLR_RPQ0_IDX BIT(1) +#define B_BE_CLR_RXQ0_IDX BIT(0) + +#define R_BE_HAXI_DMA_BUSY1 0xB01C +#define B_BE_HAXI_MST_BUSY BIT(31) +#define B_BE_HAXI_RX_IDLE BIT(25) +#define B_BE_HAXI_TX_IDLE BIT(24) +#define B_BE_ROQ1_BUSY_V1 BIT(21) +#define B_BE_RPQ1_BUSY_V1 BIT(20) +#define B_BE_RXQ1_BUSY_V1 BIT(19) +#define B_BE_ROQ0_BUSY_V1 BIT(18) +#define B_BE_RPQ0_BUSY_V1 BIT(17) +#define B_BE_RXQ0_BUSY_V1 BIT(16) +#define B_BE_WPDMA_BUSY BIT(15) +#define B_BE_CH14_BUSY BIT(14) +#define B_BE_CH13_BUSY BIT(13) +#define B_BE_CH12_BUSY BIT(12) +#define B_BE_CH11_BUSY BIT(11) +#define B_BE_CH10_BUSY BIT(10) +#define B_BE_CH9_BUSY BIT(9) +#define B_BE_CH8_BUSY BIT(8) +#define B_BE_CH7_BUSY BIT(7) +#define B_BE_CH6_BUSY BIT(6) +#define B_BE_CH5_BUSY BIT(5) +#define B_BE_CH4_BUSY BIT(4) +#define B_BE_CH3_BUSY BIT(3) +#define B_BE_CH2_BUSY BIT(2) +#define B_BE_CH1_BUSY BIT(1) +#define B_BE_CH0_BUSY BIT(0) +#define DMA_BUSY1_CHECK_BE (B_BE_CH0_BUSY | B_BE_CH1_BUSY | B_BE_CH2_BUSY | \ + B_BE_CH3_BUSY | B_BE_CH4_BUSY | B_BE_CH5_BUSY | \ + B_BE_CH6_BUSY | B_BE_CH7_BUSY | B_BE_CH8_BUSY | \ + B_BE_CH9_BUSY | B_BE_CH10_BUSY | B_BE_CH11_BUSY | \ + B_BE_CH12_BUSY | B_BE_CH13_BUSY | B_BE_CH14_BUSY) + +#define R_BE_HAXI_EXP_CTRL_V1 0xB020 +#define B_BE_R_NO_SEC_ACCESS BIT(31) +#define B_BE_FORCE_EN_DMA_RX_GCLK BIT(5) +#define B_BE_FORCE_EN_DMA_TX_GCLK BIT(4) +#define B_BE_MAX_TAG_NUM_MASK GENMASK(3, 0) + #define RTW89_PCI_TXBD_NUM_MAX 256 #define RTW89_PCI_RXBD_NUM_MAX 256 #define RTW89_PCI_TXWD_NUM_MAX 512 @@ -565,12 +998,15 @@ #define RTW89_PCI_MULTITAG 8 /* PCIE CFG register */ +#define RTW89_PCIE_CAPABILITY_SPEED 0x7C +#define RTW89_PCIE_SUPPORT_GEN_MASK GENMASK(3, 0) #define RTW89_PCIE_L1_STS_V1 0x80 #define RTW89_BCFG_LINK_SPEED_MASK GENMASK(19, 16) #define RTW89_PCIE_GEN1_SPEED 0x01 #define RTW89_PCIE_GEN2_SPEED 0x02 #define RTW89_PCIE_PHY_RATE 0x82 #define RTW89_PCIE_PHY_RATE_MASK GENMASK(1, 0) +#define RTW89_PCIE_LINK_CHANGE_SPEED 0xA0 #define RTW89_PCIE_L1SS_STS_V1 0x0168 #define RTW89_PCIE_BIT_ASPM_L11 BIT(3) #define RTW89_PCIE_BIT_ASPM_L12 BIT(2) @@ -585,6 +1021,8 @@ #define RTW89_PCIE_BIT_CLK BIT(4) #define RTW89_PCIE_BIT_L1 BIT(3) #define RTW89_PCIE_CLK_CTRL 0x0725 +#define RTW89_PCIE_FTS 0x080C +#define RTW89_PCIE_POLLING_BIT BIT(17) #define RTW89_PCIE_RST_MSTATE 0x0B48 #define RTW89_PCIE_BIT_CFG_RST_MSTATE BIT(0) @@ -757,7 +1195,26 @@ struct rtw89_pci_bd_ram { u8 min_num; }; +struct rtw89_pci_gen_def { + u32 isr_rdu; + u32 isr_halt_c2h; + u32 isr_wdt_timeout; + struct rtw89_reg2_def isr_clear_rpq; + struct rtw89_reg2_def isr_clear_rxq; + + int (*mac_pre_init)(struct rtw89_dev *rtwdev); + int (*mac_pre_deinit)(struct rtw89_dev *rtwdev); + int (*mac_post_init)(struct rtw89_dev *rtwdev); + + void (*clr_idx_all)(struct rtw89_dev *rtwdev); + int (*rst_bdram)(struct rtw89_dev *rtwdev); + + int (*lv1rst_stop_dma)(struct rtw89_dev *rtwdev); + int (*lv1rst_start_dma)(struct rtw89_dev *rtwdev); +}; + struct rtw89_pci_info { + const struct rtw89_pci_gen_def *gen_def; enum mac_ax_bd_trunc_mode txbd_trunc_mode; enum mac_ax_bd_trunc_mode rxbd_trunc_mode; enum mac_ax_rxbd_mode rxbd_mode; @@ -772,6 +1229,7 @@ struct rtw89_pci_info { enum mac_ax_pcie_func_ctrl autok_en; enum mac_ax_pcie_func_ctrl io_rcy_en; enum mac_ax_io_rcy_tmr io_rcy_tmr; + bool rx_ring_eq_is_full; u32 init_cfg_reg; u32 txhci_en_bit; @@ -781,6 +1239,7 @@ struct rtw89_pci_info { u32 max_tag_num_mask; u32 rxbd_rwptr_clr_reg; u32 txbd_rwptr_clr2_reg; + struct rtw89_reg_def dma_io_stop; struct rtw89_reg_def dma_stop1; struct rtw89_reg_def dma_stop2; struct rtw89_reg_def dma_busy1; @@ -789,6 +1248,7 @@ struct rtw89_pci_info { u32 rpwm_addr; u32 cpwm_addr; + u32 mit_addr; u32 tx_dma_ch_mask; const struct rtw89_pci_bd_idx_addr *bd_idx_addr_low_power; const struct rtw89_pci_ch_dma_addr_set *dma_addr_set; @@ -1059,33 +1519,45 @@ static inline bool rtw89_pci_ltr_is_err_reg_val(u32 val) extern const struct dev_pm_ops rtw89_pm_ops; extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set; extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_v1; +extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_be; extern const struct rtw89_pci_bd_ram rtw89_bd_ram_table_dual[RTW89_TXCH_NUM]; extern const struct rtw89_pci_bd_ram rtw89_bd_ram_table_single[RTW89_TXCH_NUM]; +extern const struct rtw89_pci_gen_def rtw89_pci_gen_ax; +extern const struct rtw89_pci_gen_def rtw89_pci_gen_be; struct pci_device_id; int rtw89_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id); void rtw89_pci_remove(struct pci_dev *pdev); +void rtw89_pci_ops_reset(struct rtw89_dev *rtwdev); int rtw89_pci_ltr_set(struct rtw89_dev *rtwdev, bool en); int rtw89_pci_ltr_set_v1(struct rtw89_dev *rtwdev, bool en); +int rtw89_pci_ltr_set_v2(struct rtw89_dev *rtwdev, bool en); u32 rtw89_pci_fill_txaddr_info(struct rtw89_dev *rtwdev, void *txaddr_info_addr, u32 total_len, dma_addr_t dma, u8 *add_info_nr); u32 rtw89_pci_fill_txaddr_info_v1(struct rtw89_dev *rtwdev, void *txaddr_info_addr, u32 total_len, dma_addr_t dma, u8 *add_info_nr); +void rtw89_pci_ctrl_dma_all(struct rtw89_dev *rtwdev, bool enable); void rtw89_pci_config_intr_mask(struct rtw89_dev *rtwdev); void rtw89_pci_config_intr_mask_v1(struct rtw89_dev *rtwdev); +void rtw89_pci_config_intr_mask_v2(struct rtw89_dev *rtwdev); void rtw89_pci_enable_intr(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci); void rtw89_pci_disable_intr(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci); void rtw89_pci_enable_intr_v1(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci); void rtw89_pci_disable_intr_v1(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci); +void rtw89_pci_enable_intr_v2(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci); +void rtw89_pci_disable_intr_v2(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci); void rtw89_pci_recognize_intrs(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci, struct rtw89_pci_isrs *isrs); void rtw89_pci_recognize_intrs_v1(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci, struct rtw89_pci_isrs *isrs); +void rtw89_pci_recognize_intrs_v2(struct rtw89_dev *rtwdev, + struct rtw89_pci *rtwpci, + struct rtw89_pci_isrs *isrs); static inline u32 rtw89_chip_fill_txaddr_info(struct rtw89_dev *rtwdev, @@ -1157,4 +1629,47 @@ void rtw89_chip_recognize_intrs(struct rtw89_dev *rtwdev, info->recognize_intrs(rtwdev, rtwpci, isrs); } +static inline int rtw89_pci_ops_mac_pre_init(struct rtw89_dev *rtwdev) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_pci_gen_def *gen_def = info->gen_def; + + return gen_def->mac_pre_init(rtwdev); +} + +static inline int rtw89_pci_ops_mac_pre_deinit(struct rtw89_dev *rtwdev) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_pci_gen_def *gen_def = info->gen_def; + + if (!gen_def->mac_pre_deinit) + return 0; + + return gen_def->mac_pre_deinit(rtwdev); +} + +static inline int rtw89_pci_ops_mac_post_init(struct rtw89_dev *rtwdev) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_pci_gen_def *gen_def = info->gen_def; + + return gen_def->mac_post_init(rtwdev); +} + +static inline void rtw89_pci_clr_idx_all(struct rtw89_dev *rtwdev) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_pci_gen_def *gen_def = info->gen_def; + + gen_def->clr_idx_all(rtwdev); +} + +static inline int rtw89_pci_reset_bdram(struct rtw89_dev *rtwdev) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_pci_gen_def *gen_def = info->gen_def; + + return gen_def->rst_bdram(rtwdev); +} + #endif diff --git a/drivers/net/wireless/realtek/rtw89/pci_be.c b/drivers/net/wireless/realtek/rtw89/pci_be.c new file mode 100644 index 0000000000000..629ffa4bee91f --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/pci_be.c @@ -0,0 +1,509 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2023 Realtek Corporation + */ + +#include + +#include "mac.h" +#include "pci.h" +#include "reg.h" + +enum pcie_rxbd_mode { + PCIE_RXBD_NORM = 0, + PCIE_RXBD_SEP, + PCIE_RXBD_EXT, +}; + +#define PL0_TMR_SCALE_ASIC 1 +#define PL0_TMR_ANA_172US 0x800 +#define PL0_TMR_MAC_1MS 0x27100 +#define PL0_TMR_AUX_1MS 0x1E848 + +static void _patch_pcie_power_wake_be(struct rtw89_dev *rtwdev, bool power_up) +{ + if (power_up) + rtw89_write32_set(rtwdev, R_BE_HCI_OPT_CTRL, BIT_WAKE_CTRL_V1); + else + rtw89_write32_clr(rtwdev, R_BE_HCI_OPT_CTRL, BIT_WAKE_CTRL_V1); +} + +static void rtw89_pci_set_io_rcy_be(struct rtw89_dev *rtwdev) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + u32 scale = PL0_TMR_SCALE_ASIC; + u32 val32; + + if (info->io_rcy_en == MAC_AX_PCIE_ENABLE) { + val32 = info->io_rcy_tmr == MAC_AX_IO_RCY_ANA_TMR_DEF ? + PL0_TMR_ANA_172US : info->io_rcy_tmr; + val32 /= scale; + + rtw89_write32(rtwdev, R_BE_AON_WDT_TMR, val32); + rtw89_write32(rtwdev, R_BE_MDIO_WDT_TMR, val32); + rtw89_write32(rtwdev, R_BE_LA_MODE_WDT_TMR, val32); + rtw89_write32(rtwdev, R_BE_WDT_AR_TMR, val32); + rtw89_write32(rtwdev, R_BE_WDT_AW_TMR, val32); + rtw89_write32(rtwdev, R_BE_WDT_W_TMR, val32); + rtw89_write32(rtwdev, R_BE_WDT_B_TMR, val32); + rtw89_write32(rtwdev, R_BE_WDT_R_TMR, val32); + + val32 = info->io_rcy_tmr == MAC_AX_IO_RCY_ANA_TMR_DEF ? + PL0_TMR_MAC_1MS : info->io_rcy_tmr; + val32 /= scale; + rtw89_write32(rtwdev, R_BE_WLAN_WDT_TMR, val32); + rtw89_write32(rtwdev, R_BE_AXIDMA_WDT_TMR, val32); + + val32 = info->io_rcy_tmr == MAC_AX_IO_RCY_ANA_TMR_DEF ? + PL0_TMR_AUX_1MS : info->io_rcy_tmr; + val32 /= scale; + rtw89_write32(rtwdev, R_BE_LOCAL_WDT_TMR, val32); + } else { + rtw89_write32_clr(rtwdev, R_BE_WLAN_WDT, B_BE_WLAN_WDT_ENABLE); + rtw89_write32_clr(rtwdev, R_BE_AXIDMA_WDT, B_BE_AXIDMA_WDT_ENABLE); + rtw89_write32_clr(rtwdev, R_BE_AON_WDT, B_BE_AON_WDT_ENABLE); + rtw89_write32_clr(rtwdev, R_BE_LOCAL_WDT, B_BE_LOCAL_WDT_ENABLE); + rtw89_write32_clr(rtwdev, R_BE_MDIO_WDT, B_BE_MDIO_WDT_ENABLE); + rtw89_write32_clr(rtwdev, R_BE_LA_MODE_WDT, B_BE_LA_MODE_WDT_ENABLE); + rtw89_write32_clr(rtwdev, R_BE_WDT_AR, B_BE_WDT_AR_ENABLE); + rtw89_write32_clr(rtwdev, R_BE_WDT_AW, B_BE_WDT_AW_ENABLE); + rtw89_write32_clr(rtwdev, R_BE_WDT_W, B_BE_WDT_W_ENABLE); + rtw89_write32_clr(rtwdev, R_BE_WDT_B, B_BE_WDT_B_ENABLE); + rtw89_write32_clr(rtwdev, R_BE_WDT_R, B_BE_WDT_R_ENABLE); + } +} + +static void rtw89_pci_ctrl_wpdma_pcie_be(struct rtw89_dev *rtwdev, bool en) +{ + if (en) + rtw89_write32_clr(rtwdev, R_BE_HAXI_DMA_STOP1, B_BE_STOP_WPDMA); + else + rtw89_write32_set(rtwdev, R_BE_HAXI_DMA_STOP1, B_BE_STOP_WPDMA); +} + +static void rtw89_pci_ctrl_trxdma_pcie_be(struct rtw89_dev *rtwdev, + enum mac_ax_pcie_func_ctrl tx_en, + enum mac_ax_pcie_func_ctrl rx_en, + enum mac_ax_pcie_func_ctrl io_en) +{ + u32 val; + + val = rtw89_read32(rtwdev, R_BE_HAXI_INIT_CFG1); + + if (tx_en == MAC_AX_PCIE_ENABLE) + val |= B_BE_TXDMA_EN; + else if (tx_en == MAC_AX_PCIE_DISABLE) + val &= ~B_BE_TXDMA_EN; + + if (rx_en == MAC_AX_PCIE_ENABLE) + val |= B_BE_RXDMA_EN; + else if (rx_en == MAC_AX_PCIE_DISABLE) + val &= ~B_BE_RXDMA_EN; + + if (io_en == MAC_AX_PCIE_ENABLE) + val &= ~B_BE_STOP_AXI_MST; + else if (io_en == MAC_AX_PCIE_DISABLE) + val |= B_BE_STOP_AXI_MST; + + rtw89_write32(rtwdev, R_BE_HAXI_INIT_CFG1, val); +} + +static void rtw89_pci_clr_idx_all_be(struct rtw89_dev *rtwdev) +{ + struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + struct rtw89_pci_rx_ring *rx_ring; + u32 val; + + val = B_BE_CLR_CH0_IDX | B_BE_CLR_CH1_IDX | B_BE_CLR_CH2_IDX | + B_BE_CLR_CH3_IDX | B_BE_CLR_CH4_IDX | B_BE_CLR_CH5_IDX | + B_BE_CLR_CH6_IDX | B_BE_CLR_CH7_IDX | B_BE_CLR_CH8_IDX | + B_BE_CLR_CH9_IDX | B_BE_CLR_CH10_IDX | B_BE_CLR_CH11_IDX | + B_BE_CLR_CH12_IDX | B_BE_CLR_CH13_IDX | B_BE_CLR_CH14_IDX; + rtw89_write32(rtwdev, R_BE_TXBD_RWPTR_CLR1, val); + + rtw89_write32(rtwdev, R_BE_RXBD_RWPTR_CLR1_V1, + B_BE_CLR_RXQ0_IDX | B_BE_CLR_RPQ0_IDX); + + rx_ring = &rtwpci->rx_rings[RTW89_RXCH_RXQ]; + rtw89_write16(rtwdev, R_BE_RXQ0_RXBD_IDX_V1, rx_ring->bd_ring.len - 1); + + rx_ring = &rtwpci->rx_rings[RTW89_RXCH_RPQ]; + rtw89_write16(rtwdev, R_BE_RPQ0_RXBD_IDX_V1, rx_ring->bd_ring.len - 1); +} + +static int rtw89_pci_poll_txdma_ch_idle_be(struct rtw89_dev *rtwdev) +{ + u32 val; + + return read_poll_timeout(rtw89_read32, val, (val & DMA_BUSY1_CHECK_BE) == 0, + 10, 1000, false, rtwdev, R_BE_HAXI_DMA_BUSY1); +} + +static int rtw89_pci_poll_rxdma_ch_idle_be(struct rtw89_dev *rtwdev) +{ + u32 check; + u32 val; + + check = B_BE_RXQ0_BUSY_V1 | B_BE_RPQ0_BUSY_V1; + + return read_poll_timeout(rtw89_read32, val, (val & check) == 0, + 10, 1000, false, rtwdev, R_BE_HAXI_DMA_BUSY1); +} + +static int rtw89_pci_poll_dma_all_idle_be(struct rtw89_dev *rtwdev) +{ + int ret; + + ret = rtw89_pci_poll_txdma_ch_idle_be(rtwdev); + if (ret) { + rtw89_err(rtwdev, "txdma ch busy\n"); + return ret; + } + + ret = rtw89_pci_poll_rxdma_ch_idle_be(rtwdev); + if (ret) { + rtw89_err(rtwdev, "rxdma ch busy\n"); + return ret; + } + + return 0; +} + +static void rtw89_pci_mode_op_be(struct rtw89_dev *rtwdev) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + u32 val32_init1, val32_rxapp, val32_exp; + + val32_init1 = rtw89_read32(rtwdev, R_BE_HAXI_INIT_CFG1); + val32_rxapp = rtw89_read32(rtwdev, R_BE_RX_APPEND_MODE); + val32_exp = rtw89_read32(rtwdev, R_BE_HAXI_EXP_CTRL_V1); + + if (info->rxbd_mode == MAC_AX_RXBD_PKT) { + val32_init1 = u32_replace_bits(val32_init1, PCIE_RXBD_NORM, + B_BE_RXQ_RXBD_MODE_MASK); + } else if (info->rxbd_mode == MAC_AX_RXBD_SEP) { + val32_init1 = u32_replace_bits(val32_init1, PCIE_RXBD_SEP, + B_BE_RXQ_RXBD_MODE_MASK); + val32_rxapp = u32_replace_bits(val32_rxapp, 0, + B_BE_APPEND_LEN_MASK); + } + + val32_init1 = u32_replace_bits(val32_init1, info->tx_burst, + B_BE_MAX_TXDMA_MASK); + val32_init1 = u32_replace_bits(val32_init1, info->rx_burst, + B_BE_MAX_RXDMA_MASK); + val32_exp = u32_replace_bits(val32_exp, info->multi_tag_num, + B_BE_MAX_TAG_NUM_MASK); + val32_init1 = u32_replace_bits(val32_init1, info->wd_dma_idle_intvl, + B_BE_CFG_WD_PERIOD_IDLE_MASK); + val32_init1 = u32_replace_bits(val32_init1, info->wd_dma_act_intvl, + B_BE_CFG_WD_PERIOD_ACTIVE_MASK); + + rtw89_write32(rtwdev, R_BE_HAXI_INIT_CFG1, val32_init1); + rtw89_write32(rtwdev, R_BE_RX_APPEND_MODE, val32_rxapp); + rtw89_write32(rtwdev, R_BE_HAXI_EXP_CTRL_V1, val32_exp); +} + +static int rtw89_pci_rst_bdram_be(struct rtw89_dev *rtwdev) +{ + u32 val; + + rtw89_write32_set(rtwdev, R_BE_HAXI_INIT_CFG1, B_BE_SET_BDRAM_BOUND); + + return read_poll_timeout(rtw89_read32, val, !(val & B_BE_SET_BDRAM_BOUND), + 50, 500000, false, rtwdev, R_BE_HAXI_INIT_CFG1); +} + +static void rtw89_pci_debounce_be(struct rtw89_dev *rtwdev) +{ + u32 val32; + + val32 = rtw89_read32(rtwdev, R_BE_SYS_PAGE_CLK_GATED); + val32 = u32_replace_bits(val32, 0, B_BE_PCIE_PRST_DEBUNC_PERIOD_MASK); + val32 |= B_BE_SYM_PRST_DEBUNC_SEL; + rtw89_write32(rtwdev, R_BE_SYS_PAGE_CLK_GATED, val32); +} + +static void rtw89_pci_ldo_low_pwr_be(struct rtw89_dev *rtwdev) +{ + rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_PSUS_OFF_CAPC_EN); + rtw89_write32_set(rtwdev, R_BE_SYS_PAGE_CLK_GATED, + B_BE_SOP_OFFPOOBS_PC | B_BE_CPHY_AUXCLK_OP | + B_BE_CPHY_POWER_READY_CHK); + rtw89_write32_clr(rtwdev, R_BE_SYS_SDIO_CTRL, B_BE_PCIE_FORCE_IBX_EN | + B_BE_PCIE_DIS_L2_RTK_PERST | + B_BE_PCIE_DIS_L2__CTRL_LDO_HCI); + rtw89_write32_clr(rtwdev, R_BE_L1_2_CTRL_HCILDO, B_BE_PCIE_DIS_L1_2_CTRL_HCILDO); +} + +static void rtw89_pci_pcie_setting_be(struct rtw89_dev *rtwdev) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_hal *hal = &rtwdev->hal; + + rtw89_write32_set(rtwdev, R_BE_PCIE_FRZ_CLK, B_BE_PCIE_EN_AUX_CLK); + rtw89_write32_clr(rtwdev, R_BE_PCIE_PS_CTRL, B_BE_CMAC_EXIT_L1_EN); + + if (chip->chip_id == RTL8922A && hal->cv == CHIP_CAV) + return; + + rtw89_write32_set(rtwdev, R_BE_EFUSE_CTRL_2_V1, B_BE_R_SYM_AUTOLOAD_WITH_PMC_SEL); + rtw89_write32_set(rtwdev, R_BE_PCIE_LAT_CTRL, B_BE_SYM_AUX_CLK_SEL); +} + +static void rtw89_pci_ser_setting_be(struct rtw89_dev *rtwdev) +{ + u32 val32; + + rtw89_write32(rtwdev, R_BE_PL1_DBG_INFO, 0x0); + rtw89_write32_set(rtwdev, R_BE_FWS1IMR, B_BE_PCIE_SER_TIMEOUT_INDIC_EN); + rtw89_write32_set(rtwdev, R_BE_SER_PL1_CTRL, B_BE_PL1_SER_PL1_EN); + + val32 = rtw89_read32(rtwdev, R_BE_REG_PL1_MASK); + val32 |= B_BE_SER_PMU_IMR | B_BE_SER_L1SUB_IMR | B_BE_SER_PM_MASTER_IMR | + B_BE_SER_LTSSM_IMR | B_BE_SER_PM_CLK_MASK | B_BE_SER_PCLKREQ_ACK_MASK; + rtw89_write32(rtwdev, R_BE_REG_PL1_MASK, val32); +} + +static void rtw89_pci_ctrl_txdma_ch_be(struct rtw89_dev *rtwdev, bool all_en, + bool h2c_en) +{ + u32 mask_all; + u32 val; + + mask_all = B_BE_STOP_CH0 | B_BE_STOP_CH1 | B_BE_STOP_CH2 | + B_BE_STOP_CH3 | B_BE_STOP_CH4 | B_BE_STOP_CH5 | + B_BE_STOP_CH6 | B_BE_STOP_CH7 | B_BE_STOP_CH8 | + B_BE_STOP_CH9 | B_BE_STOP_CH10 | B_BE_STOP_CH11; + + val = rtw89_read32(rtwdev, R_BE_HAXI_DMA_STOP1); + val |= B_BE_STOP_CH13 | B_BE_STOP_CH14; + + if (all_en) + val &= ~mask_all; + else + val |= mask_all; + + if (h2c_en) + val &= ~B_BE_STOP_CH12; + else + val |= B_BE_STOP_CH12; + + rtw89_write32(rtwdev, R_BE_HAXI_DMA_STOP1, val); +} + +static int rtw89_pci_ops_mac_pre_init_be(struct rtw89_dev *rtwdev) +{ + int ret; + + rtw89_pci_set_io_rcy_be(rtwdev); + _patch_pcie_power_wake_be(rtwdev, true); + rtw89_pci_ctrl_wpdma_pcie_be(rtwdev, false); + rtw89_pci_ctrl_trxdma_pcie_be(rtwdev, MAC_AX_PCIE_DISABLE, + MAC_AX_PCIE_DISABLE, MAC_AX_PCIE_DISABLE); + rtw89_pci_clr_idx_all_be(rtwdev); + + ret = rtw89_pci_poll_dma_all_idle_be(rtwdev); + if (ret) { + rtw89_err(rtwdev, "[ERR] poll pcie dma all idle\n"); + return ret; + } + + rtw89_pci_mode_op_be(rtwdev); + rtw89_pci_ops_reset(rtwdev); + + ret = rtw89_pci_rst_bdram_be(rtwdev); + if (ret) { + rtw89_err(rtwdev, "[ERR]pcie rst bdram\n"); + return ret; + } + + rtw89_pci_debounce_be(rtwdev); + rtw89_pci_ldo_low_pwr_be(rtwdev); + rtw89_pci_pcie_setting_be(rtwdev); + rtw89_pci_ser_setting_be(rtwdev); + + rtw89_pci_ctrl_txdma_ch_be(rtwdev, false, true); + rtw89_pci_ctrl_trxdma_pcie_be(rtwdev, MAC_AX_PCIE_ENABLE, + MAC_AX_PCIE_ENABLE, MAC_AX_PCIE_ENABLE); + + return 0; +} + +static int rtw89_pci_ops_mac_pre_deinit_be(struct rtw89_dev *rtwdev) +{ + u32 val; + + _patch_pcie_power_wake_be(rtwdev, false); + + val = rtw89_read32_mask(rtwdev, R_BE_IC_PWR_STATE, B_BE_WLMAC_PWR_STE_MASK); + if (val == 0) + return 0; + + rtw89_pci_ctrl_trxdma_pcie_be(rtwdev, MAC_AX_PCIE_DISABLE, + MAC_AX_PCIE_DISABLE, MAC_AX_PCIE_DISABLE); + rtw89_pci_clr_idx_all_be(rtwdev); + + return 0; +} + +int rtw89_pci_ltr_set_v2(struct rtw89_dev *rtwdev, bool en) +{ + u32 ctrl0, cfg0, cfg1, dec_ctrl, idle_ltcy, act_ltcy, dis_ltcy; + + ctrl0 = rtw89_read32(rtwdev, R_BE_LTR_CTRL_0); + if (rtw89_pci_ltr_is_err_reg_val(ctrl0)) + return -EINVAL; + cfg0 = rtw89_read32(rtwdev, R_BE_LTR_CFG_0); + if (rtw89_pci_ltr_is_err_reg_val(cfg0)) + return -EINVAL; + cfg1 = rtw89_read32(rtwdev, R_BE_LTR_CFG_1); + if (rtw89_pci_ltr_is_err_reg_val(cfg1)) + return -EINVAL; + dec_ctrl = rtw89_read32(rtwdev, R_BE_LTR_DECISION_CTRL_V1); + if (rtw89_pci_ltr_is_err_reg_val(dec_ctrl)) + return -EINVAL; + idle_ltcy = rtw89_read32(rtwdev, R_BE_LTR_LATENCY_IDX3_V1); + if (rtw89_pci_ltr_is_err_reg_val(idle_ltcy)) + return -EINVAL; + act_ltcy = rtw89_read32(rtwdev, R_BE_LTR_LATENCY_IDX1_V1); + if (rtw89_pci_ltr_is_err_reg_val(act_ltcy)) + return -EINVAL; + dis_ltcy = rtw89_read32(rtwdev, R_BE_LTR_LATENCY_IDX0_V1); + if (rtw89_pci_ltr_is_err_reg_val(dis_ltcy)) + return -EINVAL; + + if (en) { + dec_ctrl |= B_BE_ENABLE_LTR_CTL_DECISION | B_BE_LTR_HW_DEC_EN_V1; + ctrl0 |= B_BE_LTR_HW_EN; + } else { + dec_ctrl &= ~(B_BE_ENABLE_LTR_CTL_DECISION | B_BE_LTR_HW_DEC_EN_V1 | + B_BE_LTR_EN_PORT_V1_MASK); + ctrl0 &= ~B_BE_LTR_HW_EN; + } + + dec_ctrl = u32_replace_bits(dec_ctrl, PCI_LTR_SPC_500US, + B_BE_LTR_SPACE_IDX_MASK); + cfg0 = u32_replace_bits(cfg0, PCI_LTR_IDLE_TIMER_3_2MS, + B_BE_LTR_IDLE_TIMER_IDX_MASK); + cfg1 = u32_replace_bits(cfg1, 0xC0, B_BE_LTR_CMAC0_RX_USE_PG_TH_MASK); + cfg1 = u32_replace_bits(cfg1, 0xC0, B_BE_LTR_CMAC1_RX_USE_PG_TH_MASK); + cfg0 = u32_replace_bits(cfg0, 1, B_BE_LTR_IDX_ACTIVE_MASK); + cfg0 = u32_replace_bits(cfg0, 3, B_BE_LTR_IDX_IDLE_MASK); + dec_ctrl = u32_replace_bits(dec_ctrl, 0, B_BE_LTR_IDX_DISABLE_V1_MASK); + + rtw89_write32(rtwdev, R_BE_LTR_LATENCY_IDX3_V1, 0x90039003); + rtw89_write32(rtwdev, R_BE_LTR_LATENCY_IDX1_V1, 0x880b880b); + rtw89_write32(rtwdev, R_BE_LTR_LATENCY_IDX0_V1, 0); + rtw89_write32(rtwdev, R_BE_LTR_DECISION_CTRL_V1, dec_ctrl); + rtw89_write32(rtwdev, R_BE_LTR_CFG_0, cfg0); + rtw89_write32(rtwdev, R_BE_LTR_CFG_1, cfg1); + rtw89_write32(rtwdev, R_BE_LTR_CTRL_0, ctrl0); + + return 0; +} +EXPORT_SYMBOL(rtw89_pci_ltr_set_v2); + +static void rtw89_pci_configure_mit_be(struct rtw89_dev *rtwdev) +{ + u32 cnt; + u32 val; + + rtw89_write32_mask(rtwdev, R_BE_PCIE_MIT0_TMR, + B_BE_PCIE_MIT0_RX_TMR_MASK, BE_MIT0_TMR_UNIT_1MS); + + val = rtw89_read32(rtwdev, R_BE_PCIE_MIT0_CNT); + cnt = min_t(u32, U8_MAX, RTW89_PCI_RXBD_NUM_MAX / 2); + val = u32_replace_bits(val, cnt, B_BE_PCIE_RX_MIT0_CNT_MASK); + val = u32_replace_bits(val, 2, B_BE_PCIE_RX_MIT0_TMR_CNT_MASK); + rtw89_write32(rtwdev, R_BE_PCIE_MIT0_CNT, val); +} + +static int rtw89_pci_ops_mac_post_init_be(struct rtw89_dev *rtwdev) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + int ret; + + ret = info->ltr_set(rtwdev, true); + if (ret) { + rtw89_err(rtwdev, "pci ltr set fail\n"); + return ret; + } + + rtw89_pci_ctrl_trxdma_pcie_be(rtwdev, MAC_AX_PCIE_IGNORE, + MAC_AX_PCIE_IGNORE, MAC_AX_PCIE_ENABLE); + rtw89_pci_ctrl_wpdma_pcie_be(rtwdev, true); + rtw89_pci_ctrl_txdma_ch_be(rtwdev, true, true); + rtw89_pci_configure_mit_be(rtwdev); + + return 0; +} + +static int rtw89_pci_poll_io_idle_be(struct rtw89_dev *rtwdev) +{ + u32 sts; + int ret; + + ret = read_poll_timeout_atomic(rtw89_read32, sts, + !(sts & B_BE_HAXI_MST_BUSY), + 10, 1000, false, rtwdev, + R_BE_HAXI_DMA_BUSY1); + if (ret) { + rtw89_err(rtwdev, "pci dmach busy1 0x%X\n", sts); + return ret; + } + + return 0; +} + +static int rtw89_pci_lv1rst_stop_dma_be(struct rtw89_dev *rtwdev) +{ + int ret; + + rtw89_pci_ctrl_dma_all(rtwdev, false); + ret = rtw89_pci_poll_io_idle_be(rtwdev); + if (!ret) + return 0; + + rtw89_debug(rtwdev, RTW89_DBG_HCI, + "[PCIe] poll_io_idle fail; reset hci dma trx\n"); + + rtw89_mac_ctrl_hci_dma_trx(rtwdev, false); + rtw89_mac_ctrl_hci_dma_trx(rtwdev, true); + + return rtw89_pci_poll_io_idle_be(rtwdev); +} + +static int rtw89_pci_lv1rst_start_dma_be(struct rtw89_dev *rtwdev) +{ + int ret; + + rtw89_mac_ctrl_hci_dma_trx(rtwdev, false); + rtw89_mac_ctrl_hci_dma_trx(rtwdev, true); + rtw89_pci_clr_idx_all(rtwdev); + + ret = rtw89_pci_rst_bdram_be(rtwdev); + if (ret) + return ret; + + rtw89_pci_ctrl_dma_all(rtwdev, true); + return 0; +} + +const struct rtw89_pci_gen_def rtw89_pci_gen_be = { + .isr_rdu = B_BE_RDU_CH1_INT | B_BE_RDU_CH0_INT, + .isr_halt_c2h = B_BE_HALT_C2H_INT, + .isr_wdt_timeout = B_BE_WDT_TIMEOUT_INT, + .isr_clear_rpq = {R_BE_PCIE_DMA_ISR, B_BE_PCIE_RX_RPQ0_ISR_V1}, + .isr_clear_rxq = {R_BE_PCIE_DMA_ISR, B_BE_PCIE_RX_RX0P2_ISR_V1}, + + .mac_pre_init = rtw89_pci_ops_mac_pre_init_be, + .mac_pre_deinit = rtw89_pci_ops_mac_pre_deinit_be, + .mac_post_init = rtw89_pci_ops_mac_post_init_be, + + .clr_idx_all = rtw89_pci_clr_idx_all_be, + .rst_bdram = rtw89_pci_rst_bdram_be, + + .lv1rst_stop_dma = rtw89_pci_lv1rst_stop_dma_be, + .lv1rst_start_dma = rtw89_pci_lv1rst_start_dma_be, +}; +EXPORT_SYMBOL(rtw89_pci_gen_be); diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h index 5c85122e7bb5f..2d9cf5c02b92c 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.h +++ b/drivers/net/wireless/realtek/rtw89/phy.h @@ -591,6 +591,22 @@ enum rtw89_gain_offset rtw89_subband_to_gain_offset_band_of_ofdm(enum rtw89_subb return RTW89_GAIN_OFFSET_5G_MID; case RTW89_CH_5G_BAND_4: return RTW89_GAIN_OFFSET_5G_HIGH; + case RTW89_CH_6G_BAND_IDX0: + return RTW89_GAIN_OFFSET_6G_L0; + case RTW89_CH_6G_BAND_IDX1: + return RTW89_GAIN_OFFSET_6G_L1; + case RTW89_CH_6G_BAND_IDX2: + return RTW89_GAIN_OFFSET_6G_M0; + case RTW89_CH_6G_BAND_IDX3: + return RTW89_GAIN_OFFSET_6G_M1; + case RTW89_CH_6G_BAND_IDX4: + return RTW89_GAIN_OFFSET_6G_H0; + case RTW89_CH_6G_BAND_IDX5: + return RTW89_GAIN_OFFSET_6G_H1; + case RTW89_CH_6G_BAND_IDX6: + return RTW89_GAIN_OFFSET_6G_UH0; + case RTW89_CH_6G_BAND_IDX7: + return RTW89_GAIN_OFFSET_6G_UH1; } } diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index ccd5481e8a3dc..7a9ae6cd86e55 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -116,6 +116,7 @@ #define B_AX_LTE_MUX_CTRL_PATH BIT(26) #define R_AX_HCI_OPT_CTRL 0x0074 +#define BIT_WAKE_CTRL_V1 BIT(23) #define BIT_WAKE_CTRL BIT(5) #define R_AX_HCI_BG_CTRL 0x0078 @@ -3629,6 +3630,50 @@ #define B_AX_GNT_BT_TX_SW_VAL BIT(1) #define B_AX_GNT_BT_TX_SW_CTRL BIT(0) +#define R_BE_SYS_ISO_CTRL 0x0000 +#define B_BE_PWC_EV2EF_B BIT(15) +#define B_BE_PWC_EV2EF_S BIT(14) +#define B_BE_PA33V_EN BIT(13) +#define B_BE_PA12V_EN BIT(12) +#define B_BE_PAOOBS33V_EN BIT(11) +#define B_BE_PAOOBS12V_EN BIT(10) +#define B_BE_ISO_RFDIO BIT(9) +#define B_BE_ISO_EB2CORE BIT(8) +#define B_BE_ISO_DIOE BIT(7) +#define B_BE_ISO_WLPON2PP BIT(6) +#define B_BE_ISO_IP2MAC_WA02PP BIT(5) +#define B_BE_ISO_PD2CORE BIT(4) +#define B_BE_ISO_PA2PCIE BIT(3) +#define B_BE_ISO_PAOOBS2PCIE BIT(1) +#define B_BE_ISO_WD2PP BIT(0) + +#define R_BE_SYS_PW_CTRL 0x0004 +#define B_BE_SOP_ASWRM BIT(31) +#define B_BE_SOP_EASWR BIT(30) +#define B_BE_SOP_PWMM_DSWR BIT(29) +#define B_BE_SOP_EDSWR BIT(28) +#define B_BE_SOP_ACKF BIT(27) +#define B_BE_SOP_ERCK BIT(26) +#define B_BE_SOP_ANA_CLK_DIVISION_2 BIT(25) +#define B_BE_SOP_EXTL BIT(24) +#define B_BE_SOP_OFF_CAPC_EN BIT(23) +#define B_BE_XTAL_OFF_A_DIE BIT(22) +#define B_BE_ROP_SWPR BIT(21) +#define B_BE_DIS_HW_LPLDM BIT(20) +#define B_BE_DIS_HW_LPURLDO BIT(19) +#define B_BE_DIS_WLBT_PDNSUSEN_SOPC BIT(18) +#define B_BE_RDY_SYSPWR BIT(17) +#define B_BE_EN_WLON BIT(16) +#define B_BE_APDM_HPDN BIT(15) +#define B_BE_PSUS_OFF_CAPC_EN BIT(14) +#define B_BE_AFSM_PCIE_SUS_EN BIT(12) +#define B_BE_AFSM_WLSUS_EN BIT(11) +#define B_BE_APFM_SWLPS BIT(10) +#define B_BE_APFM_OFFMAC BIT(9) +#define B_BE_APFN_ONMAC BIT(8) +#define B_BE_CHIP_PDN_EN BIT(7) +#define B_BE_RDY_MACDIS BIT(6) + #define R_BE_SYS_CLK_CTRL 0x0008 #define B_BE_CPU_CLK_EN BIT(14) #define B_BE_SYMR_BE_CLK_EN BIT(13) @@ -3639,6 +3684,132 @@ #define B_BE_ANA_CLK_DIVISION_2 BIT(1) #define B_BE_CNTD16V_EN BIT(0) +#define R_BE_SYS_WL_EFUSE_CTRL 0x000A +#define B_BE_OTP_B_PWC_RPT BIT(15) +#define B_BE_OTP_S_PWC_RPT BIT(14) +#define B_BE_OTP_ISO_RPT BIT(13) +#define B_BE_OTP_BURST_RPT BIT(12) +#define B_BE_OTP_AUTOLOAD_RPT BIT(11) +#define B_BE_AUTOLOAD_DIS_A_DIE BIT(6) +#define B_BE_AUTOLOAD_SUS BIT(5) +#define B_BE_AUTOLOAD_DIS BIT(4) + +#define R_BE_SYS_PAGE_CLK_GATED 0x000C +#define B_BE_USB_APHY_PC_DLP_OP BIT(27) +#define B_BE_PCIE_APHY_PC_DLP_OP BIT(26) +#define B_BE_UPHY_POWER_READY_CHK BIT(25) +#define B_BE_CPHY_POWER_READY_CHK BIT(24) +#define B_BE_PCIE_PRST_DEBUNC_PERIOD_MASK GENMASK(23, 22) +#define B_BE_SYM_PRST_DEBUNC_SEL BIT(21) +#define B_BE_CPHY_AUXCLK_OP BIT(20) +#define B_BE_SOP_OFFUA_PC BIT(19) +#define B_BE_SOP_OFFPOOBS_PC BIT(18) +#define B_BE_PCIE_LAN1_MASK BIT(17) +#define B_BE_PCIE_LAN0_MASK BIT(16) +#define B_BE_DIS_CLK_REGF_GATE BIT(15) +#define B_BE_DIS_CLK_REGE_GATE BIT(14) +#define B_BE_DIS_CLK_REGD_GATE BIT(13) +#define B_BE_DIS_CLK_REGC_GATE BIT(12) +#define B_BE_DIS_CLK_REGB_GATE BIT(11) +#define B_BE_DIS_CLK_REGA_GATE BIT(10) +#define B_BE_DIS_CLK_REG9_GATE BIT(9) +#define B_BE_DIS_CLK_REG8_GATE BIT(8) +#define B_BE_DIS_CLK_REG7_GATE BIT(7) +#define B_BE_DIS_CLK_REG6_GATE BIT(6) +#define B_BE_DIS_CLK_REG5_GATE BIT(5) +#define B_BE_DIS_CLK_REG4_GATE BIT(4) +#define B_BE_DIS_CLK_REG3_GATE BIT(3) +#define B_BE_DIS_CLK_REG2_GATE BIT(2) +#define B_BE_DIS_CLK_REG1_GATE BIT(1) +#define B_BE_DIS_CLK_REG0_GATE BIT(0) + +#define R_BE_EFUSE_CTRL 0x0030 +#define B_BE_EF_MODE_SEL_MASK GENMASK(31, 30) +#define B_BE_EF_RDY BIT(29) +#define B_BE_EF_COMP_RESULT BIT(28) +#define B_BE_EF_ADDR_MASK GENMASK(15, 0) + +#define R_BE_EFUSE_CTRL_1_V1 0x0034 +#define B_BE_EF_DATA_MASK GENMASK(31, 0) + +#define R_BE_WL_BT_PWR_CTRL 0x0068 +#define B_BE_ISO_BD2PP BIT(31) +#define B_BE_LDOV12B_EN BIT(30) +#define B_BE_CKEN_BT BIT(29) +#define B_BE_FEN_BT BIT(28) +#define B_BE_BTCPU_BOOTSEL BIT(27) +#define B_BE_SPI_SPEEDUP BIT(26) +#define B_BE_BT_LDO_MODE BIT(25) +#define B_BE_ISO_BTPON2PP BIT(22) +#define B_BE_BT_FUNC_EN BIT(18) +#define B_BE_BT_HWPDN_SL BIT(17) +#define B_BE_BT_DISN_EN BIT(16) +#define B_BE_SDM_SRC_SEL BIT(12) +#define B_BE_ISO_BA2PP BIT(11) +#define B_BE_BT_AFE_LDO_EN BIT(10) +#define B_BE_BT_AFE_PLL_EN BIT(9) +#define B_BE_WLAN_32K_SEL BIT(6) +#define B_BE_WL_DRV_EXIST_IDX BIT(5) +#define B_BE_DOP_EHPAD BIT(4) +#define B_BE_WL_FUNC_EN BIT(2) +#define B_BE_WL_HWPDN_SL BIT(1) +#define B_BE_WL_HWPDN_EN BIT(0) + +#define R_BE_SYS_SDIO_CTRL 0x0070 +#define B_BE_MCM_FLASH_EN BIT(28) +#define B_BE_PCIE_SEC_LOAD BIT(26) +#define B_BE_PCIE_SER_RSTB BIT(25) +#define B_BE_PCIE_SEC_LOAD_CLR BIT(24) +#define B_BE_SDIO_CMD_SW_RST BIT(20) +#define B_BE_SDIO_INT_POLARITY BIT(19) +#define B_BE_SDIO_OFF_EN BIT(17) +#define B_BE_SDIO_ON_EN BIT(16) +#define B_BE_PCIE_DIS_L2__CTRL_LDO_HCI BIT(15) +#define B_BE_PCIE_DIS_L2_RTK_PERST BIT(14) +#define B_BE_PCIE_FORCE_PWR_NGAT BIT(13) +#define B_BE_PCIE_FORCE_IBX_EN BIT(12) +#define B_BE_PCIE_AUXCLK_GATE BIT(11) +#define B_BE_PCIE_WAIT_TIMEOUT_EVENT BIT(10) +#define B_BE_PCIE_WAIT_TIME BIT(9) +#define B_BE_L1OFF_TO_L0_RESUME_EVT BIT(8) +#define B_BE_USBA_FORCE_PWR_NGAT BIT(7) +#define B_BE_USBD_FORCE_PWR_NGAT BIT(6) +#define B_BE_BT_CTRL_USB_PWR BIT(5) +#define B_BE_USB_D_STATE_HOLD BIT(4) +#define B_BE_R_BE_FORCE_DP BIT(3) +#define B_BE_R_BE_DP_MODE BIT(2) +#define B_BE_RES_USB_MASS_STORAGE_DESC BIT(1) +#define B_BE_USB_WAIT_TIME BIT(0) + +#define R_BE_HCI_OPT_CTRL 0x0074 +#define B_BE_HCI_WLAN_IO_ST BIT(31) +#define B_BE_HCI_WLAN_IO_EN BIT(28) +#define B_BE_HAXIDMA_IO_ST BIT(27) +#define B_BE_HAXIDMA_BACKUP_RESTORE_ST BIT(26) +#define B_BE_HAXIDMA_IO_EN BIT(24) +#define B_BE_EN_PCIE_WAKE BIT(23) +#define B_BE_SDIO_PAD_H3L1 BIT(22) +#define B_BE_USBMAC_ANACLK_SW BIT(21) +#define B_BE_PCIE_CPHY_CCK_XTAL_SEL BIT(20) +#define B_BE_SDIO_DATA_PAD_SMT BIT(19) +#define B_BE_SDIO_PAD_E5 BIT(18) +#define B_BE_FORCE_PCIE_AUXCLK BIT(17) +#define B_BE_HCI_LA_ADDR_MAP BIT(16) +#define B_BE_HCI_LA_GLO_RST BIT(15) +#define B_BE_USB3_SUS_DIS BIT(14) +#define B_BE_NOPWR_CTRL_SEL BIT(13) +#define B_BE_USB_HOST_PWR_OFF_EN BIT(12) +#define B_BE_SYM_LPS_BLOCK_EN BIT(11) +#define B_BE_USB_LPM_ACT_EN BIT(10) +#define B_BE_USB_LPM_NY BIT(9) +#define B_BE_USB2_SUS_DIS BIT(8) +#define B_BE_SDIO_PAD_E_MASK GENMASK(7, 5) +#define B_BE_USB_LPPLL_EN BIT(4) +#define B_BE_USB1_1_USB2_0_DECISION BIT(3) +#define B_BE_ROP_SW15 BIT(2) +#define B_BE_PCI_CKRDY_OPT BIT(1) +#define B_BE_PCI_VAUX_EN BIT(0) + #define R_BE_PLATFORM_ENABLE 0x0088 #define B_BE_HOLD_AFTER_RESET BIT(11) #define B_BE_SYM_WLPLT_MEM_MUX_EN BIT(10) @@ -3652,6 +3823,35 @@ #define B_BE_WCPU_EN BIT(1) #define B_BE_PLATFORM_EN BIT(0) +#define R_BE_EFUSE_CTRL_2_V1 0x00A4 +#define B_BE_EF_ENT BIT(31) +#define B_BE_EF_TCOLUMN_EN BIT(29) +#define B_BE_BT_OTP_PWC_DIS BIT(28) +#define B_BE_EF_RDT BIT(27) +#define B_BE_R_SYM_AUTOLOAD_WITH_PMC_SEL BIT(24) +#define B_BE_EF_PGTS_MASK GENMASK(23, 20) +#define B_BE_EF_BURST BIT(19) +#define B_BE_EF_TEST_SEL_MASK GENMASK(18, 16) +#define B_BE_EF_TROW_EN BIT(15) +#define B_BE_EF_ERR_FLAG BIT(14) +#define B_BE_EF_FBURST_DIS BIT(13) +#define B_BE_EF_HT_SEL BIT(12) +#define B_BE_EF_DSB_EN BIT(11) +#define B_BE_EF_DLY_SEL_MASK GENMASK(3, 0) + +#define R_BE_PMC_DBG_CTRL2 0x00CC +#define B_BE_EFUSE_BURN_GNT_MASK GENMASK(31, 24) +#define B_BE_DIS_IOWRAP_TIMEOUT BIT(16) +#define B_BE_STOP_WL_PMC BIT(9) +#define B_BE_STOP_SYM_PMC BIT(8) +#define B_BE_SYM_REG_PCIE_WRMSK BIT(7) +#define B_BE_BT_ACCESS_WL_PAGE0 BIT(6) +#define B_BE_R_BE_RST_WLPMC BIT(5) +#define B_BE_R_BE_RST_PD12N BIT(4) +#define B_BE_SYSON_DIS_WLR_BE_WRMSK BIT(3) +#define B_BE_SYSON_DIS_PMCR_BE_WRMSK BIT(2) +#define B_BE_SYSON_R_BE_ARB_MASK GENMASK(1, 0) + #define R_BE_HALT_H2C_CTRL 0x0160 #define B_BE_HALT_H2C_TRIGGER BIT(0) @@ -3676,6 +3876,82 @@ #define R_BE_SECURE_BOOT_MALLOC_INFO 0x0184 +#define R_BE_FWS1IMR 0x0198 +#define B_BE_FS_RPWM_INT_EN_V1 BIT(24) +#define B_BE_PCIE_HOTRST_EN BIT(22) +#define B_BE_PCIE_SER_TIMEOUT_INDIC_EN BIT(21) +#define B_BE_PCIE_RXI300_SLVTOUT_INDIC_EN BIT(20) +#define B_BE_AON_PCIE_FLR_INT_EN BIT(19) +#define B_BE_PCIE_ERR_INDIC_INT_EN BIT(18) +#define B_BE_SDIO_ERR_INDIC_INT_EN BIT(17) +#define B_BE_USB_ERR_INDIC_INT_EN BIT(16) +#define B_BE_FS_GPIO27_INT_EN BIT(11) +#define B_BE_FS_GPIO26_INT_EN BIT(10) +#define B_BE_FS_GPIO25_INT_EN BIT(9) +#define B_BE_FS_GPIO24_INT_EN BIT(8) +#define B_BE_FS_GPIO23_INT_EN BIT(7) +#define B_BE_FS_GPIO22_INT_EN BIT(6) +#define B_BE_FS_GPIO21_INT_EN BIT(5) +#define B_BE_FS_GPIO20_INT_EN BIT(4) +#define B_BE_FS_GPIO19_INT_EN BIT(3) +#define B_BE_FS_GPIO18_INT_EN BIT(2) +#define B_BE_FS_GPIO17_INT_EN BIT(1) +#define B_BE_FS_GPIO16_INT_EN BIT(0) + +#define R_BE_HIMR0 0x01A0 +#define B_BE_WDT_DATACPU_TIMEOUT_INT_EN BIT(25) +#define B_BE_HALT_D2H_INT_EN BIT(24) +#define B_BE_WDT_TIMEOUT_INT_EN BIT(22) +#define B_BE_HALT_C2H_INT_EN BIT(21) +#define B_BE_RON_INT_EN BIT(20) +#define B_BE_PDNINT_EN BIT(19) +#define B_BE_SPSANA_OCP_INT_EN BIT(18) +#define B_BE_SPS_OCP_INT_EN BIT(17) +#define B_BE_BTON_STS_UPDATE_INT_EN BIT(16) +#define B_BE_GPIOF_INT_EN BIT(15) +#define B_BE_GPIOE_INT_EN BIT(14) +#define B_BE_GPIOD_INT_EN BIT(13) +#define B_BE_GPIOC_INT_EN BIT(12) +#define B_BE_GPIOB_INT_EN BIT(11) +#define B_BE_GPIOA_INT_EN BIT(10) +#define B_BE_GPIO9_INT_EN BIT(9) +#define B_BE_GPIO8_INT_EN BIT(8) +#define B_BE_GPIO7_INT_EN BIT(7) +#define B_BE_GPIO6_INT_EN BIT(6) +#define B_BE_GPIO5_INT_EN BIT(5) +#define B_BE_GPIO4_INT_EN BIT(4) +#define B_BE_GPIO3_INT_EN BIT(3) +#define B_BE_GPIO2_INT_EN BIT(2) +#define B_BE_GPIO1_INT_EN BIT(1) +#define B_BE_GPIO0_INT_EN BIT(0) + +#define R_BE_HISR0 0x01A4 +#define B_BE_WDT_DATACPU_TIMEOUT_INT BIT(25) +#define B_BE_HALT_D2H_INT BIT(24) +#define B_BE_WDT_TIMEOUT_INT BIT(22) +#define B_BE_HALT_C2H_INT BIT(21) +#define B_BE_RON_INT BIT(20) +#define B_BE_PDNINT BIT(19) +#define B_BE_SPSANA_OCP_INT BIT(18) +#define B_BE_SPS_OCP_INT BIT(17) +#define B_BE_BTON_STS_UPDATE_INT BIT(16) +#define B_BE_GPIOF_INT BIT(15) +#define B_BE_GPIOE_INT BIT(14) +#define B_BE_GPIOD_INT BIT(13) +#define B_BE_GPIOC_INT BIT(12) +#define B_BE_GPIOB_INT BIT(11) +#define B_BE_GPIOA_INT BIT(10) +#define B_BE_GPIO9_INT BIT(9) +#define B_BE_GPIO8_INT BIT(8) +#define B_BE_GPIO7_INT BIT(7) +#define B_BE_GPIO6_INT BIT(6) +#define B_BE_GPIO5_INT BIT(5) +#define B_BE_GPIO4_INT BIT(4) +#define B_BE_GPIO3_INT BIT(3) +#define B_BE_GPIO2_INT BIT(2) +#define B_BE_GPIO1_INT BIT(1) +#define B_BE_GPIO0_INT BIT(0) + #define R_BE_WCPU_FW_CTRL 0x01E0 #define B_BE_RUN_ENV_MASK GENMASK(31, 30) #define B_BE_WCPU_FWDL_STATUS_MASK GENMASK(29, 26) @@ -3721,6 +3997,15 @@ #define R_BE_UDM2 0x01F8 #define B_BE_UDM2_EPC_RA_MASK GENMASK(31, 0) +#define R_BE_IC_PWR_STATE 0x03F0 +#define B_BE_WHOLE_SYS_PWR_STE_MASK GENMASK(25, 16) +#define MAC_AX_SYS_ACT 0x220 +#define B_BE_WLMAC_PWR_STE_MASK GENMASK(9, 8) +#define B_BE_UART_HCISYS_PWR_STE_MASK GENMASK(7, 6) +#define B_BE_SDIO_HCISYS_PWR_STE_MASK GENMASK(5, 4) +#define B_BE_USB_HCISYS_PWR_STE_MASK GENMASK(3, 2) +#define B_BE_PCIE_HCISYS_PWR_STE_MASK GENMASK(1, 0) + #define R_BE_DCPU_PLATFORM_ENABLE 0x0888 #define B_BE_DCPU_SYM_DPLT_MEM_MUX_EN BIT(10) #define B_BE_DCPU_WARM_EN BIT(9) @@ -3732,6 +4017,133 @@ #define R_BE_FILTER_MODEL_ADDR 0x0C04 +#define R_BE_WLAN_WDT 0x3050 +#define B_BE_WLAN_WDT_TIMEOUT BIT(31) +#define B_BE_WLAN_WDT_TIMER_CLEAR BIT(4) +#define B_BE_WLAN_WDT_BYPASS BIT(1) +#define B_BE_WLAN_WDT_ENABLE BIT(0) + +#define R_BE_AXIDMA_WDT 0x305C +#define B_BE_AXIDMA_WDT_TIMEOUT BIT(31) +#define B_BE_AXIDMA_WDT_TIMER_CLEAR BIT(4) +#define B_BE_AXIDMA_WDT_BYPASS BIT(1) +#define B_BE_AXIDMA_WDT_ENABLE BIT(0) + +#define R_BE_AON_WDT 0x3068 +#define B_BE_AON_WDT_TIMEOUT BIT(31) +#define B_BE_AON_WDT_TIMER_CLEAR BIT(4) +#define B_BE_AON_WDT_BYPASS BIT(1) +#define B_BE_AON_WDT_ENABLE BIT(0) + +#define R_BE_AON_WDT_TMR 0x306C +#define R_BE_MDIO_WDT_TMR 0x3090 +#define R_BE_LA_MODE_WDT_TMR 0x309C +#define R_BE_WDT_AR_TMR 0x3144 +#define R_BE_WDT_AW_TMR 0x3150 +#define R_BE_WLAN_WDT_TMR 0x3054 +#define R_BE_WDT_W_TMR 0x315C +#define R_BE_AXIDMA_WDT_TMR 0x3060 +#define R_BE_WDT_B_TMR 0x3164 +#define R_BE_WDT_R_TMR 0x316C +#define R_BE_LOCAL_WDT_TMR 0x3084 + +#define R_BE_LOCAL_WDT 0x3080 +#define B_BE_LOCAL_WDT_TIMEOUT BIT(31) +#define B_BE_LOCAL_WDT_TIMER_CLEAR BIT(4) +#define B_BE_LOCAL_WDT_BYPASS BIT(1) +#define B_BE_LOCAL_WDT_ENABLE BIT(0) + +#define R_BE_MDIO_WDT 0x308C +#define B_BE_MDIO_WDT_TIMEOUT BIT(31) +#define B_BE_MDIO_WDT_TIMER_CLEAR BIT(4) +#define B_BE_MDIO_WDT_BYPASS BIT(1) +#define B_BE_MDIO_WDT_ENABLE BIT(0) + +#define R_BE_LA_MODE_WDT 0x3098 +#define B_BE_LA_MODE_WDT_TIMEOUT BIT(31) +#define B_BE_LA_MODE_WDT_TIMER_CLEAR BIT(4) +#define B_BE_LA_MODE_WDT_BYPASS BIT(1) +#define B_BE_LA_MODE_WDT_ENABLE BIT(0) + +#define R_BE_WDT_AR 0x3140 +#define B_BE_WDT_AR_TIMEOUT BIT(31) +#define B_BE_WDT_AR_TIMER_CLEAR BIT(4) +#define B_BE_WDT_AR_BYPASS BIT(1) +#define B_BE_WDT_AR_ENABLE BIT(0) + +#define R_BE_WDT_AW 0x314C +#define B_BE_WDT_AW_TIMEOUT BIT(31) +#define B_BE_WDT_AW_TIMER_CLEAR BIT(4) +#define B_BE_WDT_AW_BYPASS BIT(1) +#define B_BE_WDT_AW_ENABLE BIT(0) + +#define R_BE_WDT_W 0x3158 +#define B_BE_WDT_W_TIMEOUT BIT(31) +#define B_BE_WDT_W_TIMER_CLEAR BIT(4) +#define B_BE_WDT_W_BYPASS BIT(1) +#define B_BE_WDT_W_ENABLE BIT(0) + +#define R_BE_WDT_B 0x3160 +#define B_BE_WDT_B_TIMEOUT BIT(31) +#define B_BE_WDT_B_TIMER_CLEAR BIT(4) +#define B_BE_WDT_B_BYPASS BIT(1) +#define B_BE_WDT_B_ENABLE BIT(0) + +#define R_BE_WDT_R 0x3168 +#define B_BE_WDT_R_TIMEOUT BIT(31) +#define B_BE_WDT_R_TIMER_CLEAR BIT(4) +#define B_BE_WDT_R_BYPASS BIT(1) +#define B_BE_WDT_R_ENABLE BIT(0) + +#define R_BE_LTR_DECISION_CTRL_V1 0x3610 +#define B_BE_ENABLE_LTR_CTL_DECISION BIT(31) +#define B_BE_LAT_LTR_IDX_DRV_VLD_V1 BIT(24) +#define B_BE_LAT_LTR_IDX_DRV_V1_MASK GENMASK(23, 22) +#define B_BE_LAT_LTR_IDX_FW_VLD_V1 BIT(21) +#define B_BE_LAT_LTR_IDX_FW_V1_MASK GENMASK(20, 19) +#define B_BE_LAT_LTR_IDX_HW_VLD_V1 BIT(18) +#define B_BE_LAT_LTR_IDX_HW_V1_MASK GENMASK(17, 16) +#define B_BE_LTR_IDX_DRV_V1_MASK GENMASK(15, 14) +#define B_BE_LTR_REQ_DRV_V1 BIT(13) +#define B_BE_LTR_IDX_DISABLE_V1_MASK GENMASK(9, 8) +#define B_BE_LTR_EN_PORT_V1_MASK GENMASK(6, 4) +#define B_BE_LTR_DRV_DEC_EN_V1 BIT(6) +#define B_BE_LTR_FW_DEC_EN_V1 BIT(5) +#define B_BE_LTR_HW_DEC_EN_V1 BIT(4) +#define B_BE_LTR_SPACE_IDX_MASK GENMASK(1, 0) + +#define R_BE_LTR_LATENCY_IDX0_V1 0x3614 +#define R_BE_LTR_LATENCY_IDX1_V1 0x3618 +#define R_BE_LTR_LATENCY_IDX2_V1 0x361C +#define R_BE_LTR_LATENCY_IDX3_V1 0x3620 + +#define R_BE_HCI_FUNC_EN 0x7880 +#define B_BE_HCI_CR_PROTECT BIT(31) +#define B_BE_HCI_TRXBUF_EN BIT(2) +#define B_BE_HCI_RXDMA_EN BIT(1) +#define B_BE_HCI_TXDMA_EN BIT(0) + +#define R_BE_LTR_CTRL_0 0x8410 +#define B_BE_LTR_REQ_FW BIT(18) +#define B_BE_LTR_IDX_FW_MASK GENMASK(17, 16) +#define B_BE_LTR_IDLE_TIMER_IDX_MASK GENMASK(10, 8) +#define B_BE_LTR_WD_NOEMP_CHK BIT(1) +#define B_BE_LTR_HW_EN BIT(0) + +#define R_BE_LTR_CFG_0 0x8414 +#define B_BE_LTR_IDX_DISABLE_MASK GENMASK(17, 16) +#define B_BE_LTR_IDX_IDLE_MASK GENMASK(15, 14) +#define B_BE_LTR_IDX_ACTIVE_MASK GENMASK(13, 12) +#define B_BE_LTR_IDLE_TIMER_IDX_MASK GENMASK(10, 8) +#define B_BE_EN_LTR_CMAC_RX_USE_PG_CHK BIT(3) +#define B_BE_EN_LTR_WD_NON_EMPTY_CHK BIT(2) +#define B_BE_EN_LTR_HAXIDMA_TX_IDLE_CHK BIT(1) +#define B_BE_EN_LTR_HAXIDMA_RX_IDLE_CHK BIT(0) + +#define R_BE_LTR_CFG_1 0x8418 +#define B_BE_LTR_CMAC1_RX_USE_PG_TH_MASK GENMASK(27, 16) +#define B_BE_LTR_CMAC0_RX_USE_PG_TH_MASK GENMASK(11, 0) + #define R_BE_PLE_DBG_FUN_INTF_CTL 0x9110 #define B_BE_PLE_DFI_ACTIVE BIT(31) #define B_BE_PLE_DFI_TRGSEL_MASK GENMASK(19, 16) @@ -3740,6 +4152,28 @@ #define R_BE_PLE_DBG_FUN_INTF_DATA 0x9114 #define B_BE_PLE_DFI_DATA_MASK GENMASK(31, 0) +#define R_BE_HAXI_INIT_CFG1 0xB000 +#define B_BE_CFG_WD_PERIOD_IDLE_MASK GENMASK(31, 28) +#define B_BE_CFG_WD_PERIOD_ACTIVE_MASK GENMASK(27, 24) +#define B_BE_EN_RO_IDX_UPD_BY_IO BIT(19) +#define B_BE_RST_KEEP_REG BIT(18) +#define B_BE_FLUSH_HAXI_MST BIT(17) +#define B_BE_SET_BDRAM_BOUND BIT(16) +#define B_BE_ADDRINFO_ALIGN4B_EN BIT(15) +#define B_BE_RXBD_DONE_MODE_MASK GENMASK(14, 13) +#define B_BE_RXQ_RXBD_MODE_MASK GENMASK(12, 11) +#define B_BE_DMA_MODE_MASK GENMASK(10, 8) +#define S_BE_DMA_MOD_PCIE_NO_DATA_CPU 0x0 +#define S_BE_DMA_MOD_PCIE_DATA_CPU 0x1 +#define S_BE_DMA_MOD_USB 0x4 +#define S_BE_DMA_MOD_SDIO 0x6 +#define B_BE_STOP_AXI_MST BIT(7) +#define B_BE_RXDMA_ALIGN64B_EN BIT(6) +#define B_BE_RXDMA_EN BIT(5) +#define B_BE_TXDMA_EN BIT(4) +#define B_BE_MAX_RXDMA_MASK GENMASK(3, 2) +#define B_BE_MAX_TXDMA_MASK GENMASK(1, 0) + #define R_BE_CMAC_FUNC_EN 0x10000 #define R_BE_CMAC_FUNC_EN_C1 0x14000 #define B_BE_CMAC_CRPRT BIT(31) @@ -4619,6 +5053,7 @@ #define B_SEG0CSI_EN BIT(23) #define R_BSS_CLR_MAP 0x43ac #define R_BSS_CLR_MAP_V1 0x43B0 +#define R_BSS_CLR_MAP_V2 0x4EB0 #define B_BSS_CLR_MAP_VLD0 BIT(28) #define B_BSS_CLR_MAP_TGT GENMASK(27, 22) #define B_BSS_CLR_MAP_STAID GENMASK(21, 11) @@ -4912,6 +5347,8 @@ #define R_BMODE_PDTH_EN_V1 0x4B74 #define R_BMODE_PDTH_EN_V2 0x6718 #define B_BMODE_PDTH_LIMIT_EN_MSK_V1 BIT(30) +#define R_BSS_CLR_VLD_V2 0x4EBC +#define B_BSS_CLR_VLD0_V2 BIT(2) #define R_CFO_COMP_SEG1_L 0x5384 #define R_CFO_COMP_SEG1_H 0x5388 #define R_CFO_COMP_SEG1_CTRL 0x538C diff --git a/drivers/net/wireless/realtek/rtw89/regd.c b/drivers/net/wireless/realtek/rtw89/regd.c index ca99422e600f1..d0857ef60ea6a 100644 --- a/drivers/net/wireless/realtek/rtw89/regd.c +++ b/drivers/net/wireless/realtek/rtw89/regd.c @@ -112,9 +112,9 @@ static const struct rtw89_regd rtw89_regd_map[] = { COUNTRY_REGD("MY", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("PK", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("PH", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("SG", RTW89_ETSI, RTW89_ETSI, RTW89_NA), + COUNTRY_REGD("SG", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("LK", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("TW", RTW89_FCC, RTW89_FCC, RTW89_NA), + COUNTRY_REGD("TW", RTW89_FCC, RTW89_FCC, RTW89_ETSI), COUNTRY_REGD("TH", RTW89_ETSI, RTW89_ETSI, RTW89_THAILAND), COUNTRY_REGD("VN", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("AU", RTW89_ACMA, RTW89_ACMA, RTW89_ACMA), @@ -179,7 +179,7 @@ static const struct rtw89_regd rtw89_regd_map[] = { COUNTRY_REGD("GE", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("GI", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("GL", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("GD", RTW89_FCC, RTW89_FCC, RTW89_NA), + COUNTRY_REGD("GD", RTW89_FCC, RTW89_FCC, RTW89_FCC), COUNTRY_REGD("GP", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("GU", RTW89_FCC, RTW89_FCC, RTW89_NA), COUNTRY_REGD("GG", RTW89_ETSI, RTW89_ETSI, RTW89_NA), @@ -257,7 +257,42 @@ static const struct rtw89_regd rtw89_regd_map[] = { COUNTRY_REGD("PS", RTW89_ETSI, RTW89_ETSI, RTW89_NA), }; -static const struct rtw89_regd *rtw89_regd_find_reg_by_name(char *alpha2) +static const char rtw89_alpha2_list_eu[][3] = { + "AT", + "BE", + "CY", + "CZ", + "DK", + "EE", + "FI", + "FR", + "DE", + "GR", + "HU", + "IS", + "IE", + "IT", + "LV", + "LI", + "LT", + "LU", + "MT", + "MC", + "NL", + "NO", + "PL", + "PT", + "SK", + "SI", + "ES", + "SE", + "CH", + "BG", + "HR", + "RO", +}; + +static const struct rtw89_regd *rtw89_regd_find_reg_by_name(const char *alpha2) { u32 i; @@ -274,6 +309,24 @@ static bool rtw89_regd_is_ww(const struct rtw89_regd *regd) return regd == &rtw89_ww_regd; } +static u8 rtw89_regd_get_index(const struct rtw89_regd *regd) +{ + BUILD_BUG_ON(ARRAY_SIZE(rtw89_regd_map) > RTW89_REGD_MAX_COUNTRY_NUM); + + if (rtw89_regd_is_ww(regd)) + return RTW89_REGD_MAX_COUNTRY_NUM; + + return regd - rtw89_regd_map; +} + +static u8 rtw89_regd_get_index_by_name(const char *alpha2) +{ + const struct rtw89_regd *regd; + + regd = rtw89_regd_find_reg_by_name(alpha2); + return rtw89_regd_get_index(regd); +} + #define rtw89_debug_regd(_dev, _regd, _desc, _argv...) \ do { \ typeof(_regd) __r = _regd; \ @@ -291,19 +344,22 @@ static void rtw89_regd_setup_unii4(struct rtw89_dev *rtwdev, const struct rtw89_chip_info *chip = rtwdev->chip; bool regd_allow_unii_4 = chip->support_unii4; struct ieee80211_supported_band *sband; + struct rtw89_acpi_dsm_result res = {}; int ret; u8 val; if (!chip->support_unii4) goto bottom; - ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_59G_EN, &val); + ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_59G_EN, &res); if (ret) { rtw89_debug(rtwdev, RTW89_DBG_REGD, "acpi: cannot eval unii 4: %d\n", ret); goto bottom; } + val = res.u.value; + rtw89_debug(rtwdev, RTW89_DBG_REGD, "acpi: eval if allow unii 4: %d\n", val); @@ -332,25 +388,99 @@ static void rtw89_regd_setup_unii4(struct rtw89_dev *rtwdev, sband->n_channels -= 3; } +static void __rtw89_regd_setup_policy_6ghz(struct rtw89_dev *rtwdev, bool block, + const char *alpha2) +{ + struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; + u8 index; + + index = rtw89_regd_get_index_by_name(alpha2); + if (index == RTW89_REGD_MAX_COUNTRY_NUM) { + rtw89_debug(rtwdev, RTW89_DBG_REGD, "%s: unknown alpha2 %c%c\n", + __func__, alpha2[0], alpha2[1]); + return; + } + + if (block) + set_bit(index, regulatory->block_6ghz); + else + clear_bit(index, regulatory->block_6ghz); +} + +static void rtw89_regd_setup_policy_6ghz(struct rtw89_dev *rtwdev) +{ + struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; + const struct rtw89_acpi_country_code *country; + const struct rtw89_acpi_policy_6ghz *ptr; + struct rtw89_acpi_dsm_result res = {}; + bool to_block; + int i, j; + int ret; + + ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_6G_BP, &res); + if (ret) { + rtw89_debug(rtwdev, RTW89_DBG_REGD, + "acpi: cannot eval policy 6ghz: %d\n", ret); + return; + } + + ptr = res.u.policy_6ghz; + + switch (ptr->policy_mode) { + case RTW89_ACPI_POLICY_BLOCK: + to_block = true; + break; + case RTW89_ACPI_POLICY_ALLOW: + to_block = false; + /* only below list is allowed; block all first */ + bitmap_fill(regulatory->block_6ghz, RTW89_REGD_MAX_COUNTRY_NUM); + break; + default: + rtw89_debug(rtwdev, RTW89_DBG_REGD, + "%s: unknown policy mode: %d\n", __func__, + ptr->policy_mode); + goto out; + } + + for (i = 0; i < ptr->country_count; i++) { + country = &ptr->country_list[i]; + if (memcmp("EU", country->alpha2, 2) != 0) { + __rtw89_regd_setup_policy_6ghz(rtwdev, to_block, + country->alpha2); + continue; + } + + for (j = 0; j < ARRAY_SIZE(rtw89_alpha2_list_eu); j++) + __rtw89_regd_setup_policy_6ghz(rtwdev, to_block, + rtw89_alpha2_list_eu[j]); + } + +out: + kfree(ptr); +} + static void rtw89_regd_setup_6ghz(struct rtw89_dev *rtwdev, struct wiphy *wiphy) { const struct rtw89_chip_info *chip = rtwdev->chip; bool chip_support_6ghz = chip->support_bands & BIT(NL80211_BAND_6GHZ); bool regd_allow_6ghz = chip_support_6ghz; struct ieee80211_supported_band *sband; + struct rtw89_acpi_dsm_result res = {}; int ret; u8 val; if (!chip_support_6ghz) goto bottom; - ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_6G_DIS, &val); + ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_6G_DIS, &res); if (ret) { rtw89_debug(rtwdev, RTW89_DBG_REGD, "acpi: cannot eval 6ghz: %d\n", ret); goto bottom; } + val = res.u.value; + rtw89_debug(rtwdev, RTW89_DBG_REGD, "acpi: eval if disallow 6ghz: %d\n", val); @@ -369,8 +499,10 @@ static void rtw89_regd_setup_6ghz(struct rtw89_dev *rtwdev, struct wiphy *wiphy) rtw89_debug(rtwdev, RTW89_DBG_REGD, "regd: allow 6ghz: %d\n", regd_allow_6ghz); - if (regd_allow_6ghz) + if (regd_allow_6ghz) { + rtw89_regd_setup_policy_6ghz(rtwdev); return; + } sband = wiphy->bands[NL80211_BAND_6GHZ]; if (!sband) @@ -430,6 +562,33 @@ int rtw89_regd_init(struct rtw89_dev *rtwdev, return 0; } +static void rtw89_regd_apply_policy_6ghz(struct rtw89_dev *rtwdev, + struct wiphy *wiphy) +{ + struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; + const struct rtw89_regd *regd = regulatory->regd; + struct ieee80211_supported_band *sband; + u8 index; + int i; + + index = rtw89_regd_get_index(regd); + if (index == RTW89_REGD_MAX_COUNTRY_NUM) + return; + + if (!test_bit(index, regulatory->block_6ghz)) + return; + + rtw89_debug(rtwdev, RTW89_DBG_REGD, "%c%c 6 GHz is blocked by policy\n", + regd->alpha2[0], regd->alpha2[1]); + + sband = wiphy->bands[NL80211_BAND_6GHZ]; + if (!sband) + return; + + for (i = 0; i < sband->n_channels; i++) + sband->channels[i].flags |= IEEE80211_CHAN_DISABLED; +} + static void rtw89_regd_notifier_apply(struct rtw89_dev *rtwdev, struct wiphy *wiphy, struct regulatory_request *request) @@ -444,6 +603,8 @@ static void rtw89_regd_notifier_apply(struct rtw89_dev *rtwdev, wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE; else wiphy->regulatory_flags &= ~REGULATORY_COUNTRY_IE_IGNORE; + + rtw89_regd_apply_policy_6ghz(rtwdev, wiphy); } void rtw89_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 50522ff85003d..dd15b904cd2fb 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -500,7 +500,8 @@ static void rtw8851b_efuse_parsing_gain_offset(struct rtw89_dev *rtwdev, gain->offset_valid = valid; } -static int rtw8851b_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map) +static int rtw8851b_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, + enum rtw89_efuse_block block) { struct rtw89_efuse *efuse = &rtwdev->efuse; struct rtw8851b_efuse *map; @@ -2393,12 +2394,14 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .bacam_num = 2, .bacam_dynamic_num = 4, .bacam_ver = RTW89_BACAM_V0, + .ppdu_max_usr = 4, .sec_ctrl_efuse_size = 4, .physical_efuse_size = 1216, .logical_efuse_size = 2048, .limit_efuse_size = 1280, .dav_phy_efuse_size = 0, .dav_log_efuse_size = 0, + .efuse_blocks = NULL, .phycap_addr = 0x580, .phycap_size = 128, .para_ver = 0, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851be.c b/drivers/net/wireless/realtek/rtw89/rtw8851be.c index 0f7711c50bd15..ade69bd30fc86 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851be.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851be.c @@ -10,6 +10,7 @@ #include "rtw8851b.h" static const struct rtw89_pci_info rtw8851b_pci_info = { + .gen_def = &rtw89_pci_gen_ax, .txbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_mode = MAC_AX_RXBD_PKT, @@ -33,6 +34,7 @@ static const struct rtw89_pci_info rtw8851b_pci_info = { .max_tag_num_mask = B_AX_MAX_TAG_NUM, .rxbd_rwptr_clr_reg = R_AX_RXBD_RWPTR_CLR, .txbd_rwptr_clr2_reg = 0, + .dma_io_stop = {R_AX_PCIE_DMA_STOP1, B_AX_STOP_PCIEIO}, .dma_stop1 = {R_AX_PCIE_DMA_STOP1, B_AX_TX_STOP1_MASK_V1}, .dma_stop2 = {0}, .dma_busy1 = {R_AX_PCIE_DMA_BUSY1, DMA_BUSY1_CHECK_V1}, @@ -41,6 +43,7 @@ static const struct rtw89_pci_info rtw8851b_pci_info = { .rpwm_addr = R_AX_PCIE_HRPWM, .cpwm_addr = R_AX_CPWM, + .mit_addr = R_AX_INT_MIT_RX, .tx_dma_ch_mask = BIT(RTW89_TXCH_ACH4) | BIT(RTW89_TXCH_ACH5) | BIT(RTW89_TXCH_ACH6) | BIT(RTW89_TXCH_ACH7) | BIT(RTW89_TXCH_CH10) | BIT(RTW89_TXCH_CH11), diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index 0c36e6180e25b..2bddd0acb1956 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -537,7 +537,8 @@ static void rtw8852a_efuse_parsing_tssi(struct rtw89_dev *rtwdev, } } -static int rtw8852a_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map) +static int rtw8852a_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, + enum rtw89_efuse_block block) { struct rtw89_efuse *efuse = &rtwdev->efuse; struct rtw8852a_efuse *map; @@ -2129,12 +2130,14 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .bacam_num = 2, .bacam_dynamic_num = 4, .bacam_ver = RTW89_BACAM_V0, + .ppdu_max_usr = 4, .sec_ctrl_efuse_size = 4, .physical_efuse_size = 1216, .logical_efuse_size = 1536, .limit_efuse_size = 1152, .dav_phy_efuse_size = 0, .dav_log_efuse_size = 0, + .efuse_blocks = NULL, .phycap_addr = 0x580, .phycap_size = 128, .para_ver = 0x0, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c index d835a44a1d0d0..f1e890bde0499 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c @@ -10,6 +10,7 @@ #include "rtw8852a.h" static const struct rtw89_pci_info rtw8852a_pci_info = { + .gen_def = &rtw89_pci_gen_ax, .txbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_mode = MAC_AX_RXBD_PKT, @@ -24,6 +25,7 @@ static const struct rtw89_pci_info rtw8852a_pci_info = { .autok_en = MAC_AX_PCIE_DISABLE, .io_rcy_en = MAC_AX_PCIE_DISABLE, .io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_6MS, + .rx_ring_eq_is_full = false, .init_cfg_reg = R_AX_PCIE_INIT_CFG1, .txhci_en_bit = B_AX_TXHCI_EN, @@ -33,6 +35,7 @@ static const struct rtw89_pci_info rtw8852a_pci_info = { .max_tag_num_mask = B_AX_MAX_TAG_NUM, .rxbd_rwptr_clr_reg = R_AX_RXBD_RWPTR_CLR, .txbd_rwptr_clr2_reg = R_AX_TXBD_RWPTR_CLR2, + .dma_io_stop = {R_AX_PCIE_DMA_STOP1, B_AX_STOP_PCIEIO}, .dma_stop1 = {R_AX_PCIE_DMA_STOP1, B_AX_TX_STOP1_MASK}, .dma_stop2 = {R_AX_PCIE_DMA_STOP2, B_AX_TX_STOP2_ALL}, .dma_busy1 = {R_AX_PCIE_DMA_BUSY1, DMA_BUSY1_CHECK}, @@ -41,6 +44,7 @@ static const struct rtw89_pci_info rtw8852a_pci_info = { .rpwm_addr = R_AX_PCIE_HRPWM, .cpwm_addr = R_AX_CPWM, + .mit_addr = R_AX_INT_MIT_RX, .tx_dma_ch_mask = 0, .bd_idx_addr_low_power = NULL, .dma_addr_set = &rtw89_pci_ch_dma_addr_set, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 9d4e6f08218de..a576e4f478809 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -638,7 +638,8 @@ static void rtw8852b_efuse_parsing_gain_offset(struct rtw89_dev *rtwdev, gain->offset_valid = valid; } -static int rtw8852b_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map) +static int rtw8852b_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, + enum rtw89_efuse_block block) { struct rtw89_efuse *efuse = &rtwdev->efuse; struct rtw8852b_efuse *map; @@ -2563,12 +2564,14 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .bacam_num = 2, .bacam_dynamic_num = 4, .bacam_ver = RTW89_BACAM_V0, + .ppdu_max_usr = 4, .sec_ctrl_efuse_size = 4, .physical_efuse_size = 1216, .logical_efuse_size = 2048, .limit_efuse_size = 1280, .dav_phy_efuse_size = 96, .dav_log_efuse_size = 16, + .efuse_blocks = NULL, .phycap_addr = 0x580, .phycap_size = 128, .para_ver = 0, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852be.c b/drivers/net/wireless/realtek/rtw89/rtw8852be.c index ecf39d2d9f81f..920b20bbcfb73 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852be.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852be.c @@ -10,6 +10,7 @@ #include "rtw8852b.h" static const struct rtw89_pci_info rtw8852b_pci_info = { + .gen_def = &rtw89_pci_gen_ax, .txbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_mode = MAC_AX_RXBD_PKT, @@ -24,6 +25,7 @@ static const struct rtw89_pci_info rtw8852b_pci_info = { .autok_en = MAC_AX_PCIE_DISABLE, .io_rcy_en = MAC_AX_PCIE_DISABLE, .io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_6MS, + .rx_ring_eq_is_full = false, .init_cfg_reg = R_AX_PCIE_INIT_CFG1, .txhci_en_bit = B_AX_TXHCI_EN, @@ -33,6 +35,7 @@ static const struct rtw89_pci_info rtw8852b_pci_info = { .max_tag_num_mask = B_AX_MAX_TAG_NUM, .rxbd_rwptr_clr_reg = R_AX_RXBD_RWPTR_CLR, .txbd_rwptr_clr2_reg = 0, + .dma_io_stop = {R_AX_PCIE_DMA_STOP1, B_AX_STOP_PCIEIO}, .dma_stop1 = {R_AX_PCIE_DMA_STOP1, B_AX_TX_STOP1_MASK_V1}, .dma_stop2 = {0}, .dma_busy1 = {R_AX_PCIE_DMA_BUSY1, DMA_BUSY1_CHECK_V1}, @@ -41,6 +44,7 @@ static const struct rtw89_pci_info rtw8852b_pci_info = { .rpwm_addr = R_AX_PCIE_HRPWM, .cpwm_addr = R_AX_CPWM, + .mit_addr = R_AX_INT_MIT_RX, .tx_dma_ch_mask = BIT(RTW89_TXCH_ACH4) | BIT(RTW89_TXCH_ACH5) | BIT(RTW89_TXCH_ACH6) | BIT(RTW89_TXCH_ACH7) | BIT(RTW89_TXCH_CH10) | BIT(RTW89_TXCH_CH11), diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index 3b7d8ab39bab7..ea152a4613f21 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -426,11 +426,36 @@ static void rtw8852c_efuse_parsing_gain_offset(struct rtw89_dev *rtwdev, valid |= _decode_efuse_gain(map->rx_gain_5g_high, &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_5G_HIGH], &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_5G_HIGH]); + valid |= _decode_efuse_gain(map->rx_gain_6g_l0, + &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_L0], + &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_L0]); + valid |= _decode_efuse_gain(map->rx_gain_6g_l1, + &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_L1], + &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_L1]); + valid |= _decode_efuse_gain(map->rx_gain_6g_m0, + &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_M0], + &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_M0]); + valid |= _decode_efuse_gain(map->rx_gain_6g_m1, + &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_M1], + &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_M1]); + valid |= _decode_efuse_gain(map->rx_gain_6g_h0, + &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_H0], + &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_H0]); + valid |= _decode_efuse_gain(map->rx_gain_6g_h1, + &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_H1], + &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_H1]); + valid |= _decode_efuse_gain(map->rx_gain_6g_uh0, + &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_UH0], + &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_UH0]); + valid |= _decode_efuse_gain(map->rx_gain_6g_uh1, + &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_UH1], + &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_UH1]); gain->offset_valid = valid; } -static int rtw8852c_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map) +static int rtw8852c_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, + enum rtw89_efuse_block block) { struct rtw89_efuse *efuse = &rtwdev->efuse; struct rtw8852c_efuse *map; @@ -2877,12 +2902,14 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .bacam_num = 8, .bacam_dynamic_num = 8, .bacam_ver = RTW89_BACAM_V0_EXT, + .ppdu_max_usr = 8, .sec_ctrl_efuse_size = 4, .physical_efuse_size = 1216, .logical_efuse_size = 2048, .limit_efuse_size = 1280, .dav_phy_efuse_size = 96, .dav_log_efuse_size = 16, + .efuse_blocks = NULL, .phycap_addr = 0x590, .phycap_size = 0x60, .para_ver = 0x1, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.h b/drivers/net/wireless/realtek/rtw89/rtw8852c.h index ac642808a81ff..77b05daedd105 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.h @@ -73,9 +73,25 @@ struct rtw8852c_efuse { u8 bw40_1s_tssi_6g_a[TSSI_MCS_6G_CH_GROUP_NUM]; u8 rsvd14[10]; u8 bw40_1s_tssi_6g_b[TSSI_MCS_6G_CH_GROUP_NUM]; - u8 rsvd15[110]; + u8 rsvd15[94]; + u8 rx_gain_6g_l0; + u8 rsvd16; + u8 rx_gain_6g_l1; + u8 rsvd17; + u8 rx_gain_6g_m0; + u8 rsvd18; + u8 rx_gain_6g_m1; + u8 rsvd19; + u8 rx_gain_6g_h0; + u8 rsvd20; + u8 rx_gain_6g_h1; + u8 rsvd21; + u8 rx_gain_6g_uh0; + u8 rsvd22; + u8 rx_gain_6g_uh1; + u8 rsvd23; u8 channel_plan_6g; - u8 rsvd16[71]; + u8 rsvd24[71]; union { struct rtw8852c_u_efuse u; struct rtw8852c_e_efuse e; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c index 80490a5437df6..4592de3dbd942 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c @@ -19,6 +19,7 @@ static const struct rtw89_pci_bd_idx_addr rtw8852c_bd_idx_addr_low_power = { }; static const struct rtw89_pci_info rtw8852c_pci_info = { + .gen_def = &rtw89_pci_gen_ax, .txbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_mode = MAC_AX_RXBD_PKT, @@ -33,6 +34,7 @@ static const struct rtw89_pci_info rtw8852c_pci_info = { .autok_en = MAC_AX_PCIE_DISABLE, .io_rcy_en = MAC_AX_PCIE_ENABLE, .io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_6MS, + .rx_ring_eq_is_full = false, .init_cfg_reg = R_AX_HAXI_INIT_CFG1, .txhci_en_bit = B_AX_TXHCI_EN_V1, @@ -42,6 +44,7 @@ static const struct rtw89_pci_info rtw8852c_pci_info = { .max_tag_num_mask = B_AX_MAX_TAG_NUM_V1_MASK, .rxbd_rwptr_clr_reg = R_AX_RXBD_RWPTR_CLR_V1, .txbd_rwptr_clr2_reg = R_AX_TXBD_RWPTR_CLR2_V1, + .dma_io_stop = {R_AX_HAXI_INIT_CFG1, B_AX_STOP_AXI_MST}, .dma_stop1 = {R_AX_HAXI_DMA_STOP1, B_AX_TX_STOP1_MASK}, .dma_stop2 = {R_AX_HAXI_DMA_STOP2, B_AX_TX_STOP2_ALL}, .dma_busy1 = {R_AX_HAXI_DMA_BUSY1, DMA_BUSY1_CHECK}, @@ -50,6 +53,7 @@ static const struct rtw89_pci_info rtw8852c_pci_info = { .rpwm_addr = R_AX_PCIE_HRPWM_V1, .cpwm_addr = R_AX_PCIE_CRPWM, + .mit_addr = R_AX_INT_MIT_RX_V1, .tx_dma_ch_mask = 0, .bd_idx_addr_low_power = &rtw8852c_bd_idx_addr_low_power, .dma_addr_set = &rtw89_pci_ch_dma_addr_set_v1, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c new file mode 100644 index 0000000000000..d190f095a5a8f --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -0,0 +1,363 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2023 Realtek Corporation + */ + +#include "debug.h" +#include "efuse.h" +#include "fw.h" +#include "mac.h" +#include "phy.h" +#include "reg.h" +#include "rtw8922a.h" + +#define RTW8922A_FW_FORMAT_MAX 0 +#define RTW8922A_FW_BASENAME "rtw89/rtw8922a_fw" +#define RTW8922A_MODULE_FIRMWARE \ + RTW8922A_FW_BASENAME ".bin" + +static const struct rtw89_efuse_block_cfg rtw8922a_efuse_blocks[] = { + [RTW89_EFUSE_BLOCK_SYS] = {.offset = 0x00000, .size = 0x310}, + [RTW89_EFUSE_BLOCK_RF] = {.offset = 0x10000, .size = 0x240}, + [RTW89_EFUSE_BLOCK_HCI_DIG_PCIE_SDIO] = {.offset = 0x20000, .size = 0x4800}, + [RTW89_EFUSE_BLOCK_HCI_DIG_USB] = {.offset = 0x30000, .size = 0x890}, + [RTW89_EFUSE_BLOCK_HCI_PHY_PCIE] = {.offset = 0x40000, .size = 0x200}, + [RTW89_EFUSE_BLOCK_HCI_PHY_USB3] = {.offset = 0x50000, .size = 0x80}, + [RTW89_EFUSE_BLOCK_HCI_PHY_USB2] = {.offset = 0x60000, .size = 0x0}, + [RTW89_EFUSE_BLOCK_ADIE] = {.offset = 0x70000, .size = 0x10}, +}; + +static void rtw8922a_efuse_parsing_tssi(struct rtw89_dev *rtwdev, + struct rtw8922a_efuse *map) +{ + struct rtw8922a_tssi_offset *ofst[] = {&map->path_a_tssi, &map->path_b_tssi}; + u8 *bw40_1s_tssi_6g_ofst[] = {map->bw40_1s_tssi_6g_a, map->bw40_1s_tssi_6g_b}; + struct rtw89_tssi_info *tssi = &rtwdev->tssi; + u8 i, j; + + tssi->thermal[RF_PATH_A] = map->path_a_therm; + tssi->thermal[RF_PATH_B] = map->path_b_therm; + + for (i = 0; i < RF_PATH_NUM_8922A; i++) { + memcpy(tssi->tssi_cck[i], ofst[i]->cck_tssi, + sizeof(ofst[i]->cck_tssi)); + + for (j = 0; j < TSSI_CCK_CH_GROUP_NUM; j++) + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][EFUSE] path=%d cck[%d]=0x%x\n", + i, j, tssi->tssi_cck[i][j]); + + memcpy(tssi->tssi_mcs[i], ofst[i]->bw40_tssi, + sizeof(ofst[i]->bw40_tssi)); + memcpy(tssi->tssi_mcs[i] + TSSI_MCS_2G_CH_GROUP_NUM, + ofst[i]->bw40_1s_tssi_5g, sizeof(ofst[i]->bw40_1s_tssi_5g)); + memcpy(tssi->tssi_6g_mcs[i], bw40_1s_tssi_6g_ofst[i], + sizeof(tssi->tssi_6g_mcs[i])); + + for (j = 0; j < TSSI_MCS_CH_GROUP_NUM; j++) + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][EFUSE] path=%d mcs[%d]=0x%x\n", + i, j, tssi->tssi_mcs[i][j]); + } +} + +static void rtw8922a_efuse_parsing_gain_offset(struct rtw89_dev *rtwdev, + struct rtw8922a_efuse *map) +{ + struct rtw89_phy_efuse_gain *gain = &rtwdev->efuse_gain; + bool all_0xff = true, all_0x00 = true; + int i, j; + u8 t; + + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_2G_CCK] = map->rx_gain_a._2g_cck; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_2G_CCK] = map->rx_gain_b._2g_cck; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_2G_OFDM] = map->rx_gain_a._2g_ofdm; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_2G_OFDM] = map->rx_gain_b._2g_ofdm; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_5G_LOW] = map->rx_gain_a._5g_low; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_5G_LOW] = map->rx_gain_b._5g_low; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_5G_MID] = map->rx_gain_a._5g_mid; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_5G_MID] = map->rx_gain_b._5g_mid; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_5G_HIGH] = map->rx_gain_a._5g_high; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_5G_HIGH] = map->rx_gain_b._5g_high; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_L0] = map->rx_gain_6g_a._6g_l0; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_L0] = map->rx_gain_6g_b._6g_l0; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_L1] = map->rx_gain_6g_a._6g_l1; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_L1] = map->rx_gain_6g_b._6g_l1; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_M0] = map->rx_gain_6g_a._6g_m0; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_M0] = map->rx_gain_6g_b._6g_m0; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_M1] = map->rx_gain_6g_a._6g_m1; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_M1] = map->rx_gain_6g_b._6g_m1; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_H0] = map->rx_gain_6g_a._6g_h0; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_H0] = map->rx_gain_6g_b._6g_h0; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_H1] = map->rx_gain_6g_a._6g_h1; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_H1] = map->rx_gain_6g_b._6g_h1; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_UH0] = map->rx_gain_6g_a._6g_uh0; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_UH0] = map->rx_gain_6g_b._6g_uh0; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_UH1] = map->rx_gain_6g_a._6g_uh1; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_UH1] = map->rx_gain_6g_b._6g_uh1; + + for (i = RF_PATH_A; i <= RF_PATH_B; i++) + for (j = 0; j < RTW89_GAIN_OFFSET_NR; j++) { + t = gain->offset[i][j]; + if (t != 0xff) + all_0xff = false; + if (t != 0x0) + all_0x00 = false; + + /* transform: sign-bit + U(7,2) to S(8,2) */ + if (t & 0x80) + gain->offset[i][j] = (t ^ 0x7f) + 1; + } + + gain->offset_valid = !all_0xff && !all_0x00; +} + +static void rtw8922a_read_efuse_mac_addr(struct rtw89_dev *rtwdev, u32 addr) +{ + struct rtw89_efuse *efuse = &rtwdev->efuse; + u16 val; + int i; + + for (i = 0; i < ETH_ALEN; i += 2, addr += 2) { + val = rtw89_read16(rtwdev, addr); + efuse->addr[i] = val & 0xff; + efuse->addr[i + 1] = val >> 8; + } +} + +static int rtw8922a_read_efuse_pci_sdio(struct rtw89_dev *rtwdev, u8 *log_map) +{ + struct rtw89_efuse *efuse = &rtwdev->efuse; + + if (rtwdev->hci.type == RTW89_HCI_TYPE_PCIE) + rtw8922a_read_efuse_mac_addr(rtwdev, 0x3104); + else + ether_addr_copy(efuse->addr, log_map + 0x001A); + + return 0; +} + +static int rtw8922a_read_efuse_usb(struct rtw89_dev *rtwdev, u8 *log_map) +{ + rtw8922a_read_efuse_mac_addr(rtwdev, 0x4078); + + return 0; +} + +static int rtw8922a_read_efuse_rf(struct rtw89_dev *rtwdev, u8 *log_map) +{ + struct rtw8922a_efuse *map = (struct rtw8922a_efuse *)log_map; + struct rtw89_efuse *efuse = &rtwdev->efuse; + + efuse->rfe_type = map->rfe_type; + efuse->xtal_cap = map->xtal_k; + efuse->country_code[0] = map->country_code[0]; + efuse->country_code[1] = map->country_code[1]; + rtw8922a_efuse_parsing_tssi(rtwdev, map); + rtw8922a_efuse_parsing_gain_offset(rtwdev, map); + + rtw89_info(rtwdev, "chip rfe_type is %d\n", efuse->rfe_type); + + return 0; +} + +static int rtw8922a_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, + enum rtw89_efuse_block block) +{ + switch (block) { + case RTW89_EFUSE_BLOCK_HCI_DIG_PCIE_SDIO: + return rtw8922a_read_efuse_pci_sdio(rtwdev, log_map); + case RTW89_EFUSE_BLOCK_HCI_DIG_USB: + return rtw8922a_read_efuse_usb(rtwdev, log_map); + case RTW89_EFUSE_BLOCK_RF: + return rtw8922a_read_efuse_rf(rtwdev, log_map); + default: + return 0; + } +} + +#define THM_TRIM_POSITIVE_MASK BIT(6) +#define THM_TRIM_MAGNITUDE_MASK GENMASK(5, 0) + +static void rtw8922a_phycap_parsing_thermal_trim(struct rtw89_dev *rtwdev, + u8 *phycap_map) +{ + static const u32 thm_trim_addr[RF_PATH_NUM_8922A] = {0x1706, 0x1733}; + struct rtw89_power_trim_info *info = &rtwdev->pwr_trim; + u32 addr = rtwdev->chip->phycap_addr; + bool pg = true; + u8 pg_th; + s8 val; + u8 i; + + for (i = 0; i < RF_PATH_NUM_8922A; i++) { + pg_th = phycap_map[thm_trim_addr[i] - addr]; + if (pg_th == 0xff) { + info->thermal_trim[i] = 0; + pg = false; + break; + } + + val = u8_get_bits(pg_th, THM_TRIM_MAGNITUDE_MASK); + + if (!(pg_th & THM_TRIM_POSITIVE_MASK)) + val *= -1; + + info->thermal_trim[i] = val; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[THERMAL][TRIM] path=%d thermal_trim=0x%x (%d)\n", + i, pg_th, val); + } + + info->pg_thermal_trim = pg; +} + +static void rtw8922a_phycap_parsing_pa_bias_trim(struct rtw89_dev *rtwdev, + u8 *phycap_map) +{ + static const u32 pabias_trim_addr[RF_PATH_NUM_8922A] = {0x1707, 0x1734}; + static const u32 check_pa_pad_trim_addr = 0x1700; + struct rtw89_power_trim_info *info = &rtwdev->pwr_trim; + u32 addr = rtwdev->chip->phycap_addr; + u8 val; + u8 i; + + val = phycap_map[check_pa_pad_trim_addr - addr]; + if (val != 0xff) + info->pg_pa_bias_trim = true; + + for (i = 0; i < RF_PATH_NUM_8922A; i++) { + info->pa_bias_trim[i] = phycap_map[pabias_trim_addr[i] - addr]; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[PA_BIAS][TRIM] path=%d pa_bias_trim=0x%x\n", + i, info->pa_bias_trim[i]); + } +} + +static void rtw8922a_phycap_parsing_pad_bias_trim(struct rtw89_dev *rtwdev, + u8 *phycap_map) +{ + static const u32 pad_bias_trim_addr[RF_PATH_NUM_8922A] = {0x1708, 0x1735}; + struct rtw89_power_trim_info *info = &rtwdev->pwr_trim; + u32 addr = rtwdev->chip->phycap_addr; + u8 i; + + for (i = 0; i < RF_PATH_NUM_8922A; i++) { + info->pad_bias_trim[i] = phycap_map[pad_bias_trim_addr[i] - addr]; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[PAD_BIAS][TRIM] path=%d pad_bias_trim=0x%x\n", + i, info->pad_bias_trim[i]); + } +} + +static int rtw8922a_read_phycap(struct rtw89_dev *rtwdev, u8 *phycap_map) +{ + rtw8922a_phycap_parsing_thermal_trim(rtwdev, phycap_map); + rtw8922a_phycap_parsing_pa_bias_trim(rtwdev, phycap_map); + rtw8922a_phycap_parsing_pad_bias_trim(rtwdev, phycap_map); + + return 0; +} + +#ifdef CONFIG_PM +static const struct wiphy_wowlan_support rtw_wowlan_stub_8922a = { + .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, + .n_patterns = RTW89_MAX_PATTERN_NUM, + .pattern_max_len = RTW89_MAX_PATTERN_SIZE, + .pattern_min_len = 1, +}; +#endif + +static const struct rtw89_chip_ops rtw8922a_chip_ops = { + .read_efuse = rtw8922a_read_efuse, + .read_phycap = rtw8922a_read_phycap, +}; + +const struct rtw89_chip_info rtw8922a_chip_info = { + .chip_id = RTL8922A, + .chip_gen = RTW89_CHIP_BE, + .ops = &rtw8922a_chip_ops, + .mac_def = &rtw89_mac_gen_be, + .phy_def = &rtw89_phy_gen_be, + .fw_basename = RTW8922A_FW_BASENAME, + .fw_format_max = RTW8922A_FW_FORMAT_MAX, + .try_ce_fw = false, + .bbmcu_nr = 1, + .needed_fw_elms = RTW89_BE_GEN_DEF_NEEDED_FW_ELEMENTS, + .fifo_size = 589824, + .small_fifo_size = false, + .dle_scc_rsvd_size = 0, + .max_amsdu_limit = 8000, + .dis_2g_40m_ul_ofdma = false, + .rsvd_ple_ofst = 0x8f800, + .rf_base_addr = {0xe000, 0xf000}, + .pwr_on_seq = NULL, + .pwr_off_seq = NULL, + .bb_table = NULL, + .bb_gain_table = NULL, + .rf_table = {}, + .nctl_table = NULL, + .nctl_post_table = NULL, + .dflt_parms = NULL, /* load parm from fw */ + .rfe_parms_conf = NULL, /* load parm from fw */ + .txpwr_factor_rf = 2, + .txpwr_factor_mac = 1, + .dig_table = NULL, + .tssi_dbw_table = NULL, + .support_chanctx_num = 1, + .support_bands = BIT(NL80211_BAND_2GHZ) | + BIT(NL80211_BAND_5GHZ) | + BIT(NL80211_BAND_6GHZ), + .support_unii4 = true, + .ul_tb_waveform_ctrl = false, + .ul_tb_pwr_diff = false, + .hw_sec_hdr = true, + .rf_path_num = 2, + .tx_nss = 2, + .rx_nss = 2, + .acam_num = 128, + .bcam_num = 20, + .scam_num = 32, + .bacam_num = 8, + .bacam_dynamic_num = 8, + .bacam_ver = RTW89_BACAM_V1, + .ppdu_max_usr = 16, + .sec_ctrl_efuse_size = 4, + .physical_efuse_size = 0x1300, + .logical_efuse_size = 0x70000, + .limit_efuse_size = 0x40000, + .dav_phy_efuse_size = 0, + .dav_log_efuse_size = 0, + .efuse_blocks = rtw8922a_efuse_blocks, + .phycap_addr = 0x1700, + .phycap_size = 0x38, + + .ps_mode_supported = BIT(RTW89_PS_MODE_RFOFF) | + BIT(RTW89_PS_MODE_CLK_GATED) | + BIT(RTW89_PS_MODE_PWR_GATED), + .low_power_hci_modes = 0, + .hci_func_en_addr = R_BE_HCI_FUNC_EN, + .h2c_desc_size = sizeof(struct rtw89_rxdesc_short_v2), + .txwd_body_size = sizeof(struct rtw89_txwd_body_v2), + .txwd_info_size = sizeof(struct rtw89_txwd_info_v2), + .cfo_src_fd = true, + .cfo_hw_comp = true, + .dcfo_comp = NULL, + .dcfo_comp_sft = 0, + .imr_info = NULL, + .bss_clr_vld = {R_BSS_CLR_VLD_V2, B_BSS_CLR_VLD0_V2}, + .bss_clr_map_reg = R_BSS_CLR_MAP_V2, + .dma_ch_mask = 0, +#ifdef CONFIG_PM + .wowlan_stub = &rtw_wowlan_stub_8922a, +#endif + .xtal_info = NULL, +}; +EXPORT_SYMBOL(rtw8922a_chip_info); + +MODULE_FIRMWARE(RTW8922A_MODULE_FIRMWARE); +MODULE_AUTHOR("Realtek Corporation"); +MODULE_DESCRIPTION("Realtek 802.11be wireless 8922A driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.h b/drivers/net/wireless/realtek/rtw89/rtw8922a.h new file mode 100644 index 0000000000000..597317ab6af76 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.h @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2023 Realtek Corporation + */ + +#ifndef __RTW89_8922A_H__ +#define __RTW89_8922A_H__ + +#include "core.h" + +#define RF_PATH_NUM_8922A 2 +#define BB_PATH_NUM_8922A 2 + +struct rtw8922a_tssi_offset { + u8 cck_tssi[TSSI_CCK_CH_GROUP_NUM]; + u8 bw40_tssi[TSSI_MCS_2G_CH_GROUP_NUM]; + u8 rsvd[7]; + u8 bw40_1s_tssi_5g[TSSI_MCS_5G_CH_GROUP_NUM]; + u8 bw_diff_5g[10]; +} __packed; + +struct rtw8922a_rx_gain { + u8 _2g_ofdm; + u8 _2g_cck; + u8 _5g_low; + u8 _5g_mid; + u8 _5g_high; +} __packed; + +struct rtw8922a_rx_gain_6g { + u8 _6g_l0; + u8 _6g_l1; + u8 _6g_m0; + u8 _6g_m1; + u8 _6g_h0; + u8 _6g_h1; + u8 _6g_uh0; + u8 _6g_uh1; +} __packed; + +struct rtw8922a_efuse { + u8 country_code[2]; + u8 rsvd[0xe]; + struct rtw8922a_tssi_offset path_a_tssi; + struct rtw8922a_tssi_offset path_b_tssi; + u8 rsvd1[0x54]; + u8 channel_plan; + u8 xtal_k; + u8 rsvd2[0x7]; + u8 board_info; + u8 rsvd3[0x8]; + u8 rfe_type; + u8 rsvd4[0x5]; + u8 path_a_therm; + u8 path_b_therm; + u8 rsvd5[0x2]; + struct rtw8922a_rx_gain rx_gain_a; + struct rtw8922a_rx_gain rx_gain_b; + u8 rsvd6[0x22]; + u8 bw40_1s_tssi_6g_a[TSSI_MCS_6G_CH_GROUP_NUM]; + u8 rsvd7[0xa]; + u8 bw40_1s_tssi_6g_b[TSSI_MCS_6G_CH_GROUP_NUM]; + u8 rsvd8[0xa]; + u8 bw40_1s_tssi_6g_c[TSSI_MCS_6G_CH_GROUP_NUM]; + u8 rsvd9[0xa]; + u8 bw40_1s_tssi_6g_d[TSSI_MCS_6G_CH_GROUP_NUM]; + u8 rsvd10[0xa]; + struct rtw8922a_rx_gain_6g rx_gain_6g_a; + struct rtw8922a_rx_gain_6g rx_gain_6g_b; +} __packed; + +extern const struct rtw89_chip_info rtw8922a_chip_info; + +#endif diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c new file mode 100644 index 0000000000000..7b3d98d2c402c --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2023 Realtek Corporation + */ + +#include +#include + +#include "pci.h" +#include "reg.h" +#include "rtw8922a.h" + +static const struct rtw89_pci_info rtw8922a_pci_info = { + .gen_def = &rtw89_pci_gen_be, + .txbd_trunc_mode = MAC_AX_BD_TRUNC, + .rxbd_trunc_mode = MAC_AX_BD_TRUNC, + .rxbd_mode = MAC_AX_RXBD_PKT, + .tag_mode = MAC_AX_TAG_MULTI, + .tx_burst = MAC_AX_TX_BURST_V1_256B, + .rx_burst = MAC_AX_RX_BURST_V1_128B, + .wd_dma_idle_intvl = MAC_AX_WD_DMA_INTVL_256NS, + .wd_dma_act_intvl = MAC_AX_WD_DMA_INTVL_256NS, + .multi_tag_num = MAC_AX_TAG_NUM_8, + .lbc_en = MAC_AX_PCIE_ENABLE, + .lbc_tmr = MAC_AX_LBC_TMR_2MS, + .autok_en = MAC_AX_PCIE_DISABLE, + .io_rcy_en = MAC_AX_PCIE_ENABLE, + .io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_DEF, + .rx_ring_eq_is_full = true, + + .init_cfg_reg = R_BE_HAXI_INIT_CFG1, + .txhci_en_bit = B_BE_TXDMA_EN, + .rxhci_en_bit = B_BE_RXDMA_EN, + .rxbd_mode_bit = B_BE_RXQ_RXBD_MODE_MASK, + .exp_ctrl_reg = R_BE_HAXI_EXP_CTRL_V1, + .max_tag_num_mask = B_BE_MAX_TAG_NUM_MASK, + .rxbd_rwptr_clr_reg = R_BE_RXBD_RWPTR_CLR1_V1, + .txbd_rwptr_clr2_reg = R_BE_TXBD_RWPTR_CLR1, + .dma_io_stop = {R_BE_HAXI_INIT_CFG1, B_BE_STOP_AXI_MST}, + .dma_stop1 = {R_BE_HAXI_DMA_STOP1, B_BE_TX_STOP1_MASK}, + .dma_stop2 = {0}, + .dma_busy1 = {R_BE_HAXI_DMA_BUSY1, DMA_BUSY1_CHECK_BE}, + .dma_busy2_reg = 0, + .dma_busy3_reg = R_BE_HAXI_DMA_BUSY1, + + .rpwm_addr = R_BE_PCIE_HRPWM, + .cpwm_addr = R_BE_PCIE_CRPWM, + .mit_addr = R_BE_PCIE_MIT_CH_EN, + .tx_dma_ch_mask = 0, + .bd_idx_addr_low_power = NULL, + .dma_addr_set = &rtw89_pci_ch_dma_addr_set_be, + .bd_ram_table = NULL, + + .ltr_set = rtw89_pci_ltr_set_v2, + .fill_txaddr_info = rtw89_pci_fill_txaddr_info_v1, + .config_intr_mask = rtw89_pci_config_intr_mask_v2, + .enable_intr = rtw89_pci_enable_intr_v2, + .disable_intr = rtw89_pci_disable_intr_v2, + .recognize_intrs = rtw89_pci_recognize_intrs_v2, +}; + +static const struct rtw89_driver_info rtw89_8922ae_info = { + .chip = &rtw8922a_chip_info, + .bus = { + .pci = &rtw8922a_pci_info, + }, +}; + +static const struct pci_device_id rtw89_8922ae_id_table[] = { + { + PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8922), + .driver_data = (kernel_ulong_t)&rtw89_8922ae_info, + }, + {}, +}; +MODULE_DEVICE_TABLE(pci, rtw89_8922ae_id_table); + +static struct pci_driver rtw89_8922ae_driver = { + .name = "rtw89_8922ae", + .id_table = rtw89_8922ae_id_table, + .probe = rtw89_pci_probe, + .remove = rtw89_pci_remove, + .driver.pm = &rtw89_pm_ops, +}; +module_pci_driver(rtw89_8922ae_driver); + +MODULE_AUTHOR("Realtek Corporation"); +MODULE_DESCRIPTION("Realtek 802.11be wireless 8922AE driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/realtek/rtw89/sar.c b/drivers/net/wireless/realtek/rtw89/sar.c index aed05b026c6c3..1b2a400406ae1 100644 --- a/drivers/net/wireless/realtek/rtw89/sar.c +++ b/drivers/net/wireless/realtek/rtw89/sar.c @@ -404,16 +404,18 @@ static void rtw89_tas_state_update(struct rtw89_dev *rtwdev) void rtw89_tas_init(struct rtw89_dev *rtwdev) { struct rtw89_tas_info *tas = &rtwdev->tas; + struct rtw89_acpi_dsm_result res = {}; int ret; u8 val; - ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_TAS_EN, &val); + ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_TAS_EN, &res); if (ret) { rtw89_debug(rtwdev, RTW89_DBG_SAR, "acpi: cannot get TAS: %d\n", ret); return; } + val = res.u.value; switch (val) { case 0: tas->enable = false; diff --git a/drivers/net/wireless/realtek/rtw89/ser.c b/drivers/net/wireless/realtek/rtw89/ser.c index c1644353053f0..1e4a79a3b814a 100644 --- a/drivers/net/wireless/realtek/rtw89/ser.c +++ b/drivers/net/wireless/realtek/rtw89/ser.c @@ -361,6 +361,9 @@ static int hal_enable_dma(struct rtw89_ser *ser) ret = rtwdev->hci.ops->mac_lv1_rcvy(rtwdev, RTW89_LV1_RCVY_STEP_2); if (!ret) clear_bit(RTW89_SER_HAL_STOP_DMA, ser->flags); + else + rtw89_debug(rtwdev, RTW89_DBG_SER, + "lv1 rcvy fail to start dma: %d\n", ret); return ret; } @@ -376,6 +379,9 @@ static int hal_stop_dma(struct rtw89_ser *ser) ret = rtwdev->hci.ops->mac_lv1_rcvy(rtwdev, RTW89_LV1_RCVY_STEP_1); if (!ret) set_bit(RTW89_SER_HAL_STOP_DMA, ser->flags); + else + rtw89_debug(rtwdev, RTW89_DBG_SER, + "lv1 rcvy fail to stop dma: %d\n", ret); return ret; } diff --git a/drivers/net/wireless/realtek/rtw89/txrx.h b/drivers/net/wireless/realtek/rtw89/txrx.h index 7142cce167de4..c467a80ffa88d 100644 --- a/drivers/net/wireless/realtek/rtw89/txrx.h +++ b/drivers/net/wireless/realtek/rtw89/txrx.h @@ -416,8 +416,11 @@ struct rtw89_rxinfo { } __packed; #define RTW89_RXINFO_W0_USR_NUM GENMASK(3, 0) +#define RTW89_RXINFO_W0_USR_NUM_V1 GENMASK(4, 0) #define RTW89_RXINFO_W0_FW_DEFINE GENMASK(15, 8) +#define RTW89_RXINFO_W0_PLCP_LEN_V1 GENMASK(23, 16) #define RTW89_RXINFO_W0_LSIG_LEN GENMASK(27, 16) +#define RTW89_RXINFO_W0_INVALID_V1 BIT(27) #define RTW89_RXINFO_W0_IS_TO_SELF BIT(28) #define RTW89_RXINFO_W0_RX_CNT_VLD BIT(29) #define RTW89_RXINFO_W0_LONG_RXD GENMASK(31, 30) @@ -430,6 +433,7 @@ struct rtw89_phy_sts_hdr { } __packed; #define RTW89_PHY_STS_HDR_W0_IE_MAP GENMASK(4, 0) +#define RTW89_PHY_STS_HDR_W0_VALID BIT(7) #define RTW89_PHY_STS_HDR_W0_LEN GENMASK(15, 8) #define RTW89_PHY_STS_HDR_W0_RSSI_AVG GENMASK(31, 24) #define RTW89_PHY_STS_HDR_W1_RSSI_A GENMASK(7, 0) diff --git a/drivers/net/wireless/zydas/Kconfig b/drivers/net/wireless/zydas/Kconfig index 08574433df66f..839e1217e855c 100644 --- a/drivers/net/wireless/zydas/Kconfig +++ b/drivers/net/wireless/zydas/Kconfig @@ -12,25 +12,6 @@ config WLAN_VENDOR_ZYDAS if WLAN_VENDOR_ZYDAS -config USB_ZD1201 - tristate "USB ZD1201 based Wireless device support" - depends on CFG80211 && USB - select WIRELESS_EXT - select WEXT_PRIV - select FW_LOADER - help - Say Y if you want to use wireless LAN adapters based on the ZyDAS - ZD1201 chip. - - This driver makes the adapter appear as a normal Ethernet interface, - typically on wlan0. - - The zd1201 device requires external firmware to be loaded. - This can be found at http://linux-lc100020.sourceforge.net/ - - To compile this driver as a module, choose M here: the - module will be called zd1201. - source "drivers/net/wireless/zydas/zd1211rw/Kconfig" endif # WLAN_VENDOR_ZYDAS diff --git a/drivers/net/wireless/zydas/Makefile b/drivers/net/wireless/zydas/Makefile index c70003d30a8fb..3e0a51db98742 100644 --- a/drivers/net/wireless/zydas/Makefile +++ b/drivers/net/wireless/zydas/Makefile @@ -1,4 +1,2 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_ZD1211RW) += zd1211rw/ - -obj-$(CONFIG_USB_ZD1201) += zd1201.o diff --git a/drivers/net/wireless/zydas/zd1201.c b/drivers/net/wireless/zydas/zd1201.c deleted file mode 100644 index 2814df1ecc78f..0000000000000 --- a/drivers/net/wireless/zydas/zd1201.c +++ /dev/null @@ -1,1909 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Driver for ZyDAS zd1201 based USB wireless devices. - * - * Copyright (c) 2004, 2005 Jeroen Vreeken (pe1rxq@amsat.org) - * - * Parts of this driver have been derived from a wlan-ng version - * modified by ZyDAS. They also made documentation available, thanks! - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "zd1201.h" - -static const struct usb_device_id zd1201_table[] = { - {USB_DEVICE(0x0586, 0x3400)}, /* Peabird USB Wireless Adapter */ - {USB_DEVICE(0x0ace, 0x1201)}, /* ZyDAS ZD1201 USB Wireless Adapter */ - {USB_DEVICE(0x050d, 0x6051)}, /* Belkin F5D6051 usb adapter */ - {USB_DEVICE(0x0db0, 0x6823)}, /* MSI UB11B usb adapter */ - {USB_DEVICE(0x1044, 0x8004)}, /* Gigabyte GN-WLBZ101 */ - {USB_DEVICE(0x1044, 0x8005)}, /* GIGABYTE GN-WLBZ201 usb adapter */ - {} -}; - -static int ap; /* Are we an AP or a normal station? */ - -#define ZD1201_VERSION "0.15" - -MODULE_AUTHOR("Jeroen Vreeken "); -MODULE_DESCRIPTION("Driver for ZyDAS ZD1201 based USB Wireless adapters"); -MODULE_VERSION(ZD1201_VERSION); -MODULE_LICENSE("GPL"); -module_param(ap, int, 0); -MODULE_PARM_DESC(ap, "If non-zero Access Point firmware will be loaded"); -MODULE_DEVICE_TABLE(usb, zd1201_table); - - -static int zd1201_fw_upload(struct usb_device *dev, int apfw) -{ - const struct firmware *fw_entry; - const char *data; - unsigned long len; - int err; - unsigned char ret; - char *buf; - char *fwfile; - - if (apfw) - fwfile = "zd1201-ap.fw"; - else - fwfile = "zd1201.fw"; - - err = request_firmware(&fw_entry, fwfile, &dev->dev); - if (err) { - dev_err(&dev->dev, "Failed to load %s firmware file!\n", fwfile); - dev_err(&dev->dev, "Make sure the hotplug firmware loader is installed.\n"); - dev_err(&dev->dev, "Goto http://linux-lc100020.sourceforge.net for more info.\n"); - return err; - } - - data = fw_entry->data; - len = fw_entry->size; - - buf = kmalloc(1024, GFP_ATOMIC); - if (!buf) { - err = -ENOMEM; - goto exit; - } - - while (len > 0) { - int translen = (len > 1024) ? 1024 : len; - memcpy(buf, data, translen); - - err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0, - USB_DIR_OUT | 0x40, 0, 0, buf, translen, - ZD1201_FW_TIMEOUT); - if (err < 0) - goto exit; - - len -= translen; - data += translen; - } - - err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0x2, - USB_DIR_OUT | 0x40, 0, 0, NULL, 0, ZD1201_FW_TIMEOUT); - if (err < 0) - goto exit; - - err = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 0x4, - USB_DIR_IN | 0x40, 0, 0, buf, sizeof(ret), ZD1201_FW_TIMEOUT); - if (err < 0) - goto exit; - - memcpy(&ret, buf, sizeof(ret)); - - if (ret & 0x80) { - err = -EIO; - goto exit; - } - - err = 0; -exit: - kfree(buf); - release_firmware(fw_entry); - return err; -} - -MODULE_FIRMWARE("zd1201-ap.fw"); -MODULE_FIRMWARE("zd1201.fw"); - -static void zd1201_usbfree(struct urb *urb) -{ - struct zd1201 *zd = urb->context; - - switch(urb->status) { - case -EILSEQ: - case -ENODEV: - case -ETIME: - case -ENOENT: - case -EPIPE: - case -EOVERFLOW: - case -ESHUTDOWN: - dev_warn(&zd->usb->dev, "%s: urb failed: %d\n", - zd->dev->name, urb->status); - } - - kfree(urb->transfer_buffer); - usb_free_urb(urb); -} - -/* cmdreq message: - u32 type - u16 cmd - u16 parm0 - u16 parm1 - u16 parm2 - u8 pad[4] - - total: 4 + 2 + 2 + 2 + 2 + 4 = 16 -*/ -static int zd1201_docmd(struct zd1201 *zd, int cmd, int parm0, - int parm1, int parm2) -{ - unsigned char *command; - int ret; - struct urb *urb; - - command = kmalloc(16, GFP_ATOMIC); - if (!command) - return -ENOMEM; - - *((__le32*)command) = cpu_to_le32(ZD1201_USB_CMDREQ); - *((__le16*)&command[4]) = cpu_to_le16(cmd); - *((__le16*)&command[6]) = cpu_to_le16(parm0); - *((__le16*)&command[8]) = cpu_to_le16(parm1); - *((__le16*)&command[10])= cpu_to_le16(parm2); - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) { - kfree(command); - return -ENOMEM; - } - usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, zd->endp_out2), - command, 16, zd1201_usbfree, zd); - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret) { - kfree(command); - usb_free_urb(urb); - } - - return ret; -} - -/* Callback after sending out a packet */ -static void zd1201_usbtx(struct urb *urb) -{ - struct zd1201 *zd = urb->context; - netif_wake_queue(zd->dev); -} - -/* Incoming data */ -static void zd1201_usbrx(struct urb *urb) -{ - struct zd1201 *zd = urb->context; - int free = 0; - unsigned char *data = urb->transfer_buffer; - struct sk_buff *skb; - unsigned char type; - - if (!zd) - return; - - switch(urb->status) { - case -EILSEQ: - case -ENODEV: - case -ETIME: - case -ENOENT: - case -EPIPE: - case -EOVERFLOW: - case -ESHUTDOWN: - dev_warn(&zd->usb->dev, "%s: rx urb failed: %d\n", - zd->dev->name, urb->status); - free = 1; - goto exit; - } - - if (urb->status != 0 || urb->actual_length == 0) - goto resubmit; - - type = data[0]; - if (type == ZD1201_PACKET_EVENTSTAT || type == ZD1201_PACKET_RESOURCE) { - memcpy(zd->rxdata, data, urb->actual_length); - zd->rxlen = urb->actual_length; - zd->rxdatas = 1; - wake_up(&zd->rxdataq); - } - /* Info frame */ - if (type == ZD1201_PACKET_INQUIRE) { - int i = 0; - unsigned short infotype, copylen; - infotype = le16_to_cpu(*(__le16*)&data[6]); - - if (infotype == ZD1201_INF_LINKSTATUS) { - short linkstatus; - - linkstatus = le16_to_cpu(*(__le16*)&data[8]); - switch(linkstatus) { - case 1: - netif_carrier_on(zd->dev); - break; - case 2: - netif_carrier_off(zd->dev); - break; - case 3: - netif_carrier_off(zd->dev); - break; - case 4: - netif_carrier_on(zd->dev); - break; - default: - netif_carrier_off(zd->dev); - } - goto resubmit; - } - if (infotype == ZD1201_INF_ASSOCSTATUS) { - short status = le16_to_cpu(*(__le16*)(data+8)); - int event; - union iwreq_data wrqu; - - switch (status) { - case ZD1201_ASSOCSTATUS_STAASSOC: - case ZD1201_ASSOCSTATUS_REASSOC: - event = IWEVREGISTERED; - break; - case ZD1201_ASSOCSTATUS_DISASSOC: - case ZD1201_ASSOCSTATUS_ASSOCFAIL: - case ZD1201_ASSOCSTATUS_AUTHFAIL: - default: - event = IWEVEXPIRED; - } - memcpy(wrqu.addr.sa_data, data+10, ETH_ALEN); - wrqu.addr.sa_family = ARPHRD_ETHER; - - /* Send event to user space */ - wireless_send_event(zd->dev, event, &wrqu, NULL); - - goto resubmit; - } - if (infotype == ZD1201_INF_AUTHREQ) { - union iwreq_data wrqu; - - memcpy(wrqu.addr.sa_data, data+8, ETH_ALEN); - wrqu.addr.sa_family = ARPHRD_ETHER; - /* There isn't a event that trully fits this request. - We assume that userspace will be smart enough to - see a new station being expired and sends back a - authstation ioctl to authorize it. */ - wireless_send_event(zd->dev, IWEVEXPIRED, &wrqu, NULL); - goto resubmit; - } - /* Other infotypes are handled outside this handler */ - zd->rxlen = 0; - while (i < urb->actual_length) { - copylen = le16_to_cpu(*(__le16*)&data[i+2]); - /* Sanity check, sometimes we get junk */ - if (copylen+zd->rxlen > sizeof(zd->rxdata)) - break; - memcpy(zd->rxdata+zd->rxlen, data+i+4, copylen); - zd->rxlen += copylen; - i += 64; - } - if (i >= urb->actual_length) { - zd->rxdatas = 1; - wake_up(&zd->rxdataq); - } - goto resubmit; - } - /* Actual data */ - if (data[urb->actual_length-1] == ZD1201_PACKET_RXDATA) { - int datalen = urb->actual_length-1; - unsigned short len, fc, seq; - - len = ntohs(*(__be16 *)&data[datalen-2]); - if (len>datalen) - len=datalen; - fc = le16_to_cpu(*(__le16 *)&data[datalen-16]); - seq = le16_to_cpu(*(__le16 *)&data[datalen-24]); - - if (zd->monitor) { - if (datalen < 24) - goto resubmit; - if (!(skb = dev_alloc_skb(datalen+24))) - goto resubmit; - - skb_put_data(skb, &data[datalen - 16], 2); - skb_put_data(skb, &data[datalen - 2], 2); - skb_put_data(skb, &data[datalen - 14], 6); - skb_put_data(skb, &data[datalen - 22], 6); - skb_put_data(skb, &data[datalen - 8], 6); - skb_put_data(skb, &data[datalen - 24], 2); - skb_put_data(skb, data, len); - skb->protocol = eth_type_trans(skb, zd->dev); - zd->dev->stats.rx_packets++; - zd->dev->stats.rx_bytes += skb->len; - netif_rx(skb); - goto resubmit; - } - - if ((seq & IEEE80211_SCTL_FRAG) || - (fc & IEEE80211_FCTL_MOREFRAGS)) { - struct zd1201_frag *frag = NULL; - char *ptr; - - if (datalen<14) - goto resubmit; - if ((seq & IEEE80211_SCTL_FRAG) == 0) { - frag = kmalloc(sizeof(*frag), GFP_ATOMIC); - if (!frag) - goto resubmit; - skb = dev_alloc_skb(IEEE80211_MAX_DATA_LEN +14+2); - if (!skb) { - kfree(frag); - goto resubmit; - } - frag->skb = skb; - frag->seq = seq & IEEE80211_SCTL_SEQ; - skb_reserve(skb, 2); - skb_put_data(skb, &data[datalen - 14], 12); - skb_put_data(skb, &data[6], 2); - skb_put_data(skb, data + 8, len); - hlist_add_head(&frag->fnode, &zd->fraglist); - goto resubmit; - } - hlist_for_each_entry(frag, &zd->fraglist, fnode) - if (frag->seq == (seq&IEEE80211_SCTL_SEQ)) - break; - if (!frag) - goto resubmit; - skb = frag->skb; - ptr = skb_put(skb, len); - if (ptr) - memcpy(ptr, data+8, len); - if (fc & IEEE80211_FCTL_MOREFRAGS) - goto resubmit; - hlist_del_init(&frag->fnode); - kfree(frag); - } else { - if (datalen<14) - goto resubmit; - skb = dev_alloc_skb(len + 14 + 2); - if (!skb) - goto resubmit; - skb_reserve(skb, 2); - skb_put_data(skb, &data[datalen - 14], 12); - skb_put_data(skb, &data[6], 2); - skb_put_data(skb, data + 8, len); - } - skb->protocol = eth_type_trans(skb, zd->dev); - zd->dev->stats.rx_packets++; - zd->dev->stats.rx_bytes += skb->len; - netif_rx(skb); - } -resubmit: - memset(data, 0, ZD1201_RXSIZE); - - urb->status = 0; - urb->dev = zd->usb; - if(usb_submit_urb(urb, GFP_ATOMIC)) - free = 1; - -exit: - if (free) { - zd->rxlen = 0; - zd->rxdatas = 1; - wake_up(&zd->rxdataq); - kfree(urb->transfer_buffer); - } -} - -static int zd1201_getconfig(struct zd1201 *zd, int rid, void *riddata, - unsigned int riddatalen) -{ - int err; - int i = 0; - int code; - int rid_fid; - int length; - unsigned char *pdata; - - zd->rxdatas = 0; - err = zd1201_docmd(zd, ZD1201_CMDCODE_ACCESS, rid, 0, 0); - if (err) - return err; - - wait_event_interruptible(zd->rxdataq, zd->rxdatas); - if (!zd->rxlen) - return -EIO; - - code = le16_to_cpu(*(__le16*)(&zd->rxdata[4])); - rid_fid = le16_to_cpu(*(__le16*)(&zd->rxdata[6])); - length = le16_to_cpu(*(__le16*)(&zd->rxdata[8])); - if (length > zd->rxlen) - length = zd->rxlen-6; - - /* If access bit is not on, then error */ - if ((code & ZD1201_ACCESSBIT) != ZD1201_ACCESSBIT || rid_fid != rid ) - return -EINVAL; - - /* Not enough buffer for allocating data */ - if (riddatalen != (length - 4)) { - dev_dbg(&zd->usb->dev, "riddatalen mismatches, expected=%u, (packet=%u) length=%u, rid=0x%04X, rid_fid=0x%04X\n", - riddatalen, zd->rxlen, length, rid, rid_fid); - return -ENODATA; - } - - zd->rxdatas = 0; - /* Issue SetRxRid commnd */ - err = zd1201_docmd(zd, ZD1201_CMDCODE_SETRXRID, rid, 0, length); - if (err) - return err; - - /* Receive RID record from resource packets */ - wait_event_interruptible(zd->rxdataq, zd->rxdatas); - if (!zd->rxlen) - return -EIO; - - if (zd->rxdata[zd->rxlen - 1] != ZD1201_PACKET_RESOURCE) { - dev_dbg(&zd->usb->dev, "Packet type mismatch: 0x%x not 0x3\n", - zd->rxdata[zd->rxlen-1]); - return -EINVAL; - } - - /* Set the data pointer and received data length */ - pdata = zd->rxdata; - length = zd->rxlen; - - do { - int actual_length; - - actual_length = (length > 64) ? 64 : length; - - if (pdata[0] != 0x3) { - dev_dbg(&zd->usb->dev, "Rx Resource packet type error: %02X\n", - pdata[0]); - return -EINVAL; - } - - if (actual_length != 64) { - /* Trim the last packet type byte */ - actual_length--; - } - - /* Skip the 4 bytes header (RID length and RID) */ - if (i == 0) { - pdata += 8; - actual_length -= 8; - } else { - pdata += 4; - actual_length -= 4; - } - - memcpy(riddata, pdata, actual_length); - riddata += actual_length; - pdata += actual_length; - length -= 64; - i++; - } while (length > 0); - - return 0; -} - -/* - * resreq: - * byte type - * byte sequence - * u16 reserved - * byte data[12] - * total: 16 - */ -static int zd1201_setconfig(struct zd1201 *zd, int rid, const void *buf, int len, int wait) -{ - int err; - unsigned char *request; - int reqlen; - char seq=0; - struct urb *urb; - gfp_t gfp_mask = wait ? GFP_NOIO : GFP_ATOMIC; - - len += 4; /* first 4 are for header */ - - zd->rxdatas = 0; - zd->rxlen = 0; - for (seq=0; len > 0; seq++) { - request = kzalloc(16, gfp_mask); - if (!request) - return -ENOMEM; - urb = usb_alloc_urb(0, gfp_mask); - if (!urb) { - kfree(request); - return -ENOMEM; - } - reqlen = len>12 ? 12 : len; - request[0] = ZD1201_USB_RESREQ; - request[1] = seq; - request[2] = 0; - request[3] = 0; - if (request[1] == 0) { - /* add header */ - *(__le16*)&request[4] = cpu_to_le16((len-2+1)/2); - *(__le16*)&request[6] = cpu_to_le16(rid); - memcpy(request+8, buf, reqlen-4); - buf += reqlen-4; - } else { - memcpy(request+4, buf, reqlen); - buf += reqlen; - } - - len -= reqlen; - - usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, - zd->endp_out2), request, 16, zd1201_usbfree, zd); - err = usb_submit_urb(urb, gfp_mask); - if (err) - goto err; - } - - request = kmalloc(16, gfp_mask); - if (!request) - return -ENOMEM; - urb = usb_alloc_urb(0, gfp_mask); - if (!urb) { - kfree(request); - return -ENOMEM; - } - *((__le32*)request) = cpu_to_le32(ZD1201_USB_CMDREQ); - *((__le16*)&request[4]) = - cpu_to_le16(ZD1201_CMDCODE_ACCESS|ZD1201_ACCESSBIT); - *((__le16*)&request[6]) = cpu_to_le16(rid); - *((__le16*)&request[8]) = cpu_to_le16(0); - *((__le16*)&request[10]) = cpu_to_le16(0); - usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, zd->endp_out2), - request, 16, zd1201_usbfree, zd); - err = usb_submit_urb(urb, gfp_mask); - if (err) - goto err; - - if (wait) { - wait_event_interruptible(zd->rxdataq, zd->rxdatas); - if (!zd->rxlen || le16_to_cpu(*(__le16*)&zd->rxdata[6]) != rid) { - dev_dbg(&zd->usb->dev, "wrong or no RID received\n"); - } - } - - return 0; -err: - kfree(request); - usb_free_urb(urb); - return err; -} - -static inline int zd1201_getconfig16(struct zd1201 *zd, int rid, short *val) -{ - int err; - __le16 zdval; - - err = zd1201_getconfig(zd, rid, &zdval, sizeof(__le16)); - if (err) - return err; - *val = le16_to_cpu(zdval); - return 0; -} - -static inline int zd1201_setconfig16(struct zd1201 *zd, int rid, short val) -{ - __le16 zdval = cpu_to_le16(val); - return (zd1201_setconfig(zd, rid, &zdval, sizeof(__le16), 1)); -} - -static int zd1201_drvr_start(struct zd1201 *zd) -{ - int err, i; - short max; - __le16 zdmax; - unsigned char *buffer; - - buffer = kzalloc(ZD1201_RXSIZE, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - usb_fill_bulk_urb(zd->rx_urb, zd->usb, - usb_rcvbulkpipe(zd->usb, zd->endp_in), buffer, ZD1201_RXSIZE, - zd1201_usbrx, zd); - - err = usb_submit_urb(zd->rx_urb, GFP_KERNEL); - if (err) - goto err_buffer; - - err = zd1201_docmd(zd, ZD1201_CMDCODE_INIT, 0, 0, 0); - if (err) - goto err_urb; - - err = zd1201_getconfig(zd, ZD1201_RID_CNFMAXTXBUFFERNUMBER, &zdmax, - sizeof(__le16)); - if (err) - goto err_urb; - - max = le16_to_cpu(zdmax); - for (i=0; irx_urb); - return err; -err_buffer: - kfree(buffer); - return err; -} - -/* Magic alert: The firmware doesn't seem to like the MAC state being - * toggled in promisc (aka monitor) mode. - * (It works a number of times, but will halt eventually) - * So we turn it of before disabling and on after enabling if needed. - */ -static int zd1201_enable(struct zd1201 *zd) -{ - int err; - - if (zd->mac_enabled) - return 0; - - err = zd1201_docmd(zd, ZD1201_CMDCODE_ENABLE, 0, 0, 0); - if (!err) - zd->mac_enabled = 1; - - if (zd->monitor) - err = zd1201_setconfig16(zd, ZD1201_RID_PROMISCUOUSMODE, 1); - - return err; -} - -static int zd1201_disable(struct zd1201 *zd) -{ - int err; - - if (!zd->mac_enabled) - return 0; - if (zd->monitor) { - err = zd1201_setconfig16(zd, ZD1201_RID_PROMISCUOUSMODE, 0); - if (err) - return err; - } - - err = zd1201_docmd(zd, ZD1201_CMDCODE_DISABLE, 0, 0, 0); - if (!err) - zd->mac_enabled = 0; - return err; -} - -static int zd1201_mac_reset(struct zd1201 *zd) -{ - if (!zd->mac_enabled) - return 0; - zd1201_disable(zd); - return zd1201_enable(zd); -} - -static int zd1201_join(struct zd1201 *zd, char *essid, int essidlen) -{ - int err, val; - char buf[IW_ESSID_MAX_SIZE+2]; - - err = zd1201_disable(zd); - if (err) - return err; - - val = ZD1201_CNFAUTHENTICATION_OPENSYSTEM; - val |= ZD1201_CNFAUTHENTICATION_SHAREDKEY; - err = zd1201_setconfig16(zd, ZD1201_RID_CNFAUTHENTICATION, val); - if (err) - return err; - - *(__le16 *)buf = cpu_to_le16(essidlen); - memcpy(buf+2, essid, essidlen); - if (!zd->ap) { /* Normal station */ - err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID, buf, - IW_ESSID_MAX_SIZE+2, 1); - if (err) - return err; - } else { /* AP */ - err = zd1201_setconfig(zd, ZD1201_RID_CNFOWNSSID, buf, - IW_ESSID_MAX_SIZE+2, 1); - if (err) - return err; - } - - err = zd1201_setconfig(zd, ZD1201_RID_CNFOWNMACADDR, - zd->dev->dev_addr, zd->dev->addr_len, 1); - if (err) - return err; - - err = zd1201_enable(zd); - if (err) - return err; - - msleep(100); - return 0; -} - -static int zd1201_net_open(struct net_device *dev) -{ - struct zd1201 *zd = netdev_priv(dev); - - /* Start MAC with wildcard if no essid set */ - if (!zd->mac_enabled) - zd1201_join(zd, zd->essid, zd->essidlen); - netif_start_queue(dev); - - return 0; -} - -static int zd1201_net_stop(struct net_device *dev) -{ - netif_stop_queue(dev); - return 0; -} - -/* - RFC 1042 encapsulates Ethernet frames in 802.11 frames - by prefixing them with 0xaa, 0xaa, 0x03) followed by a SNAP OID of 0 - (0x00, 0x00, 0x00). Zd requires an additional padding, copy - of ethernet addresses, length of the standard RFC 1042 packet - and a command byte (which is nul for tx). - - tx frame (from Wlan NG): - RFC 1042: - llc 0xAA 0xAA 0x03 (802.2 LLC) - snap 0x00 0x00 0x00 (Ethernet encapsulated) - type 2 bytes, Ethernet type field - payload (minus eth header) - Zydas specific: - padding 1B if (skb->len+8+1)%64==0 - Eth MAC addr 12 bytes, Ethernet MAC addresses - length 2 bytes, RFC 1042 packet length - (llc+snap+type+payload) - zd 1 null byte, zd1201 packet type - */ -static netdev_tx_t zd1201_hard_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct zd1201 *zd = netdev_priv(dev); - unsigned char *txbuf = zd->txdata; - int txbuflen, pad = 0, err; - struct urb *urb = zd->tx_urb; - - if (!zd->mac_enabled || zd->monitor) { - dev->stats.tx_dropped++; - kfree_skb(skb); - return NETDEV_TX_OK; - } - netif_stop_queue(dev); - - txbuflen = skb->len + 8 + 1; - if (txbuflen%64 == 0) { - pad = 1; - txbuflen++; - } - txbuf[0] = 0xAA; - txbuf[1] = 0xAA; - txbuf[2] = 0x03; - txbuf[3] = 0x00; /* rfc1042 */ - txbuf[4] = 0x00; - txbuf[5] = 0x00; - - skb_copy_from_linear_data_offset(skb, 12, txbuf + 6, skb->len - 12); - if (pad) - txbuf[skb->len-12+6]=0; - skb_copy_from_linear_data(skb, txbuf + skb->len - 12 + 6 + pad, 12); - *(__be16*)&txbuf[skb->len+6+pad] = htons(skb->len-12+6); - txbuf[txbuflen-1] = 0; - - usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, zd->endp_out), - txbuf, txbuflen, zd1201_usbtx, zd); - - err = usb_submit_urb(zd->tx_urb, GFP_ATOMIC); - if (err) { - dev->stats.tx_errors++; - netif_start_queue(dev); - } else { - dev->stats.tx_packets++; - dev->stats.tx_bytes += skb->len; - } - kfree_skb(skb); - - return NETDEV_TX_OK; -} - -static void zd1201_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - struct zd1201 *zd = netdev_priv(dev); - - if (!zd) - return; - dev_warn(&zd->usb->dev, "%s: TX timeout, shooting down urb\n", - dev->name); - usb_unlink_urb(zd->tx_urb); - dev->stats.tx_errors++; - /* Restart the timeout to quiet the watchdog: */ - netif_trans_update(dev); /* prevent tx timeout */ -} - -static int zd1201_set_mac_address(struct net_device *dev, void *p) -{ - struct sockaddr *addr = p; - struct zd1201 *zd = netdev_priv(dev); - int err; - - if (!zd) - return -ENODEV; - - err = zd1201_setconfig(zd, ZD1201_RID_CNFOWNMACADDR, - addr->sa_data, dev->addr_len, 1); - if (err) - return err; - eth_hw_addr_set(dev, addr->sa_data); - - return zd1201_mac_reset(zd); -} - -static struct iw_statistics *zd1201_get_wireless_stats(struct net_device *dev) -{ - struct zd1201 *zd = netdev_priv(dev); - - return &zd->iwstats; -} - -static void zd1201_set_multicast(struct net_device *dev) -{ - struct zd1201 *zd = netdev_priv(dev); - struct netdev_hw_addr *ha; - unsigned char reqbuf[ETH_ALEN*ZD1201_MAXMULTI]; - int i; - - if (netdev_mc_count(dev) > ZD1201_MAXMULTI) - return; - - i = 0; - netdev_for_each_mc_addr(ha, dev) - memcpy(reqbuf + i++ * ETH_ALEN, ha->addr, ETH_ALEN); - zd1201_setconfig(zd, ZD1201_RID_CNFGROUPADDRESS, reqbuf, - netdev_mc_count(dev) * ETH_ALEN, 0); -} - -static int zd1201_config_commit(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *essid) -{ - struct zd1201 *zd = netdev_priv(dev); - - return zd1201_mac_reset(zd); -} - -static int zd1201_get_name(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - strcpy(wrqu->name, "IEEE 802.11b"); - return 0; -} - -static int zd1201_set_freq(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_freq *freq = &wrqu->freq; - struct zd1201 *zd = netdev_priv(dev); - short channel = 0; - int err; - - if (freq->e == 0) - channel = freq->m; - else - channel = ieee80211_frequency_to_channel(freq->m); - - err = zd1201_setconfig16(zd, ZD1201_RID_CNFOWNCHANNEL, channel); - if (err) - return err; - - zd1201_mac_reset(zd); - - return 0; -} - -static int zd1201_get_freq(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_freq *freq = &wrqu->freq; - struct zd1201 *zd = netdev_priv(dev); - short channel; - int err; - - err = zd1201_getconfig16(zd, ZD1201_RID_CNFOWNCHANNEL, &channel); - if (err) - return err; - freq->e = 0; - freq->m = channel; - - return 0; -} - -static int zd1201_set_mode(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - __u32 *mode = &wrqu->mode; - struct zd1201 *zd = netdev_priv(dev); - short porttype, monitor = 0; - unsigned char buffer[IW_ESSID_MAX_SIZE+2]; - int err; - - if (zd->ap) { - if (*mode != IW_MODE_MASTER) - return -EINVAL; - return 0; - } - - err = zd1201_setconfig16(zd, ZD1201_RID_PROMISCUOUSMODE, 0); - if (err) - return err; - zd->dev->type = ARPHRD_ETHER; - switch(*mode) { - case IW_MODE_MONITOR: - monitor = 1; - zd->dev->type = ARPHRD_IEEE80211; - /* Make sure we are no longer associated with by - setting an 'impossible' essid. - (otherwise we mess up firmware) - */ - zd1201_join(zd, "\0-*#\0", 5); - /* Put port in pIBSS */ - fallthrough; - case 8: /* No pseudo-IBSS in wireless extensions (yet) */ - porttype = ZD1201_PORTTYPE_PSEUDOIBSS; - break; - case IW_MODE_ADHOC: - porttype = ZD1201_PORTTYPE_IBSS; - break; - case IW_MODE_INFRA: - porttype = ZD1201_PORTTYPE_BSS; - break; - default: - return -EINVAL; - } - - err = zd1201_setconfig16(zd, ZD1201_RID_CNFPORTTYPE, porttype); - if (err) - return err; - if (zd->monitor && !monitor) { - zd1201_disable(zd); - *(__le16 *)buffer = cpu_to_le16(zd->essidlen); - memcpy(buffer+2, zd->essid, zd->essidlen); - err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID, - buffer, IW_ESSID_MAX_SIZE+2, 1); - if (err) - return err; - } - zd->monitor = monitor; - /* If monitor mode is set we don't actually turn it on here since it - * is done during mac reset anyway (see zd1201_mac_enable). - */ - zd1201_mac_reset(zd); - - return 0; -} - -static int zd1201_get_mode(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - __u32 *mode = &wrqu->mode; - struct zd1201 *zd = netdev_priv(dev); - short porttype; - int err; - - err = zd1201_getconfig16(zd, ZD1201_RID_CNFPORTTYPE, &porttype); - if (err) - return err; - switch(porttype) { - case ZD1201_PORTTYPE_IBSS: - *mode = IW_MODE_ADHOC; - break; - case ZD1201_PORTTYPE_BSS: - *mode = IW_MODE_INFRA; - break; - case ZD1201_PORTTYPE_WDS: - *mode = IW_MODE_REPEAT; - break; - case ZD1201_PORTTYPE_PSEUDOIBSS: - *mode = 8;/* No Pseudo-IBSS... */ - break; - case ZD1201_PORTTYPE_AP: - *mode = IW_MODE_MASTER; - break; - default: - dev_dbg(&zd->usb->dev, "Unknown porttype: %d\n", - porttype); - *mode = IW_MODE_AUTO; - } - if (zd->monitor) - *mode = IW_MODE_MONITOR; - - return 0; -} - -static int zd1201_get_range(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_point *wrq = &wrqu->data; - struct iw_range *range = (struct iw_range *)extra; - - wrq->length = sizeof(struct iw_range); - memset(range, 0, sizeof(struct iw_range)); - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = WIRELESS_EXT; - - range->max_qual.qual = 128; - range->max_qual.level = 128; - range->max_qual.noise = 128; - range->max_qual.updated = 7; - - range->encoding_size[0] = 5; - range->encoding_size[1] = 13; - range->num_encoding_sizes = 2; - range->max_encoding_tokens = ZD1201_NUMKEYS; - - range->num_bitrates = 4; - range->bitrate[0] = 1000000; - range->bitrate[1] = 2000000; - range->bitrate[2] = 5500000; - range->bitrate[3] = 11000000; - - range->min_rts = 0; - range->min_frag = ZD1201_FRAGMIN; - range->max_rts = ZD1201_RTSMAX; - range->min_frag = ZD1201_FRAGMAX; - - return 0; -} - -/* Little bit of magic here: we only get the quality if we poll - * for it, and we never get an actual request to trigger such - * a poll. Therefore we 'assume' that the user will soon ask for - * the stats after asking the bssid. - */ -static int zd1201_get_wap(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct sockaddr *ap_addr = &wrqu->ap_addr; - struct zd1201 *zd = netdev_priv(dev); - unsigned char buffer[6]; - - if (!zd1201_getconfig(zd, ZD1201_RID_COMMSQUALITY, buffer, 6)) { - /* Unfortunately the quality and noise reported is useless. - they seem to be accumulators that increase until you - read them, unless we poll on a fixed interval we can't - use them - */ - /*zd->iwstats.qual.qual = le16_to_cpu(((__le16 *)buffer)[0]);*/ - zd->iwstats.qual.level = le16_to_cpu(((__le16 *)buffer)[1]); - /*zd->iwstats.qual.noise = le16_to_cpu(((__le16 *)buffer)[2]);*/ - zd->iwstats.qual.updated = 2; - } - - return zd1201_getconfig(zd, ZD1201_RID_CURRENTBSSID, ap_addr->sa_data, 6); -} - -static int zd1201_set_scan(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - /* We do everything in get_scan */ - return 0; -} - -static int zd1201_get_scan(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_point *srq = &wrqu->data; - struct zd1201 *zd = netdev_priv(dev); - int err, i, j, enabled_save; - struct iw_event iwe; - char *cev = extra; - char *end_buf = extra + IW_SCAN_MAX_DATA; - - /* No scanning in AP mode */ - if (zd->ap) - return -EOPNOTSUPP; - - /* Scan doesn't seem to work if disabled */ - enabled_save = zd->mac_enabled; - zd1201_enable(zd); - - zd->rxdatas = 0; - err = zd1201_docmd(zd, ZD1201_CMDCODE_INQUIRE, - ZD1201_INQ_SCANRESULTS, 0, 0); - if (err) - return err; - - wait_event_interruptible(zd->rxdataq, zd->rxdatas); - if (!zd->rxlen) - return -EIO; - - if (le16_to_cpu(*(__le16*)&zd->rxdata[2]) != ZD1201_INQ_SCANRESULTS) - return -EIO; - - for(i=8; irxlen; i+=62) { - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, zd->rxdata+i+6, 6); - cev = iwe_stream_add_event(info, cev, end_buf, - &iwe, IW_EV_ADDR_LEN); - - iwe.cmd = SIOCGIWESSID; - iwe.u.data.length = zd->rxdata[i+16]; - iwe.u.data.flags = 1; - cev = iwe_stream_add_point(info, cev, end_buf, - &iwe, zd->rxdata+i+18); - - iwe.cmd = SIOCGIWMODE; - if (zd->rxdata[i+14]&0x01) - iwe.u.mode = IW_MODE_MASTER; - else - iwe.u.mode = IW_MODE_ADHOC; - cev = iwe_stream_add_event(info, cev, end_buf, - &iwe, IW_EV_UINT_LEN); - - iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = zd->rxdata[i+0]; - iwe.u.freq.e = 0; - cev = iwe_stream_add_event(info, cev, end_buf, - &iwe, IW_EV_FREQ_LEN); - - iwe.cmd = SIOCGIWRATE; - iwe.u.bitrate.fixed = 0; - iwe.u.bitrate.disabled = 0; - for (j=0; j<10; j++) if (zd->rxdata[i+50+j]) { - iwe.u.bitrate.value = (zd->rxdata[i+50+j]&0x7f)*500000; - cev = iwe_stream_add_event(info, cev, end_buf, - &iwe, IW_EV_PARAM_LEN); - } - - iwe.cmd = SIOCGIWENCODE; - iwe.u.data.length = 0; - if (zd->rxdata[i+14]&0x10) - iwe.u.data.flags = IW_ENCODE_ENABLED; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - cev = iwe_stream_add_point(info, cev, end_buf, &iwe, NULL); - - iwe.cmd = IWEVQUAL; - iwe.u.qual.qual = zd->rxdata[i+4]; - iwe.u.qual.noise= zd->rxdata[i+2]/10-100; - iwe.u.qual.level = (256+zd->rxdata[i+4]*100)/255-100; - iwe.u.qual.updated = 7; - cev = iwe_stream_add_event(info, cev, end_buf, - &iwe, IW_EV_QUAL_LEN); - } - - if (!enabled_save) - zd1201_disable(zd); - - srq->length = cev - extra; - srq->flags = 0; - - return 0; -} - -static int zd1201_set_essid(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *essid) -{ - struct iw_point *data = &wrqu->data; - struct zd1201 *zd = netdev_priv(dev); - - if (data->length > IW_ESSID_MAX_SIZE) - return -EINVAL; - if (data->length < 1) - data->length = 1; - zd->essidlen = data->length; - memset(zd->essid, 0, IW_ESSID_MAX_SIZE+1); - memcpy(zd->essid, essid, data->length); - return zd1201_join(zd, zd->essid, zd->essidlen); -} - -static int zd1201_get_essid(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *essid) -{ - struct iw_point *data = &wrqu->data; - struct zd1201 *zd = netdev_priv(dev); - - memcpy(essid, zd->essid, zd->essidlen); - data->flags = 1; - data->length = zd->essidlen; - - return 0; -} - -static int zd1201_get_nick(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *nick) -{ - struct iw_point *data = &wrqu->data; - strcpy(nick, "zd1201"); - data->flags = 1; - data->length = strlen(nick); - return 0; -} - -static int zd1201_set_rate(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->bitrate; - struct zd1201 *zd = netdev_priv(dev); - short rate; - int err; - - switch (rrq->value) { - case 1000000: - rate = ZD1201_RATEB1; - break; - case 2000000: - rate = ZD1201_RATEB2; - break; - case 5500000: - rate = ZD1201_RATEB5; - break; - case 11000000: - default: - rate = ZD1201_RATEB11; - break; - } - if (!rrq->fixed) { /* Also enable all lower bitrates */ - rate |= rate-1; - } - - err = zd1201_setconfig16(zd, ZD1201_RID_TXRATECNTL, rate); - if (err) - return err; - - return zd1201_mac_reset(zd); -} - -static int zd1201_get_rate(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->bitrate; - struct zd1201 *zd = netdev_priv(dev); - short rate; - int err; - - err = zd1201_getconfig16(zd, ZD1201_RID_CURRENTTXRATE, &rate); - if (err) - return err; - - switch(rate) { - case 1: - rrq->value = 1000000; - break; - case 2: - rrq->value = 2000000; - break; - case 5: - rrq->value = 5500000; - break; - case 11: - rrq->value = 11000000; - break; - default: - rrq->value = 0; - } - rrq->fixed = 0; - rrq->disabled = 0; - - return 0; -} - -static int zd1201_set_rts(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rts = &wrqu->rts; - struct zd1201 *zd = netdev_priv(dev); - int err; - short val = rts->value; - - if (rts->disabled || !rts->fixed) - val = ZD1201_RTSMAX; - if (val > ZD1201_RTSMAX) - return -EINVAL; - if (val < 0) - return -EINVAL; - - err = zd1201_setconfig16(zd, ZD1201_RID_CNFRTSTHRESHOLD, val); - if (err) - return err; - return zd1201_mac_reset(zd); -} - -static int zd1201_get_rts(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rts = &wrqu->rts; - struct zd1201 *zd = netdev_priv(dev); - short rtst; - int err; - - err = zd1201_getconfig16(zd, ZD1201_RID_CNFRTSTHRESHOLD, &rtst); - if (err) - return err; - rts->value = rtst; - rts->disabled = (rts->value == ZD1201_RTSMAX); - rts->fixed = 1; - - return 0; -} - -static int zd1201_set_frag(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *frag = &wrqu->frag; - struct zd1201 *zd = netdev_priv(dev); - int err; - short val = frag->value; - - if (frag->disabled || !frag->fixed) - val = ZD1201_FRAGMAX; - if (val > ZD1201_FRAGMAX) - return -EINVAL; - if (val < ZD1201_FRAGMIN) - return -EINVAL; - if (val & 1) - return -EINVAL; - err = zd1201_setconfig16(zd, ZD1201_RID_CNFFRAGTHRESHOLD, val); - if (err) - return err; - return zd1201_mac_reset(zd); -} - -static int zd1201_get_frag(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *frag = &wrqu->frag; - struct zd1201 *zd = netdev_priv(dev); - short fragt; - int err; - - err = zd1201_getconfig16(zd, ZD1201_RID_CNFFRAGTHRESHOLD, &fragt); - if (err) - return err; - frag->value = fragt; - frag->disabled = (frag->value == ZD1201_FRAGMAX); - frag->fixed = 1; - - return 0; -} - -static int zd1201_set_retry(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - return 0; -} - -static int zd1201_get_retry(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - return 0; -} - -static int zd1201_set_encode(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *key) -{ - struct iw_point *erq = &wrqu->encoding; - struct zd1201 *zd = netdev_priv(dev); - short i; - int err, rid; - - if (erq->length > ZD1201_MAXKEYLEN) - return -EINVAL; - - i = (erq->flags & IW_ENCODE_INDEX)-1; - if (i == -1) { - err = zd1201_getconfig16(zd,ZD1201_RID_CNFDEFAULTKEYID,&i); - if (err) - return err; - } else { - err = zd1201_setconfig16(zd, ZD1201_RID_CNFDEFAULTKEYID, i); - if (err) - return err; - } - - if (i < 0 || i >= ZD1201_NUMKEYS) - return -EINVAL; - - rid = ZD1201_RID_CNFDEFAULTKEY0 + i; - err = zd1201_setconfig(zd, rid, key, erq->length, 1); - if (err) - return err; - zd->encode_keylen[i] = erq->length; - memcpy(zd->encode_keys[i], key, erq->length); - - i=0; - if (!(erq->flags & IW_ENCODE_DISABLED & IW_ENCODE_MODE)) { - i |= 0x01; - zd->encode_enabled = 1; - } else - zd->encode_enabled = 0; - if (erq->flags & IW_ENCODE_RESTRICTED & IW_ENCODE_MODE) { - i |= 0x02; - zd->encode_restricted = 1; - } else - zd->encode_restricted = 0; - err = zd1201_setconfig16(zd, ZD1201_RID_CNFWEBFLAGS, i); - if (err) - return err; - - if (zd->encode_enabled) - i = ZD1201_CNFAUTHENTICATION_SHAREDKEY; - else - i = ZD1201_CNFAUTHENTICATION_OPENSYSTEM; - err = zd1201_setconfig16(zd, ZD1201_RID_CNFAUTHENTICATION, i); - if (err) - return err; - - return zd1201_mac_reset(zd); -} - -static int zd1201_get_encode(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *key) -{ - struct iw_point *erq = &wrqu->encoding; - struct zd1201 *zd = netdev_priv(dev); - short i; - int err; - - if (zd->encode_enabled) - erq->flags = IW_ENCODE_ENABLED; - else - erq->flags = IW_ENCODE_DISABLED; - if (zd->encode_restricted) - erq->flags |= IW_ENCODE_RESTRICTED; - else - erq->flags |= IW_ENCODE_OPEN; - - i = (erq->flags & IW_ENCODE_INDEX) -1; - if (i == -1) { - err = zd1201_getconfig16(zd, ZD1201_RID_CNFDEFAULTKEYID, &i); - if (err) - return err; - } - if (i<0 || i>= ZD1201_NUMKEYS) - return -EINVAL; - - erq->flags |= i+1; - - erq->length = zd->encode_keylen[i]; - memcpy(key, zd->encode_keys[i], erq->length); - - return 0; -} - -static int zd1201_set_power(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *vwrq = &wrqu->power; - struct zd1201 *zd = netdev_priv(dev); - short enabled, duration, level; - int err; - - enabled = vwrq->disabled ? 0 : 1; - if (enabled) { - if (vwrq->flags & IW_POWER_PERIOD) { - duration = vwrq->value; - err = zd1201_setconfig16(zd, - ZD1201_RID_CNFMAXSLEEPDURATION, duration); - if (err) - return err; - goto out; - } - if (vwrq->flags & IW_POWER_TIMEOUT) { - err = zd1201_getconfig16(zd, - ZD1201_RID_CNFMAXSLEEPDURATION, &duration); - if (err) - return err; - level = vwrq->value * 4 / duration; - if (level > 4) - level = 4; - if (level < 0) - level = 0; - err = zd1201_setconfig16(zd, ZD1201_RID_CNFPMEPS, - level); - if (err) - return err; - goto out; - } - return -EINVAL; - } -out: - return zd1201_setconfig16(zd, ZD1201_RID_CNFPMENABLED, enabled); -} - -static int zd1201_get_power(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *vwrq = &wrqu->power; - struct zd1201 *zd = netdev_priv(dev); - short enabled, level, duration; - int err; - - err = zd1201_getconfig16(zd, ZD1201_RID_CNFPMENABLED, &enabled); - if (err) - return err; - err = zd1201_getconfig16(zd, ZD1201_RID_CNFPMEPS, &level); - if (err) - return err; - err = zd1201_getconfig16(zd, ZD1201_RID_CNFMAXSLEEPDURATION, &duration); - if (err) - return err; - vwrq->disabled = enabled ? 0 : 1; - if (vwrq->flags & IW_POWER_TYPE) { - if (vwrq->flags & IW_POWER_PERIOD) { - vwrq->value = duration; - vwrq->flags = IW_POWER_PERIOD; - } else { - vwrq->value = duration * level / 4; - vwrq->flags = IW_POWER_TIMEOUT; - } - } - if (vwrq->flags & IW_POWER_MODE) { - if (enabled && level) - vwrq->flags = IW_POWER_UNICAST_R; - else - vwrq->flags = IW_POWER_ALL_R; - } - - return 0; -} - - -static const iw_handler zd1201_iw_handler[] = -{ - IW_HANDLER(SIOCSIWCOMMIT, zd1201_config_commit), - IW_HANDLER(SIOCGIWNAME, zd1201_get_name), - IW_HANDLER(SIOCSIWFREQ, zd1201_set_freq), - IW_HANDLER(SIOCGIWFREQ, zd1201_get_freq), - IW_HANDLER(SIOCSIWMODE, zd1201_set_mode), - IW_HANDLER(SIOCGIWMODE, zd1201_get_mode), - IW_HANDLER(SIOCGIWRANGE, zd1201_get_range), - IW_HANDLER(SIOCGIWAP, zd1201_get_wap), - IW_HANDLER(SIOCSIWSCAN, zd1201_set_scan), - IW_HANDLER(SIOCGIWSCAN, zd1201_get_scan), - IW_HANDLER(SIOCSIWESSID, zd1201_set_essid), - IW_HANDLER(SIOCGIWESSID, zd1201_get_essid), - IW_HANDLER(SIOCGIWNICKN, zd1201_get_nick), - IW_HANDLER(SIOCSIWRATE, zd1201_set_rate), - IW_HANDLER(SIOCGIWRATE, zd1201_get_rate), - IW_HANDLER(SIOCSIWRTS, zd1201_set_rts), - IW_HANDLER(SIOCGIWRTS, zd1201_get_rts), - IW_HANDLER(SIOCSIWFRAG, zd1201_set_frag), - IW_HANDLER(SIOCGIWFRAG, zd1201_get_frag), - IW_HANDLER(SIOCSIWRETRY, zd1201_set_retry), - IW_HANDLER(SIOCGIWRETRY, zd1201_get_retry), - IW_HANDLER(SIOCSIWENCODE, zd1201_set_encode), - IW_HANDLER(SIOCGIWENCODE, zd1201_get_encode), - IW_HANDLER(SIOCSIWPOWER, zd1201_set_power), - IW_HANDLER(SIOCGIWPOWER, zd1201_get_power), -}; - -static int zd1201_set_hostauth(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->param; - struct zd1201 *zd = netdev_priv(dev); - - if (!zd->ap) - return -EOPNOTSUPP; - - return zd1201_setconfig16(zd, ZD1201_RID_CNFHOSTAUTH, rrq->value); -} - -static int zd1201_get_hostauth(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->param; - struct zd1201 *zd = netdev_priv(dev); - short hostauth; - int err; - - if (!zd->ap) - return -EOPNOTSUPP; - - err = zd1201_getconfig16(zd, ZD1201_RID_CNFHOSTAUTH, &hostauth); - if (err) - return err; - rrq->value = hostauth; - rrq->fixed = 1; - - return 0; -} - -static int zd1201_auth_sta(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct sockaddr *sta = &wrqu->ap_addr; - struct zd1201 *zd = netdev_priv(dev); - unsigned char buffer[10]; - - if (!zd->ap) - return -EOPNOTSUPP; - - memcpy(buffer, sta->sa_data, ETH_ALEN); - *(short*)(buffer+6) = 0; /* 0==success, 1==failure */ - *(short*)(buffer+8) = 0; - - return zd1201_setconfig(zd, ZD1201_RID_AUTHENTICATESTA, buffer, 10, 1); -} - -static int zd1201_set_maxassoc(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->param; - struct zd1201 *zd = netdev_priv(dev); - - if (!zd->ap) - return -EOPNOTSUPP; - - return zd1201_setconfig16(zd, ZD1201_RID_CNFMAXASSOCSTATIONS, rrq->value); -} - -static int zd1201_get_maxassoc(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->param; - struct zd1201 *zd = netdev_priv(dev); - short maxassoc; - int err; - - if (!zd->ap) - return -EOPNOTSUPP; - - err = zd1201_getconfig16(zd, ZD1201_RID_CNFMAXASSOCSTATIONS, &maxassoc); - if (err) - return err; - rrq->value = maxassoc; - rrq->fixed = 1; - - return 0; -} - -static const iw_handler zd1201_private_handler[] = { - zd1201_set_hostauth, /* ZD1201SIWHOSTAUTH */ - zd1201_get_hostauth, /* ZD1201GIWHOSTAUTH */ - zd1201_auth_sta, /* ZD1201SIWAUTHSTA */ - NULL, /* nothing to get */ - zd1201_set_maxassoc, /* ZD1201SIMAXASSOC */ - zd1201_get_maxassoc, /* ZD1201GIMAXASSOC */ -}; - -static const struct iw_priv_args zd1201_private_args[] = { - { ZD1201SIWHOSTAUTH, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_NONE, "sethostauth" }, - { ZD1201GIWHOSTAUTH, IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostauth" }, - { ZD1201SIWAUTHSTA, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_NONE, "authstation" }, - { ZD1201SIWMAXASSOC, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_NONE, "setmaxassoc" }, - { ZD1201GIWMAXASSOC, IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmaxassoc" }, -}; - -static const struct iw_handler_def zd1201_iw_handlers = { - .num_standard = ARRAY_SIZE(zd1201_iw_handler), - .num_private = ARRAY_SIZE(zd1201_private_handler), - .num_private_args = ARRAY_SIZE(zd1201_private_args), - .standard = zd1201_iw_handler, - .private = zd1201_private_handler, - .private_args = (struct iw_priv_args *) zd1201_private_args, - .get_wireless_stats = zd1201_get_wireless_stats, -}; - -static const struct net_device_ops zd1201_netdev_ops = { - .ndo_open = zd1201_net_open, - .ndo_stop = zd1201_net_stop, - .ndo_start_xmit = zd1201_hard_start_xmit, - .ndo_tx_timeout = zd1201_tx_timeout, - .ndo_set_rx_mode = zd1201_set_multicast, - .ndo_set_mac_address = zd1201_set_mac_address, - .ndo_validate_addr = eth_validate_addr, -}; - -static int zd1201_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct zd1201 *zd; - struct net_device *dev; - struct usb_device *usb; - int err; - short porttype; - char buf[IW_ESSID_MAX_SIZE+2]; - u8 addr[ETH_ALEN]; - - usb = interface_to_usbdev(interface); - - dev = alloc_etherdev(sizeof(*zd)); - if (!dev) - return -ENOMEM; - zd = netdev_priv(dev); - zd->dev = dev; - - zd->ap = ap; - zd->usb = usb; - zd->removed = 0; - init_waitqueue_head(&zd->rxdataq); - INIT_HLIST_HEAD(&zd->fraglist); - - err = zd1201_fw_upload(usb, zd->ap); - if (err) { - dev_err(&usb->dev, "zd1201 firmware upload failed: %d\n", err); - goto err_zd; - } - - zd->endp_in = 1; - zd->endp_out = 1; - zd->endp_out2 = 2; - zd->rx_urb = usb_alloc_urb(0, GFP_KERNEL); - zd->tx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!zd->rx_urb || !zd->tx_urb) { - err = -ENOMEM; - goto err_zd; - } - - mdelay(100); - err = zd1201_drvr_start(zd); - if (err) - goto err_zd; - - err = zd1201_setconfig16(zd, ZD1201_RID_CNFMAXDATALEN, 2312); - if (err) - goto err_start; - - err = zd1201_setconfig16(zd, ZD1201_RID_TXRATECNTL, - ZD1201_RATEB1 | ZD1201_RATEB2 | ZD1201_RATEB5 | ZD1201_RATEB11); - if (err) - goto err_start; - - dev->netdev_ops = &zd1201_netdev_ops; - dev->wireless_handlers = &zd1201_iw_handlers; - dev->watchdog_timeo = ZD1201_TX_TIMEOUT; - strcpy(dev->name, "wlan%d"); - - err = zd1201_getconfig(zd, ZD1201_RID_CNFOWNMACADDR, addr, ETH_ALEN); - if (err) - goto err_start; - eth_hw_addr_set(dev, addr); - - /* Set wildcard essid to match zd->essid */ - *(__le16 *)buf = cpu_to_le16(0); - err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID, buf, - IW_ESSID_MAX_SIZE+2, 1); - if (err) - goto err_start; - - if (zd->ap) - porttype = ZD1201_PORTTYPE_AP; - else - porttype = ZD1201_PORTTYPE_BSS; - err = zd1201_setconfig16(zd, ZD1201_RID_CNFPORTTYPE, porttype); - if (err) - goto err_start; - - SET_NETDEV_DEV(dev, &usb->dev); - - err = register_netdev(dev); - if (err) - goto err_start; - dev_info(&usb->dev, "%s: ZD1201 USB Wireless interface\n", - dev->name); - - usb_set_intfdata(interface, zd); - zd1201_enable(zd); /* zd1201 likes to startup enabled, */ - zd1201_disable(zd); /* interfering with all the wifis in range */ - return 0; - -err_start: - /* Leave the device in reset state */ - zd1201_docmd(zd, ZD1201_CMDCODE_INIT, 0, 0, 0); -err_zd: - usb_free_urb(zd->tx_urb); - usb_free_urb(zd->rx_urb); - free_netdev(dev); - return err; -} - -static void zd1201_disconnect(struct usb_interface *interface) -{ - struct zd1201 *zd = usb_get_intfdata(interface); - struct hlist_node *node2; - struct zd1201_frag *frag; - - if (!zd) - return; - usb_set_intfdata(interface, NULL); - - hlist_for_each_entry_safe(frag, node2, &zd->fraglist, fnode) { - hlist_del_init(&frag->fnode); - kfree_skb(frag->skb); - kfree(frag); - } - - if (zd->tx_urb) { - usb_kill_urb(zd->tx_urb); - usb_free_urb(zd->tx_urb); - } - if (zd->rx_urb) { - usb_kill_urb(zd->rx_urb); - usb_free_urb(zd->rx_urb); - } - - if (zd->dev) { - unregister_netdev(zd->dev); - free_netdev(zd->dev); - } -} - -#ifdef CONFIG_PM - -static int zd1201_suspend(struct usb_interface *interface, - pm_message_t message) -{ - struct zd1201 *zd = usb_get_intfdata(interface); - - netif_device_detach(zd->dev); - - zd->was_enabled = zd->mac_enabled; - - if (zd->was_enabled) - return zd1201_disable(zd); - else - return 0; -} - -static int zd1201_resume(struct usb_interface *interface) -{ - struct zd1201 *zd = usb_get_intfdata(interface); - - if (!zd || !zd->dev) - return -ENODEV; - - netif_device_attach(zd->dev); - - if (zd->was_enabled) - return zd1201_enable(zd); - else - return 0; -} - -#else - -#define zd1201_suspend NULL -#define zd1201_resume NULL - -#endif - -static struct usb_driver zd1201_usb = { - .name = "zd1201", - .probe = zd1201_probe, - .disconnect = zd1201_disconnect, - .id_table = zd1201_table, - .suspend = zd1201_suspend, - .resume = zd1201_resume, - .disable_hub_initiated_lpm = 1, -}; - -module_usb_driver(zd1201_usb); diff --git a/drivers/net/wireless/zydas/zd1201.h b/drivers/net/wireless/zydas/zd1201.h deleted file mode 100644 index c46ac87550d1b..0000000000000 --- a/drivers/net/wireless/zydas/zd1201.h +++ /dev/null @@ -1,144 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2004, 2005 Jeroen Vreeken (pe1rxq@amsat.org) - * - * Parts of this driver have been derived from a wlan-ng version - * modified by ZyDAS. - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - */ - -#ifndef _INCLUDE_ZD1201_H_ -#define _INCLUDE_ZD1201_H_ - -#define ZD1201_NUMKEYS 4 -#define ZD1201_MAXKEYLEN 13 -#define ZD1201_MAXMULTI 16 -#define ZD1201_FRAGMAX 2500 -#define ZD1201_FRAGMIN 256 -#define ZD1201_RTSMAX 2500 - -#define ZD1201_RXSIZE 3000 - -struct zd1201 { - struct usb_device *usb; - int removed; - struct net_device *dev; - struct iw_statistics iwstats; - - int endp_in; - int endp_out; - int endp_out2; - struct urb *rx_urb; - struct urb *tx_urb; - - unsigned char rxdata[ZD1201_RXSIZE]; - int rxlen; - wait_queue_head_t rxdataq; - int rxdatas; - struct hlist_head fraglist; - unsigned char txdata[ZD1201_RXSIZE]; - - int ap; - char essid[IW_ESSID_MAX_SIZE+1]; - int essidlen; - int mac_enabled; - int was_enabled; - int monitor; - int encode_enabled; - int encode_restricted; - unsigned char encode_keys[ZD1201_NUMKEYS][ZD1201_MAXKEYLEN]; - int encode_keylen[ZD1201_NUMKEYS]; -}; - -struct zd1201_frag { - struct hlist_node fnode; - int seq; - struct sk_buff *skb; -}; - -#define ZD1201SIWHOSTAUTH SIOCIWFIRSTPRIV -#define ZD1201GIWHOSTAUTH ZD1201SIWHOSTAUTH+1 -#define ZD1201SIWAUTHSTA SIOCIWFIRSTPRIV+2 -#define ZD1201SIWMAXASSOC SIOCIWFIRSTPRIV+4 -#define ZD1201GIWMAXASSOC ZD1201SIWMAXASSOC+1 - -#define ZD1201_FW_TIMEOUT (1000) - -#define ZD1201_TX_TIMEOUT (2000) - -#define ZD1201_USB_CMDREQ 0 -#define ZD1201_USB_RESREQ 1 - -#define ZD1201_CMDCODE_INIT 0x00 -#define ZD1201_CMDCODE_ENABLE 0x01 -#define ZD1201_CMDCODE_DISABLE 0x02 -#define ZD1201_CMDCODE_ALLOC 0x0a -#define ZD1201_CMDCODE_INQUIRE 0x11 -#define ZD1201_CMDCODE_SETRXRID 0x17 -#define ZD1201_CMDCODE_ACCESS 0x21 - -#define ZD1201_PACKET_EVENTSTAT 0x0 -#define ZD1201_PACKET_RXDATA 0x1 -#define ZD1201_PACKET_INQUIRE 0x2 -#define ZD1201_PACKET_RESOURCE 0x3 - -#define ZD1201_ACCESSBIT 0x0100 - -#define ZD1201_RID_CNFPORTTYPE 0xfc00 -#define ZD1201_RID_CNFOWNMACADDR 0xfc01 -#define ZD1201_RID_CNFDESIREDSSID 0xfc02 -#define ZD1201_RID_CNFOWNCHANNEL 0xfc03 -#define ZD1201_RID_CNFOWNSSID 0xfc04 -#define ZD1201_RID_CNFMAXDATALEN 0xfc07 -#define ZD1201_RID_CNFPMENABLED 0xfc09 -#define ZD1201_RID_CNFPMEPS 0xfc0a -#define ZD1201_RID_CNFMAXSLEEPDURATION 0xfc0c -#define ZD1201_RID_CNFDEFAULTKEYID 0xfc23 -#define ZD1201_RID_CNFDEFAULTKEY0 0xfc24 -#define ZD1201_RID_CNFDEFAULTKEY1 0xfc25 -#define ZD1201_RID_CNFDEFAULTKEY2 0xfc26 -#define ZD1201_RID_CNFDEFAULTKEY3 0xfc27 -#define ZD1201_RID_CNFWEBFLAGS 0xfc28 -#define ZD1201_RID_CNFAUTHENTICATION 0xfc2a -#define ZD1201_RID_CNFMAXASSOCSTATIONS 0xfc2b -#define ZD1201_RID_CNFHOSTAUTH 0xfc2e -#define ZD1201_RID_CNFGROUPADDRESS 0xfc80 -#define ZD1201_RID_CNFFRAGTHRESHOLD 0xfc82 -#define ZD1201_RID_CNFRTSTHRESHOLD 0xfc83 -#define ZD1201_RID_TXRATECNTL 0xfc84 -#define ZD1201_RID_PROMISCUOUSMODE 0xfc85 -#define ZD1201_RID_CNFBASICRATES 0xfcb3 -#define ZD1201_RID_AUTHENTICATESTA 0xfce3 -#define ZD1201_RID_CURRENTBSSID 0xfd42 -#define ZD1201_RID_COMMSQUALITY 0xfd43 -#define ZD1201_RID_CURRENTTXRATE 0xfd44 -#define ZD1201_RID_CNFMAXTXBUFFERNUMBER 0xfda0 -#define ZD1201_RID_CURRENTCHANNEL 0xfdc1 - -#define ZD1201_INQ_SCANRESULTS 0xf101 - -#define ZD1201_INF_LINKSTATUS 0xf200 -#define ZD1201_INF_ASSOCSTATUS 0xf201 -#define ZD1201_INF_AUTHREQ 0xf202 - -#define ZD1201_ASSOCSTATUS_STAASSOC 0x1 -#define ZD1201_ASSOCSTATUS_REASSOC 0x2 -#define ZD1201_ASSOCSTATUS_DISASSOC 0x3 -#define ZD1201_ASSOCSTATUS_ASSOCFAIL 0x4 -#define ZD1201_ASSOCSTATUS_AUTHFAIL 0x5 - -#define ZD1201_PORTTYPE_IBSS 0 -#define ZD1201_PORTTYPE_BSS 1 -#define ZD1201_PORTTYPE_WDS 2 -#define ZD1201_PORTTYPE_PSEUDOIBSS 3 -#define ZD1201_PORTTYPE_AP 6 - -#define ZD1201_RATEB1 1 -#define ZD1201_RATEB2 2 -#define ZD1201_RATEB5 4 /* 5.5 really, but 5 is shorter :) */ -#define ZD1201_RATEB11 8 - -#define ZD1201_CNFAUTHENTICATION_OPENSYSTEM 0x0001 -#define ZD1201_CNFAUTHENTICATION_SHAREDKEY 0x0002 - -#endif /* _INCLUDE_ZD1201_H_ */ diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 958771bac9c02..5e5ea216f3413 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -172,11 +172,11 @@ #define IEEE80211_SN_MODULO (IEEE80211_MAX_SN + 1) -/* PV1 Layout 11ah 9.8.3.1 */ +/* PV1 Layout IEEE 802.11-2020 9.8.3.1 */ #define IEEE80211_PV1_FCTL_VERS 0x0003 #define IEEE80211_PV1_FCTL_FTYPE 0x001c #define IEEE80211_PV1_FCTL_STYPE 0x00e0 -#define IEEE80211_PV1_FCTL_TODS 0x0100 +#define IEEE80211_PV1_FCTL_FROMDS 0x0100 #define IEEE80211_PV1_FCTL_MOREFRAGS 0x0200 #define IEEE80211_PV1_FCTL_PM 0x0400 #define IEEE80211_PV1_FCTL_MOREDATA 0x0800 diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index b137a33a1b689..d36ad4cedf3b5 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2608,6 +2608,8 @@ struct cfg80211_scan_6ghz_params { * @n_6ghz_params: number of 6 GHz params * @scan_6ghz_params: 6 GHz params * @bssid: BSSID to scan for (most commonly, the wildcard BSSID) + * @tsf_report_link_id: for MLO, indicates the link ID of the BSS that should be + * used for TSF reporting. Can be set to -1 to indicate no preference. */ struct cfg80211_scan_request { struct cfg80211_ssid *ssids; @@ -2636,6 +2638,7 @@ struct cfg80211_scan_request { bool scan_6ghz; u32 n_6ghz_params; struct cfg80211_scan_6ghz_params *scan_6ghz_params; + s8 tsf_report_link_id; /* keep last */ struct ieee80211_channel *channels[] __counted_by(n_channels); diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index dced2c49daecd..0cd1da2c2902a 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1135,11 +1135,15 @@ * @NL80211_CMD_DEL_PMK: For offloaded 4-Way handshake, delete the previously * configured PMK for the authenticator address identified by * %NL80211_ATTR_MAC. - * @NL80211_CMD_PORT_AUTHORIZED: An event that indicates an 802.1X FT roam was - * completed successfully. Drivers that support 4 way handshake offload - * should send this event after indicating 802.1X FT assocation with - * %NL80211_CMD_ROAM. If the 4 way handshake failed %NL80211_CMD_DISCONNECT - * should be indicated instead. + * @NL80211_CMD_PORT_AUTHORIZED: An event that indicates port is authorized and + * open for regular data traffic. For STA/P2P-client, this event is sent + * with AP MAC address and for AP/P2P-GO, the event carries the STA/P2P- + * client MAC address. + * Drivers that support 4 way handshake offload should send this event for + * STA/P2P-client after successful 4-way HS or after 802.1X FT following + * NL80211_CMD_CONNECT or NL80211_CMD_ROAM. Drivers using AP/P2P-GO 4-way + * handshake offload should send this event on successful completion of + * 4-way handshake with the peer (STA/P2P-client). * @NL80211_CMD_CONTROL_PORT_FRAME: Control Port (e.g. PAE) frame TX request * and RX notification. This command is used both as a request to transmit * a control port frame and as a notification that a control port frame @@ -6241,9 +6245,11 @@ enum nl80211_feature_flags { * the BSS that the interface that requested the scan is connected to * (if available). * @NL80211_EXT_FEATURE_BSS_PARENT_TSF: Per BSS, this driver reports the - * time the last beacon/probe was received. The time is the TSF of the - * BSS that the interface that requested the scan is connected to - * (if available). + * time the last beacon/probe was received. For a non MLO connection, the + * time is the TSF of the BSS that the interface that requested the scan is + * connected to (if available). For an MLO connection, the time is the TSF + * of the BSS corresponding with link ID specified in the scan request (if + * specified). * @NL80211_EXT_FEATURE_SET_SCAN_DWELL: This driver supports configuration of * channel dwell time. * @NL80211_EXT_FEATURE_BEACON_RATE_LEGACY: Driver supports beacon rate diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 24fa06105378d..1d98877647d85 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -194,11 +194,32 @@ ieee80211_bss_info_update(struct ieee80211_local *local, if (scan_sdata && scan_sdata->vif.type == NL80211_IFTYPE_STATION && scan_sdata->vif.cfg.assoc && ieee80211_have_rx_timestamp(rx_status)) { - bss_meta.parent_tsf = - ieee80211_calculate_rx_timestamp(local, rx_status, - len + FCS_LEN, 24); - ether_addr_copy(bss_meta.parent_bssid, - scan_sdata->vif.bss_conf.bssid); + struct ieee80211_bss_conf *link_conf = NULL; + + /* for an MLO connection, set the TSF data only in case we have + * an indication on which of the links the frame was received + */ + if (ieee80211_vif_is_mld(&scan_sdata->vif)) { + if (rx_status->link_valid) { + s8 link_id = rx_status->link_id; + + link_conf = + rcu_dereference(scan_sdata->vif.link_conf[link_id]); + } + } else { + link_conf = &scan_sdata->vif.bss_conf; + } + + if (link_conf) { + bss_meta.parent_tsf = + ieee80211_calculate_rx_timestamp(local, + rx_status, + len + FCS_LEN, + 24); + + ether_addr_copy(bss_meta.parent_bssid, + link_conf->bssid); + } } rcu_read_unlock(); @@ -666,6 +687,21 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, if (local->scan_req) return -EBUSY; + /* For an MLO connection, if a link ID was specified, validate that it + * is indeed active. If no link ID was specified, select one of the + * active links. + */ + if (ieee80211_vif_is_mld(&sdata->vif)) { + if (req->tsf_report_link_id >= 0) { + if (!(sdata->vif.active_links & + BIT(req->tsf_report_link_id))) + return -EINVAL; + } else { + req->tsf_report_link_id = + __ffs(sdata->vif.active_links); + } + } + if (!__ieee80211_can_leave_ch(sdata)) return -EBUSY; @@ -714,6 +750,8 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, local->hw_scan_req->req.duration = req->duration; local->hw_scan_req->req.duration_mandatory = req->duration_mandatory; + local->hw_scan_req->req.tsf_report_link_id = + req->tsf_report_link_id; local->hw_scan_band = 0; local->hw_scan_req->req.n_6ghz_params = req->n_6ghz_params; diff --git a/net/rfkill/core.c b/net/rfkill/core.c index 14cc8fe8584bd..c3feb4f49d09c 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c @@ -1351,11 +1351,11 @@ static long rfkill_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct rfkill_data *data = file->private_data; - int ret = -ENOSYS; + int ret = -ENOTTY; u32 size; if (_IOC_TYPE(cmd) != RFKILL_IOC_MAGIC) - return -ENOSYS; + return -ENOTTY; mutex_lock(&data->mtx); switch (_IOC_NR(cmd)) { diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 569234bc2be6a..12b7bd92bb86a 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -9337,6 +9337,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) else eth_broadcast_addr(request->bssid); + request->tsf_report_link_id = nl80211_link_id_or_invalid(info->attrs); request->wdev = wdev; request->wiphy = &rdev->wiphy; request->scan_start = jiffies;