wireless-next patches for v6.8
The first features pull request for v6.8. Not so big in number of commits but we removed quite a few ancient drivers: libertas 16-bit PCMCIA support, atmel, hostap, zd1201, orinoco, ray_cs, wl3501 and rndis_wlan. Major changes: cfg80211/mac80211 * extend support for scanning while Multi-Link Operation (MLO) connected -----BEGIN PGP SIGNATURE----- iQFFBAABCgAvFiEEiBjanGPFTz4PRfLobhckVSbrbZsFAmVk2JkRHGt2YWxvQGtl cm5lbC5vcmcACgkQbhckVSbrbZtD4gf7B8eR+lq6+5Qg7ObiURTci/WYlDo3prz4 R7hDmuHI5S3AJIRXF87fmC1iThIigi6dri1akRdRo3UvNr9gBTRpDGHnALuDPxOp p8MpsG1gPNhMo0aNFfX5RDaGkfKqZQMT3er3ELG4B+k4q0glNWud07D2/0t1zSt9 rag3vlFVPRzcCz2T/Xv/nXXWaiIaQx0RLHrQshbxg0Glu+m/l3/ACBrirMiWami4 nr4SX717yckqwRElH0l5fSmCbylTDCTslo4UnpVKusxTtt1f3RxFZvsxvRgI5O9q LEYsMtjNj2Ea3uLb0DvSNY640O/dqbRSm0PjwYxPwlmrtQB/6GMx8g== =a+Xs -----END PGP SIGNATURE----- Merge tag 'wireless-next-2023-11-27' of git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next Kalle Valo says: ==================== wireless-next patches for v6.8 The first features pull request for v6.8. Not so big in number of commits but we removed quite a few ancient drivers: libertas 16-bit PCMCIA support, atmel, hostap, zd1201, orinoco, ray_cs, wl3501 and rndis_wlan. Major changes: cfg80211/mac80211 - extend support for scanning while Multi-Link Operation (MLO) connected * tag 'wireless-next-2023-11-27' of git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next: (68 commits) wifi: nl80211: Documentation update for NL80211_CMD_PORT_AUTHORIZED event wifi: mac80211: Extend support for scanning while MLO connected wifi: cfg80211: Extend support for scanning while MLO connected wifi: ieee80211: fix PV1 frame control field name rfkill: return ENOTTY on invalid ioctl MAINTAINERS: update iwlwifi maintainers wifi: rtw89: 8922a: read efuse content from physical map wifi: rtw89: 8922a: read efuse content via efuse map struct from logic map wifi: rtw89: 8852c: read RX gain offset from efuse for 6GHz channels wifi: rtw89: mac: add to access efuse for WiFi 7 chips wifi: rtw89: mac: use mac_gen pointer to access about efuse wifi: rtw89: 8922a: add 8922A basic chip info wifi: rtlwifi: drop unused const_amdpci_aspm wifi: mwifiex: mwifiex_process_sleep_confirm_resp(): remove unused priv variable wifi: rtw89: regd: update regulatory map to R65-R44 wifi: rtw89: regd: handle policy of 6 GHz according to BIOS wifi: rtw89: acpi: process 6 GHz band policy from DSM wifi: rtlwifi: simplify rtl_action_proc() and rtl_tx_agg_start() wifi: rtw89: pci: update interrupt mitigation register for 8922AE wifi: rtw89: pci: correct interrupt mitigation register for 8852CE ... ==================== Link: https://lore.kernel.org/r/20231127180056.0B48DC433C8@smtp.kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
a214724554
@ -10,7 +10,6 @@ Contents:
|
||||
|
||||
intel/ipw2100
|
||||
intel/ipw2200
|
||||
ray_cs
|
||||
|
||||
.. only:: subproject and html
|
||||
|
||||
|
@ -1,165 +0,0 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
.. include:: <isonum.txt>
|
||||
|
||||
=========================
|
||||
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.
|
42
MAINTAINERS
42
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 <will@kernel.org>
|
||||
M: Peter Zijlstra <peterz@infradead.org>
|
||||
@ -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 <jorge.lopez2@hp.com>
|
||||
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 <gregory.greenman@intel.com>
|
||||
M: Miri Korenblit <miriam.rachel.korenblit@intel.com>
|
||||
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" <prabhakar.csengg@gmail.com>
|
||||
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 <sean@mess.org>
|
||||
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 <mathias.nyman@intel.com>
|
||||
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 <willemdebruijn.kernel@gmail.com>
|
||||
S: Maintained
|
||||
@ -23499,11 +23464,6 @@ M: Miloslav Trmac <mitr@volny.cz>
|
||||
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 <W_Armin@gmx.de>
|
||||
R: Thomas Weißschuh <linux@weissschuh.net>
|
||||
|
@ -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
|
||||
|
@ -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/
|
||||
|
@ -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
|
||||
<http://www.thekelleys.org.uk/atmel>
|
||||
|
||||
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
|
||||
|
@ -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
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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
|
@ -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 <simon@thekelleys.org.uk> 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
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
#ifdef __IN_PCMCIA_PACKAGE__
|
||||
#include <pcmcia/k_compat.h>
|
||||
#endif
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
#include <pcmcia/cistpl.h>
|
||||
#include <pcmcia/cisreg.h>
|
||||
#include <pcmcia/ds.h>
|
||||
#include <pcmcia/ciscode.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <linux/wireless.h>
|
||||
|
||||
#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.
|
||||
*/
|
@ -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 <linux/pci.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/netdevice.h>
|
||||
#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);
|
@ -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");
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
@ -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
|
File diff suppressed because it is too large
Load Diff
@ -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_ */
|
@ -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 <breed@users.sourceforge.net>
|
||||
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
|
||||
<dahinds@users.sourceforge.net>. Portions created by David A. Hinds
|
||||
are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
|
||||
|
||||
======================================================================*/
|
||||
|
||||
#ifdef __IN_PCMCIA_PACKAGE__
|
||||
#include <pcmcia/k_compat.h>
|
||||
#endif
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
#include <pcmcia/cistpl.h>
|
||||
#include <pcmcia/cisreg.h>
|
||||
#include <pcmcia/ds.h>
|
||||
|
||||
#include <linux/io.h>
|
||||
|
||||
#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.
|
||||
*/
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -1,4 +1,2 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
obj-$(CONFIG_HOSTAP) += hostap/
|
||||
obj-$(CONFIG_HERMES) += orinoco/
|
||||
obj-$(CONFIG_P54_COMMON) += p54/
|
||||
|
@ -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 <http://hostap.epitest.fi/> 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.
|
@ -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
|
@ -1,98 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef HOSTAP_H
|
||||
#define HOSTAP_H
|
||||
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#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 */
|
@ -1,97 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef HOSTAP_80211_H
|
||||
#define HOSTAP_80211_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
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 */
|
File diff suppressed because it is too large
Load Diff
@ -1,554 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/slab.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/etherdevice.h>
|
||||
|
||||
#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);
|
File diff suppressed because it is too large
Load Diff
@ -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 */
|
@ -1,420 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef HOSTAP_COMMON_H
|
||||
#define HOSTAP_COMMON_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/if_ether.h>
|
||||
|
||||
/* 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 */
|
@ -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 */
|
@ -1,710 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#define PRISM2_PCCARD
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <net/iw_handler.h>
|
||||
|
||||
#include <pcmcia/cistpl.h>
|
||||
#include <pcmcia/cisreg.h>
|
||||
#include <pcmcia/ds.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#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);
|
@ -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;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,509 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Host AP driver Info Frame processing (part of hostap.o module) */
|
||||
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#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);
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -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 <reyk@vantronix.net> and
|
||||
* Andy Warner <andyw@pobox.com> */
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <net/iw_handler.h>
|
||||
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/pci.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#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);
|
@ -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 <linux/module.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <net/iw_handler.h>
|
||||
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/pci.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#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);
|
@ -1,411 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* /proc routines for Host AP driver */
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/export.h>
|
||||
#include <net/lib80211.h>
|
||||
|
||||
#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);
|
File diff suppressed because it is too large
Load Diff
@ -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 :
|
||||
<https://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>
|
||||
|
||||
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:
|
||||
<https://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
|
||||
|
||||
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
|
||||
<http://sourceforge.net/projects/orinoco/>
|
||||
|
||||
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.
|
@ -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
|
@ -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 <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <asm/pmac_feature.h>
|
||||
|
||||
#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 <benh@kernel.crashing.org>)";
|
||||
MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
|
||||
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);
|
@ -1,291 +0,0 @@
|
||||
/* cfg80211 support
|
||||
*
|
||||
* See copyright notice in main.c
|
||||
*/
|
||||
#include <linux/ieee80211.h>
|
||||
#include <net/cfg80211.h>
|
||||
#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,
|
||||
};
|
@ -1,15 +0,0 @@
|
||||
/* cfg80211 support.
|
||||
*
|
||||
* See copyright notice in main.c
|
||||
*/
|
||||
#ifndef ORINOCO_CFG_H
|
||||
#define ORINOCO_CFG_H
|
||||
|
||||
#include <net/cfg80211.h>
|
||||
|
||||
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 */
|
@ -1,387 +0,0 @@
|
||||
/* Firmware file reading and download helpers
|
||||
*
|
||||
* See copyright notice in main.c
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#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
|
@ -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_ */
|
@ -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 <linux/net.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#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,
|
||||
};
|
@ -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 <linux/if_ether.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
/*
|
||||
* 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 <h1kari AT dachb0den.com> - 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 */
|
@ -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 <proski@gnu.org>
|
||||
* 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 <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#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;
|
||||
}
|
@ -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 */
|
@ -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
|
File diff suppressed because it is too large
Load Diff
@ -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 <linux/types.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <net/cfg80211.h>
|
||||
|
||||
/* 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_ */
|
File diff suppressed because it is too large
Load Diff
@ -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 <linux/ieee80211.h>
|
||||
#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_ */
|
@ -1,89 +0,0 @@
|
||||
/* Orinoco MIC helpers
|
||||
*
|
||||
* See copyright notice in main.c
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <crypto/hash.h>
|
||||
|
||||
#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;
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
/* Orinoco MIC helpers
|
||||
*
|
||||
* See copyright notice in main.c
|
||||
*/
|
||||
#ifndef _ORINOCO_MIC_H_
|
||||
#define _ORINOCO_MIC_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <crypto/hash.h>
|
||||
|
||||
#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 */
|
@ -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 <linux/interrupt.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <net/iw_handler.h>
|
||||
#include <net/cfg80211.h>
|
||||
|
||||
#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 */
|
@ -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 <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/delay.h>
|
||||
#include <pcmcia/cistpl.h>
|
||||
#include <pcmcia/cisreg.h>
|
||||
#include <pcmcia/ds.h>
|
||||
|
||||
#include "orinoco.h"
|
||||
|
||||
/********************************************************************/
|
||||
/* Module stuff */
|
||||
/********************************************************************/
|
||||
|
||||
MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>");
|
||||
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);
|
@ -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 <disdos@traum404.de>
|
||||
*
|
||||
* 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 <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pci.h>
|
||||
#include <pcmcia/cisreg.h>
|
||||
|
||||
#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 <disdos@traum404.de>)";
|
||||
MODULE_AUTHOR("Christoph Jungegger <disdos@traum404.de>");
|
||||
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);
|
@ -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 <proski AT gnu.org>
|
||||
* and David Gibson <hermes AT gibson.dropbear.id.au>
|
||||
*
|
||||
* Some of this code is borrowed from orinoco_plx.c
|
||||
* Copyright (C) 2001 Daniel Barlow <dan AT telent.net>
|
||||
* 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 <jt AT hpl.hp.com>
|
||||
* 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 <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#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 <proski@gnu.org>,"
|
||||
" David Gibson <hermes@gibson.dropbear.id.au> &"
|
||||
" Jean Tourrilhes <jt@hpl.hp.com>)";
|
||||
MODULE_AUTHOR("Pavel Roskin <proski@gnu.org> &"
|
||||
" David Gibson <hermes@gibson.dropbear.id.au>");
|
||||
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);
|
@ -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 <linux/netdevice.h>
|
||||
|
||||
/* 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 */
|
@ -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 <proski AT gnu.org>
|
||||
* and David Gibson <hermes AT gibson.dropbear.id.au>
|
||||
*
|
||||
* (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 <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pci.h>
|
||||
#include <pcmcia/cisreg.h>
|
||||
|
||||
#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 <rit AT jacked-in.org> */
|
||||
{0x10b7, 0x7770, PCI_ANY_ID, PCI_ANY_ID,}, /* 3Com AirConnect PCI tested by
|
||||
Damien Persohn <damien AT persohn.net> */
|
||||
{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 <proski@gnu.org>,"
|
||||
" David Gibson <hermes@gibson.dropbear.id.au>,"
|
||||
" Daniel Barlow <dan@telent.net>)";
|
||||
MODULE_AUTHOR("Daniel Barlow <dan@telent.net>");
|
||||
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);
|
@ -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 <joerg AT dorchain.net>
|
||||
* 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 <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pci.h>
|
||||
#include <pcmcia/cisreg.h>
|
||||
|
||||
#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 <joerg@dorchain.net>)";
|
||||
MODULE_AUTHOR("Joerg Dorchain <joerg@dorchain.net>");
|
||||
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);
|
File diff suppressed because it is too large
Load Diff
@ -1,259 +0,0 @@
|
||||
/* Helpers for managing scan queues
|
||||
*
|
||||
* See copyright notice in main.c
|
||||
*/
|
||||
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/ieee80211.h>
|
||||
#include <net/cfg80211.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
}
|
@ -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_ */
|
@ -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 <proski@gnu.org>
|
||||
* 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 <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/delay.h>
|
||||
#include <pcmcia/cistpl.h>
|
||||
#include <pcmcia/cisreg.h>
|
||||
#include <pcmcia/ds.h>
|
||||
|
||||
#include "orinoco.h"
|
||||
|
||||
/********************************************************************/
|
||||
/* Module stuff */
|
||||
/********************************************************************/
|
||||
|
||||
MODULE_AUTHOR("Pavel Roskin <proski@gnu.org>");
|
||||
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);
|
File diff suppressed because it is too large
Load Diff
@ -1,13 +0,0 @@
|
||||
/* Wireless extensions support.
|
||||
*
|
||||
* See copyright notice in main.c
|
||||
*/
|
||||
#ifndef _ORINOCO_WEXT_H_
|
||||
#define _ORINOCO_WEXT_H_
|
||||
|
||||
#include <net/iw_handler.h>
|
||||
|
||||
/* Structure defining all our WEXT handlers */
|
||||
extern const struct iw_handler_def orinoco_handler_def;
|
||||
|
||||
#endif /* _ORINOCO_WEXT_H_ */
|
@ -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
|
||||
<file:Documentation/networking/device_drivers/wifi/ray_cs.rst> 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.
|
||||
|
@ -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
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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_ */
|
@ -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_ */
|
File diff suppressed because it is too large
Load Diff
@ -1,615 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef __WL3501_H__
|
||||
#define __WL3501_H__
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/ieee80211.h>
|
||||
|
||||
/* 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
|
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 <hs4233@mail.mn-solutions.de>
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
#include <pcmcia/cistpl.h>
|
||||
#include <pcmcia/ds.h>
|
||||
|
||||
#include <linux/io.h>
|
||||
|
||||
#define DRV_NAME "libertas_cs"
|
||||
|
||||
#include "decl.h"
|
||||
#include "defs.h"
|
||||
#include "dev.h"
|
||||
|
||||
|
||||
/********************************************************************/
|
||||
/* Module stuff */
|
||||
/********************************************************************/
|
||||
|
||||
MODULE_AUTHOR("Holger Schurig <hs4233@mail.mn-solutions.de>");
|
||||
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);
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 @@ out:
|
||||
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)
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user