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:
Jakub Kicinski 2023-11-27 18:43:27 -08:00
commit a214724554
158 changed files with 3424 additions and 58838 deletions

View File

@ -10,7 +10,6 @@ Contents:
intel/ipw2100
intel/ipw2200
ray_cs
.. only:: subproject and html

View File

@ -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.

View File

@ -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>

View File

@ -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

View File

@ -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/

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.
*/

View File

@ -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);

View File

@ -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");

View File

@ -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) {

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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_ */

View File

@ -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.
*/

View File

@ -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,

View File

@ -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

View File

@ -1,4 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_HOSTAP) += hostap/
obj-$(CONFIG_HERMES) += orinoco/
obj-$(CONFIG_P54_COMMON) += p54/

View File

@ -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.

View File

@ -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

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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);

View File

@ -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,
};

View File

@ -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 */

View File

@ -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

View File

@ -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_ */

View File

@ -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,
};

View File

@ -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 */

View File

@ -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;
}

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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_ */

View File

@ -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;
}

View File

@ -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 */

View File

@ -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 */

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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 */

View File

@ -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);

View File

@ -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

View File

@ -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;
}
}

View File

@ -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_ */

View File

@ -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

View File

@ -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_ */

View File

@ -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.

View File

@ -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

View File

@ -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_ */

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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 */

View File

@ -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;

View File

@ -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)

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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 */

View File

@ -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(&reg, CCK_PROT_CFG_TX_OP_ALLOW_MM40, 0);
rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_GF20, 1);
rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_GF40, 0);
rt2x00_set_field32(&reg, CCK_PROT_CFG_RTS_TH_EN, 1);
rt2x00_set_field32(&reg, 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(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_MM40, 0);
rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_GF20, 1);
rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_GF40, 0);
rt2x00_set_field32(&reg, OFDM_PROT_CFG_RTS_TH_EN, 1);
rt2x00_set_field32(&reg, 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);

View File

@ -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
*/

View File

@ -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)

View File

@ -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;

View File

@ -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,

View File

@ -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 */

View File

@ -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