libertas: move under marvell vendor directory
authorKalle Valo <kvalo@codeaurora.org>
Tue, 17 Nov 2015 19:07:19 +0000 (21:07 +0200)
committerKalle Valo <kvalo@codeaurora.org>
Wed, 18 Nov 2015 12:28:30 +0000 (14:28 +0200)
Part of reorganising wireless drivers directory and Kconfig.

Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
67 files changed:
MAINTAINERS
drivers/net/wireless/Kconfig
drivers/net/wireless/Makefile
drivers/net/wireless/libertas/Kconfig [deleted file]
drivers/net/wireless/libertas/LICENSE [deleted file]
drivers/net/wireless/libertas/Makefile [deleted file]
drivers/net/wireless/libertas/README [deleted file]
drivers/net/wireless/libertas/cfg.c [deleted file]
drivers/net/wireless/libertas/cfg.h [deleted file]
drivers/net/wireless/libertas/cmd.c [deleted file]
drivers/net/wireless/libertas/cmd.h [deleted file]
drivers/net/wireless/libertas/cmdresp.c [deleted file]
drivers/net/wireless/libertas/debugfs.c [deleted file]
drivers/net/wireless/libertas/debugfs.h [deleted file]
drivers/net/wireless/libertas/decl.h [deleted file]
drivers/net/wireless/libertas/defs.h [deleted file]
drivers/net/wireless/libertas/dev.h [deleted file]
drivers/net/wireless/libertas/ethtool.c [deleted file]
drivers/net/wireless/libertas/firmware.c [deleted file]
drivers/net/wireless/libertas/host.h [deleted file]
drivers/net/wireless/libertas/if_cs.c [deleted file]
drivers/net/wireless/libertas/if_sdio.c [deleted file]
drivers/net/wireless/libertas/if_sdio.h [deleted file]
drivers/net/wireless/libertas/if_spi.c [deleted file]
drivers/net/wireless/libertas/if_spi.h [deleted file]
drivers/net/wireless/libertas/if_usb.c [deleted file]
drivers/net/wireless/libertas/if_usb.h [deleted file]
drivers/net/wireless/libertas/main.c [deleted file]
drivers/net/wireless/libertas/mesh.c [deleted file]
drivers/net/wireless/libertas/mesh.h [deleted file]
drivers/net/wireless/libertas/radiotap.h [deleted file]
drivers/net/wireless/libertas/rx.c [deleted file]
drivers/net/wireless/libertas/tx.c [deleted file]
drivers/net/wireless/libertas/types.h [deleted file]
drivers/net/wireless/marvell/Kconfig [new file with mode: 0644]
drivers/net/wireless/marvell/Makefile [new file with mode: 0644]
drivers/net/wireless/marvell/libertas/Kconfig [new file with mode: 0644]
drivers/net/wireless/marvell/libertas/LICENSE [new file with mode: 0644]
drivers/net/wireless/marvell/libertas/Makefile [new file with mode: 0644]
drivers/net/wireless/marvell/libertas/README [new file with mode: 0644]
drivers/net/wireless/marvell/libertas/cfg.c [new file with mode: 0644]
drivers/net/wireless/marvell/libertas/cfg.h [new file with mode: 0644]
drivers/net/wireless/marvell/libertas/cmd.c [new file with mode: 0644]
drivers/net/wireless/marvell/libertas/cmd.h [new file with mode: 0644]
drivers/net/wireless/marvell/libertas/cmdresp.c [new file with mode: 0644]
drivers/net/wireless/marvell/libertas/debugfs.c [new file with mode: 0644]
drivers/net/wireless/marvell/libertas/debugfs.h [new file with mode: 0644]
drivers/net/wireless/marvell/libertas/decl.h [new file with mode: 0644]
drivers/net/wireless/marvell/libertas/defs.h [new file with mode: 0644]
drivers/net/wireless/marvell/libertas/dev.h [new file with mode: 0644]
drivers/net/wireless/marvell/libertas/ethtool.c [new file with mode: 0644]
drivers/net/wireless/marvell/libertas/firmware.c [new file with mode: 0644]
drivers/net/wireless/marvell/libertas/host.h [new file with mode: 0644]
drivers/net/wireless/marvell/libertas/if_cs.c [new file with mode: 0644]
drivers/net/wireless/marvell/libertas/if_sdio.c [new file with mode: 0644]
drivers/net/wireless/marvell/libertas/if_sdio.h [new file with mode: 0644]
drivers/net/wireless/marvell/libertas/if_spi.c [new file with mode: 0644]
drivers/net/wireless/marvell/libertas/if_spi.h [new file with mode: 0644]
drivers/net/wireless/marvell/libertas/if_usb.c [new file with mode: 0644]
drivers/net/wireless/marvell/libertas/if_usb.h [new file with mode: 0644]
drivers/net/wireless/marvell/libertas/main.c [new file with mode: 0644]
drivers/net/wireless/marvell/libertas/mesh.c [new file with mode: 0644]
drivers/net/wireless/marvell/libertas/mesh.h [new file with mode: 0644]
drivers/net/wireless/marvell/libertas/radiotap.h [new file with mode: 0644]
drivers/net/wireless/marvell/libertas/rx.c [new file with mode: 0644]
drivers/net/wireless/marvell/libertas/tx.c [new file with mode: 0644]
drivers/net/wireless/marvell/libertas/types.h [new file with mode: 0644]

index d72be8c..75ff743 100644 (file)
@@ -6708,7 +6708,7 @@ F:        drivers/net/ethernet/marvell/sk*
 MARVELL LIBERTAS WIRELESS DRIVER
 L:     libertas-dev@lists.infradead.org
 S:     Orphan
 MARVELL LIBERTAS WIRELESS DRIVER
 L:     libertas-dev@lists.infradead.org
 S:     Orphan
-F:     drivers/net/wireless/libertas/
+F:     drivers/net/wireless/marvell/libertas/
 
 MARVELL MV643XX ETHERNET DRIVER
 M:     Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
 
 MARVELL MV643XX ETHERNET DRIVER
 M:     Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
index d71efe8..b11a2d3 100644 (file)
@@ -22,6 +22,7 @@ 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/broadcom/Kconfig"
 source "drivers/net/wireless/cisco/Kconfig"
 source "drivers/net/wireless/intel/Kconfig"
+source "drivers/net/wireless/marvell/Kconfig"
 source "drivers/net/wireless/st/Kconfig"
 
 config PCMCIA_RAYCS
 source "drivers/net/wireless/st/Kconfig"
 
 config PCMCIA_RAYCS
@@ -162,7 +163,6 @@ config MWL8K
 
 source "drivers/net/wireless/ath/Kconfig"
 source "drivers/net/wireless/hostap/Kconfig"
 
 source "drivers/net/wireless/ath/Kconfig"
 source "drivers/net/wireless/hostap/Kconfig"
-source "drivers/net/wireless/libertas/Kconfig"
 source "drivers/net/wireless/orinoco/Kconfig"
 source "drivers/net/wireless/p54/Kconfig"
 source "drivers/net/wireless/rt2x00/Kconfig"
 source "drivers/net/wireless/orinoco/Kconfig"
 source "drivers/net/wireless/p54/Kconfig"
 source "drivers/net/wireless/rt2x00/Kconfig"
index 6bcb292..a974a6e 100644 (file)
@@ -7,6 +7,7 @@ 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_BROADCOM) += broadcom/
 obj-$(CONFIG_WLAN_VENDOR_CISCO) += cisco/
 obj-$(CONFIG_WLAN_VENDOR_INTEL) += intel/
+obj-$(CONFIG_WLAN_VENDOR_MARVELL) += marvell/
 obj-$(CONFIG_WLAN_VENDOR_ST) += st/
 
 obj-$(CONFIG_HERMES)           += orinoco/
 obj-$(CONFIG_WLAN_VENDOR_ST) += st/
 
 obj-$(CONFIG_HERMES)           += orinoco/
@@ -24,7 +25,6 @@ obj-$(CONFIG_PCMCIA_WL3501)   += wl3501_cs.o
 obj-$(CONFIG_USB_NET_RNDIS_WLAN)       += rndis_wlan.o
 
 obj-$(CONFIG_USB_ZD1201)       += zd1201.o
 obj-$(CONFIG_USB_NET_RNDIS_WLAN)       += rndis_wlan.o
 
 obj-$(CONFIG_USB_ZD1201)       += zd1201.o
-obj-$(CONFIG_LIBERTAS)         += libertas/
 
 obj-$(CONFIG_LIBERTAS_THINFIRM)        += libertas_tf/
 
 
 obj-$(CONFIG_LIBERTAS_THINFIRM)        += libertas_tf/
 
diff --git a/drivers/net/wireless/libertas/Kconfig b/drivers/net/wireless/libertas/Kconfig
deleted file mode 100644 (file)
index e6268ce..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-config LIBERTAS
-       tristate "Marvell 8xxx Libertas WLAN driver support"
-       depends on CFG80211
-       select WIRELESS_EXT
-       select WEXT_SPY
-       select LIB80211
-       select FW_LOADER
-       ---help---
-         A library for Marvell Libertas 8xxx devices.
-
-config LIBERTAS_USB
-       tristate "Marvell Libertas 8388 USB 802.11b/g cards"
-       depends on 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
-       ---help---
-         A driver for Marvell Libertas 8385/8686/8688 SDIO devices.
-
-config LIBERTAS_SPI
-       tristate "Marvell Libertas 8686 SPI 802.11b/g cards"
-       depends on LIBERTAS && SPI
-       ---help---
-         A driver for Marvell Libertas 8686 SPI devices.
-
-config LIBERTAS_DEBUG
-       bool "Enable full debugging output in the Libertas module."
-       depends on LIBERTAS
-       ---help---
-         Debugging support.
-
-config LIBERTAS_MESH
-       bool "Enable mesh support"
-       depends on LIBERTAS
-       help
-         This enables Libertas' MESH support, used by e.g. the OLPC people.
diff --git a/drivers/net/wireless/libertas/LICENSE b/drivers/net/wireless/libertas/LICENSE
deleted file mode 100644 (file)
index 8862742..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-  Copyright (c) 2003-2006, Marvell International Ltd.
-  All Rights Reserved
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms of version 2 of the GNU General Public License as
-  published by the Free Software Foundation.
-
-  This program is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc., 59
-  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-
diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile
deleted file mode 100644 (file)
index eac72f7..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-libertas-y += cfg.o
-libertas-y += cmd.o
-libertas-y += cmdresp.o
-libertas-y += debugfs.o
-libertas-y += ethtool.o
-libertas-y += main.o
-libertas-y += rx.o
-libertas-y += tx.o
-libertas-y += firmware.o
-libertas-$(CONFIG_LIBERTAS_MESH) += mesh.o
-
-usb8xxx-objs += if_usb.o
-libertas_cs-objs += if_cs.o
-libertas_sdio-objs += if_sdio.o
-libertas_spi-objs += if_spi.o
-
-obj-$(CONFIG_LIBERTAS)     += libertas.o
-obj-$(CONFIG_LIBERTAS_USB) += usb8xxx.o
-obj-$(CONFIG_LIBERTAS_CS)  += libertas_cs.o
-obj-$(CONFIG_LIBERTAS_SDIO) += libertas_sdio.o
-obj-$(CONFIG_LIBERTAS_SPI) += libertas_spi.o
diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README
deleted file mode 100644 (file)
index 1a554a6..0000000
+++ /dev/null
@@ -1,239 +0,0 @@
-================================================================================
-                       README for Libertas
-
- (c) Copyright Â© 2003-2006, Marvell International Ltd.
- All Rights Reserved
-
- This software file (the "File") is distributed by Marvell International
- Ltd. under the terms of the GNU General Public License Version 2, June 1991
- (the "License").  You may use, redistribute and/or modify this File in
- accordance with the terms and conditions of the License, a copy of which
- is available along with the File in the license.txt file or on the worldwide
- web at http://www.gnu.org/licenses/gpl.txt.
-
- THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
- IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
- ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
- this warranty disclaimer.
-================================================================================
-
-=====================
-DRIVER LOADING
-=====================
-
-       o. Copy the firmware image (e.g. usb8388.bin) to /lib/firmware/
-
-       o. Load driver by using the following command:
-
-               insmod usb8388.ko [fw_name=usb8388.bin]
-
-=========================
-ETHTOOL
-=========================
-
-
-Use the -i option to retrieve version information from the driver.
-
-# ethtool -i eth0
-driver: libertas
-version: COMM-USB8388-318.p4
-firmware-version: 5.110.7
-bus-info:
-
-Use the -e option to read the EEPROM contents of the card.
-
-       Usage:
-       ethtool -e ethX [raw on|off] [offset N] [length N]
-
-       -e     retrieves and prints an EEPROM dump for the  specified  ethernet
-              device.   When raw is enabled, then it dumps the raw EEPROM data
-              to stdout. The length and offset parameters allow  dumping  cer-
-              tain portions of the EEPROM.  Default is to dump the entire EEP-
-              ROM.
-
-# ethtool -e eth0 offset 0 length 16
-Offset          Values
-------          ------
-0x0000          38 33 30 58 00 00 34 f4 00 00 10 00 00 c4 17 00
-
-========================
-DEBUGFS COMMANDS
-========================
-
-those commands are used via debugfs interface
-
-===========
-rdmac
-rdbbp
-rdrf
-       These commands are used to read the MAC, BBP and RF registers from the
-       card.  These commands take one parameter that specifies the offset
-       location that is to be read.  This parameter must be specified in
-       hexadecimal (its possible to precede preceding the number with a "0x").
-
-       Path: /sys/kernel/debug/libertas_wireless/ethX/registers/
-
-       Usage:
-               echo "0xa123" > rdmac ; cat rdmac
-               echo "0xa123" > rdbbp ; cat rdbbp
-               echo "0xa123" > rdrf ; cat rdrf
-wrmac
-wrbbp
-wrrf
-       These commands are used to write the MAC, BBP and RF registers in the
-       card.  These commands take two parameters that specify the offset
-       location and the value that is to be written. This parameters must
-       be specified in hexadecimal (its possible to precede the number
-       with a "0x").
-
-       Usage:
-               echo "0xa123 0xaa" > wrmac
-               echo "0xa123 0xaa" > wrbbp
-               echo "0xa123 0xaa" > wrrf
-
-sleepparams
-       This command is used to set the sleepclock configurations
-
-       Path: /sys/kernel/debug/libertas_wireless/ethX/
-
-       Usage:
-               cat sleepparams: reads the current sleepclock configuration
-
-               echo "p1 p2 p3 p4 p5 p6" > sleepparams: writes the sleepclock configuration.
-
-               where:
-                       p1 is Sleep clock error in ppm (0-65535)
-                       p2 is Wakeup offset in usec (0-65535)
-                       p3 is Clock stabilization time in usec (0-65535)
-                       p4 is Control periodic calibration (0-2)
-                       p5 is Control the use of external sleep clock (0-2)
-                       p6 is reserved for debug (0-65535)
-
-subscribed_events
-
-       The subscribed_events directory contains the interface for the
-       subscribed events API.
-
-       Path: /sys/kernel/debug/libertas_wireless/ethX/subscribed_events/
-
-       Each event is represented by a filename. Each filename consists of the
-       following three fields:
-       Value Frequency Subscribed
-
-       To read the current values for a given event, do:
-               cat event
-       To set the current values, do:
-               echo "60 2 1" > event
-
-       Frequency field specifies the reporting frequency for this event.
-       If it is set to 0, then the event is reported only once, and then
-       automatically unsubscribed. If it is set to 1, then the event is
-       reported every time it occurs. If it is set to N, then the event is
-       reported every Nth time it occurs.
-
-       beacon_missed
-       Value field specifies the number of consecutive missing beacons which
-       triggers the LINK_LOSS event. This event is generated only once after
-       which the firmware resets its state. At initialization, the LINK_LOSS
-       event is subscribed by default. The default value of MissedBeacons is
-       60.
-
-       failure_count
-       Value field specifies the consecutive failure count threshold which
-       triggers the generation of the MAX_FAIL event. Once this event is
-       generated, the consecutive failure count is reset to 0.
-       At initialization, the MAX_FAIL event is NOT subscribed by
-       default.
-
-       high_rssi
-       This event is generated when the average received RSSI in beacons goes
-       above a threshold, specified by Value.
-
-       low_rssi
-       This event is generated when the average received RSSI in beacons goes
-       below a threshold, specified by Value.
-
-       high_snr
-       This event is generated when the average received SNR in beacons goes
-       above a threshold, specified by Value.
-
-       low_snr
-       This event is generated when the average received SNR in beacons goes
-       below a threshold, specified by Value.
-
-extscan
-       This command is used to do a specific scan.
-
-       Path: /sys/kernel/debug/libertas_wireless/ethX/
-
-       Usage: echo "SSID" > extscan
-
-       Example:
-               echo "LINKSYS-AP" > extscan
-
-       To see the results of use getscantable command.
-
-getscantable
-
-       Display the current contents of the driver scan table (ie. get the
-       scan results).
-
-       Path: /sys/kernel/debug/libertas_wireless/ethX/
-
-       Usage:
-               cat getscantable
-
-setuserscan
-       Initiate a customized scan and retrieve the results
-
-
-       Path: /sys/kernel/debug/libertas_wireless/ethX/
-
-    Usage:
-       echo "[ARGS]" > setuserscan
-
-         where [ARGS]:
-
-      bssid=xx:xx:xx:xx:xx:xx  specify a BSSID filter for the scan
-      ssid="[SSID]"            specify a SSID filter for the scan
-      keep=[0 or 1]            keep the previous scan results (1), discard (0)
-      dur=[scan time]          time to scan for each channel in milliseconds
-      type=[1,2,3]             BSS type: 1 (Infra), 2(Adhoc), 3(Any)
-
-    Any combination of the above arguments can be supplied on the command
-    line. If dur tokens are absent, the driver default setting will be used.
-    The bssid and ssid fields, if blank, will produce an unfiltered scan.
-    The type field will default to 3 (Any) and the keep field will default
-    to 0 (Discard).
-
-    Examples:
-    1) Perform a passive scan on all channels for 20 ms per channel:
-            echo "dur=20" > setuserscan
-
-    2) Perform an active scan for a specific SSID:
-            echo "ssid="TestAP"" > setuserscan
-
-    3) Scan all available channels (B/G, A bands) for a specific BSSID, keep
-       the current scan table intact, update existing or append new scan data:
-            echo "bssid=00:50:43:20:12:82 keep=1" > setuserscan
-
-    4) Scan for all infrastructure networks.
-       Keep the previous scan table intact. Update any duplicate BSSID/SSID
-       matches with the new scan data:
-            echo "type=1 keep=1" > setuserscan
-
-    All entries in the scan table (not just the new scan data when keep=1)
-    will be displayed upon completion by use of the getscantable ioctl.
-
-hostsleep
-       This command is used to enable/disable host sleep.
-       Note: Host sleep parameters should be configured using
-       "ethtool -s ethX wol X" command before enabling host sleep.
-
-       Path: /sys/kernel/debug/libertas_wireless/ethX/
-
-       Usage:
-               cat hostsleep: reads the current hostsleep state
-               echo "1" > hostsleep : enable host sleep.
-               echo "0" > hostsleep : disable host sleep
-
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
deleted file mode 100644 (file)
index 8317afd..0000000
+++ /dev/null
@@ -1,2215 +0,0 @@
-/*
- * Implement cfg80211 ("iw") support.
- *
- * Copyright (C) 2009 M&N Solutions GmbH, 61191 Rosbach, Germany
- * Holger Schurig <hs4233@mail.mn-solutions.de>
- *
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/hardirq.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/slab.h>
-#include <linux/ieee80211.h>
-#include <net/cfg80211.h>
-#include <asm/unaligned.h>
-
-#include "decl.h"
-#include "cfg.h"
-#include "cmd.h"
-#include "mesh.h"
-
-
-#define CHAN2G(_channel, _freq, _flags) {        \
-       .band             = IEEE80211_BAND_2GHZ, \
-       .center_freq      = (_freq),             \
-       .hw_value         = (_channel),          \
-       .flags            = (_flags),            \
-       .max_antenna_gain = 0,                   \
-       .max_power        = 30,                  \
-}
-
-static struct ieee80211_channel lbs_2ghz_channels[] = {
-       CHAN2G(1,  2412, 0),
-       CHAN2G(2,  2417, 0),
-       CHAN2G(3,  2422, 0),
-       CHAN2G(4,  2427, 0),
-       CHAN2G(5,  2432, 0),
-       CHAN2G(6,  2437, 0),
-       CHAN2G(7,  2442, 0),
-       CHAN2G(8,  2447, 0),
-       CHAN2G(9,  2452, 0),
-       CHAN2G(10, 2457, 0),
-       CHAN2G(11, 2462, 0),
-       CHAN2G(12, 2467, 0),
-       CHAN2G(13, 2472, 0),
-       CHAN2G(14, 2484, 0),
-};
-
-#define RATETAB_ENT(_rate, _hw_value, _flags) { \
-       .bitrate  = (_rate),                    \
-       .hw_value = (_hw_value),                \
-       .flags    = (_flags),                   \
-}
-
-
-/* Table 6 in section 3.2.1.1 */
-static struct ieee80211_rate lbs_rates[] = {
-       RATETAB_ENT(10,  0,  0),
-       RATETAB_ENT(20,  1,  0),
-       RATETAB_ENT(55,  2,  0),
-       RATETAB_ENT(110, 3,  0),
-       RATETAB_ENT(60,  9,  0),
-       RATETAB_ENT(90,  6,  0),
-       RATETAB_ENT(120, 7,  0),
-       RATETAB_ENT(180, 8,  0),
-       RATETAB_ENT(240, 9,  0),
-       RATETAB_ENT(360, 10, 0),
-       RATETAB_ENT(480, 11, 0),
-       RATETAB_ENT(540, 12, 0),
-};
-
-static struct ieee80211_supported_band lbs_band_2ghz = {
-       .channels = lbs_2ghz_channels,
-       .n_channels = ARRAY_SIZE(lbs_2ghz_channels),
-       .bitrates = lbs_rates,
-       .n_bitrates = ARRAY_SIZE(lbs_rates),
-};
-
-
-static const u32 cipher_suites[] = {
-       WLAN_CIPHER_SUITE_WEP40,
-       WLAN_CIPHER_SUITE_WEP104,
-       WLAN_CIPHER_SUITE_TKIP,
-       WLAN_CIPHER_SUITE_CCMP,
-};
-
-/* Time to stay on the channel */
-#define LBS_DWELL_PASSIVE 100
-#define LBS_DWELL_ACTIVE  40
-
-
-/***************************************************************************
- * Misc utility functions
- *
- * TLVs are Marvell specific. They are very similar to IEs, they have the
- * same structure: type, length, data*. The only difference: for IEs, the
- * type and length are u8, but for TLVs they're __le16.
- */
-
-/*
- * Convert NL80211's auth_type to the one from Libertas, see chapter 5.9.1
- * in the firmware spec
- */
-static int lbs_auth_to_authtype(enum nl80211_auth_type auth_type)
-{
-       int ret = -ENOTSUPP;
-
-       switch (auth_type) {
-       case NL80211_AUTHTYPE_OPEN_SYSTEM:
-       case NL80211_AUTHTYPE_SHARED_KEY:
-               ret = auth_type;
-               break;
-       case NL80211_AUTHTYPE_AUTOMATIC:
-               ret = NL80211_AUTHTYPE_OPEN_SYSTEM;
-               break;
-       case NL80211_AUTHTYPE_NETWORK_EAP:
-               ret = 0x80;
-               break;
-       default:
-               /* silence compiler */
-               break;
-       }
-       return ret;
-}
-
-
-/*
- * Various firmware commands need the list of supported rates, but with
- * the hight-bit set for basic rates
- */
-static int lbs_add_rates(u8 *rates)
-{
-       size_t i;
-
-       for (i = 0; i < ARRAY_SIZE(lbs_rates); i++) {
-               u8 rate = lbs_rates[i].bitrate / 5;
-               if (rate == 0x02 || rate == 0x04 ||
-                   rate == 0x0b || rate == 0x16)
-                       rate |= 0x80;
-               rates[i] = rate;
-       }
-       return ARRAY_SIZE(lbs_rates);
-}
-
-
-/***************************************************************************
- * TLV utility functions
- *
- * TLVs are Marvell specific. They are very similar to IEs, they have the
- * same structure: type, length, data*. The only difference: for IEs, the
- * type and length are u8, but for TLVs they're __le16.
- */
-
-
-/*
- * Add ssid TLV
- */
-#define LBS_MAX_SSID_TLV_SIZE                  \
-       (sizeof(struct mrvl_ie_header)          \
-        + IEEE80211_MAX_SSID_LEN)
-
-static int lbs_add_ssid_tlv(u8 *tlv, const u8 *ssid, int ssid_len)
-{
-       struct mrvl_ie_ssid_param_set *ssid_tlv = (void *)tlv;
-
-       /*
-        * TLV-ID SSID  00 00
-        * length       06 00
-        * ssid         4d 4e 54 45 53 54
-        */
-       ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID);
-       ssid_tlv->header.len = cpu_to_le16(ssid_len);
-       memcpy(ssid_tlv->ssid, ssid, ssid_len);
-       return sizeof(ssid_tlv->header) + ssid_len;
-}
-
-
-/*
- * Add channel list TLV (section 8.4.2)
- *
- * Actual channel data comes from priv->wdev->wiphy->channels.
- */
-#define LBS_MAX_CHANNEL_LIST_TLV_SIZE                                  \
-       (sizeof(struct mrvl_ie_header)                                  \
-        + (LBS_SCAN_BEFORE_NAP * sizeof(struct chanscanparamset)))
-
-static int lbs_add_channel_list_tlv(struct lbs_private *priv, u8 *tlv,
-                                   int last_channel, int active_scan)
-{
-       int chanscanparamsize = sizeof(struct chanscanparamset) *
-               (last_channel - priv->scan_channel);
-
-       struct mrvl_ie_header *header = (void *) tlv;
-
-       /*
-        * TLV-ID CHANLIST  01 01
-        * length           0e 00
-        * channel          00 01 00 00 00 64 00
-        *   radio type     00
-        *   channel           01
-        *   scan type            00
-        *   min scan time           00 00
-        *   max scan time                 64 00
-        * channel 2        00 02 00 00 00 64 00
-        *
-        */
-
-       header->type = cpu_to_le16(TLV_TYPE_CHANLIST);
-       header->len  = cpu_to_le16(chanscanparamsize);
-       tlv += sizeof(struct mrvl_ie_header);
-
-       /* lbs_deb_scan("scan: channels %d to %d\n", priv->scan_channel,
-                    last_channel); */
-       memset(tlv, 0, chanscanparamsize);
-
-       while (priv->scan_channel < last_channel) {
-               struct chanscanparamset *param = (void *) tlv;
-
-               param->radiotype = CMD_SCAN_RADIO_TYPE_BG;
-               param->channumber =
-                       priv->scan_req->channels[priv->scan_channel]->hw_value;
-               if (active_scan) {
-                       param->maxscantime = cpu_to_le16(LBS_DWELL_ACTIVE);
-               } else {
-                       param->chanscanmode.passivescan = 1;
-                       param->maxscantime = cpu_to_le16(LBS_DWELL_PASSIVE);
-               }
-               tlv += sizeof(struct chanscanparamset);
-               priv->scan_channel++;
-       }
-       return sizeof(struct mrvl_ie_header) + chanscanparamsize;
-}
-
-
-/*
- * Add rates TLV
- *
- * The rates are in lbs_bg_rates[], but for the 802.11b
- * rates the high bit is set. We add this TLV only because
- * there's a firmware which otherwise doesn't report all
- * APs in range.
- */
-#define LBS_MAX_RATES_TLV_SIZE                 \
-       (sizeof(struct mrvl_ie_header)          \
-        + (ARRAY_SIZE(lbs_rates)))
-
-/* Adds a TLV with all rates the hardware supports */
-static int lbs_add_supported_rates_tlv(u8 *tlv)
-{
-       size_t i;
-       struct mrvl_ie_rates_param_set *rate_tlv = (void *)tlv;
-
-       /*
-        * TLV-ID RATES  01 00
-        * length        0e 00
-        * rates         82 84 8b 96 0c 12 18 24 30 48 60 6c
-        */
-       rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES);
-       tlv += sizeof(rate_tlv->header);
-       i = lbs_add_rates(tlv);
-       tlv += i;
-       rate_tlv->header.len = cpu_to_le16(i);
-       return sizeof(rate_tlv->header) + i;
-}
-
-/* Add common rates from a TLV and return the new end of the TLV */
-static u8 *
-add_ie_rates(u8 *tlv, const u8 *ie, int *nrates)
-{
-       int hw, ap, ap_max = ie[1];
-       u8 hw_rate;
-
-       /* Advance past IE header */
-       ie += 2;
-
-       lbs_deb_hex(LBS_DEB_ASSOC, "AP IE Rates", (u8 *) ie, ap_max);
-
-       for (hw = 0; hw < ARRAY_SIZE(lbs_rates); hw++) {
-               hw_rate = lbs_rates[hw].bitrate / 5;
-               for (ap = 0; ap < ap_max; ap++) {
-                       if (hw_rate == (ie[ap] & 0x7f)) {
-                               *tlv++ = ie[ap];
-                               *nrates = *nrates + 1;
-                       }
-               }
-       }
-       return tlv;
-}
-
-/*
- * Adds a TLV with all rates the hardware *and* BSS supports.
- */
-static int lbs_add_common_rates_tlv(u8 *tlv, struct cfg80211_bss *bss)
-{
-       struct mrvl_ie_rates_param_set *rate_tlv = (void *)tlv;
-       const u8 *rates_eid, *ext_rates_eid;
-       int n = 0;
-
-       rcu_read_lock();
-       rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
-       ext_rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
-
-       /*
-        * 01 00                   TLV_TYPE_RATES
-        * 04 00                   len
-        * 82 84 8b 96             rates
-        */
-       rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES);
-       tlv += sizeof(rate_tlv->header);
-
-       /* Add basic rates */
-       if (rates_eid) {
-               tlv = add_ie_rates(tlv, rates_eid, &n);
-
-               /* Add extended rates, if any */
-               if (ext_rates_eid)
-                       tlv = add_ie_rates(tlv, ext_rates_eid, &n);
-       } else {
-               lbs_deb_assoc("assoc: bss had no basic rate IE\n");
-               /* Fallback: add basic 802.11b rates */
-               *tlv++ = 0x82;
-               *tlv++ = 0x84;
-               *tlv++ = 0x8b;
-               *tlv++ = 0x96;
-               n = 4;
-       }
-       rcu_read_unlock();
-
-       rate_tlv->header.len = cpu_to_le16(n);
-       return sizeof(rate_tlv->header) + n;
-}
-
-
-/*
- * Add auth type TLV.
- *
- * This is only needed for newer firmware (V9 and up).
- */
-#define LBS_MAX_AUTH_TYPE_TLV_SIZE \
-       sizeof(struct mrvl_ie_auth_type)
-
-static int lbs_add_auth_type_tlv(u8 *tlv, enum nl80211_auth_type auth_type)
-{
-       struct mrvl_ie_auth_type *auth = (void *) tlv;
-
-       /*
-        * 1f 01  TLV_TYPE_AUTH_TYPE
-        * 01 00  len
-        * 01     auth type
-        */
-       auth->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
-       auth->header.len = cpu_to_le16(sizeof(*auth)-sizeof(auth->header));
-       auth->auth = cpu_to_le16(lbs_auth_to_authtype(auth_type));
-       return sizeof(*auth);
-}
-
-
-/*
- * Add channel (phy ds) TLV
- */
-#define LBS_MAX_CHANNEL_TLV_SIZE \
-       sizeof(struct mrvl_ie_header)
-
-static int lbs_add_channel_tlv(u8 *tlv, u8 channel)
-{
-       struct mrvl_ie_ds_param_set *ds = (void *) tlv;
-
-       /*
-        * 03 00  TLV_TYPE_PHY_DS
-        * 01 00  len
-        * 06     channel
-        */
-       ds->header.type = cpu_to_le16(TLV_TYPE_PHY_DS);
-       ds->header.len = cpu_to_le16(sizeof(*ds)-sizeof(ds->header));
-       ds->channel = channel;
-       return sizeof(*ds);
-}
-
-
-/*
- * Add (empty) CF param TLV of the form:
- */
-#define LBS_MAX_CF_PARAM_TLV_SIZE              \
-       sizeof(struct mrvl_ie_header)
-
-static int lbs_add_cf_param_tlv(u8 *tlv)
-{
-       struct mrvl_ie_cf_param_set *cf = (void *)tlv;
-
-       /*
-        * 04 00  TLV_TYPE_CF
-        * 06 00  len
-        * 00     cfpcnt
-        * 00     cfpperiod
-        * 00 00  cfpmaxduration
-        * 00 00  cfpdurationremaining
-        */
-       cf->header.type = cpu_to_le16(TLV_TYPE_CF);
-       cf->header.len = cpu_to_le16(sizeof(*cf)-sizeof(cf->header));
-       return sizeof(*cf);
-}
-
-/*
- * Add WPA TLV
- */
-#define LBS_MAX_WPA_TLV_SIZE                   \
-       (sizeof(struct mrvl_ie_header)          \
-        + 128 /* TODO: I guessed the size */)
-
-static int lbs_add_wpa_tlv(u8 *tlv, const u8 *ie, u8 ie_len)
-{
-       size_t tlv_len;
-
-       /*
-        * We need just convert an IE to an TLV. IEs use u8 for the header,
-        *   u8      type
-        *   u8      len
-        *   u8[]    data
-        * but TLVs use __le16 instead:
-        *   __le16  type
-        *   __le16  len
-        *   u8[]    data
-        */
-       *tlv++ = *ie++;
-       *tlv++ = 0;
-       tlv_len = *tlv++ = *ie++;
-       *tlv++ = 0;
-       while (tlv_len--)
-               *tlv++ = *ie++;
-       /* the TLV is two bytes larger than the IE */
-       return ie_len + 2;
-}
-
-/*
- * Set Channel
- */
-
-static int lbs_cfg_set_monitor_channel(struct wiphy *wiphy,
-                                      struct cfg80211_chan_def *chandef)
-{
-       struct lbs_private *priv = wiphy_priv(wiphy);
-       int ret = -ENOTSUPP;
-
-       lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d",
-                          chandef->chan->center_freq,
-                          cfg80211_get_chandef_type(chandef));
-
-       if (cfg80211_get_chandef_type(chandef) != NL80211_CHAN_NO_HT)
-               goto out;
-
-       ret = lbs_set_channel(priv, chandef->chan->hw_value);
-
- out:
-       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
-       return ret;
-}
-
-static int lbs_cfg_set_mesh_channel(struct wiphy *wiphy,
-                                   struct net_device *netdev,
-                                   struct ieee80211_channel *channel)
-{
-       struct lbs_private *priv = wiphy_priv(wiphy);
-       int ret = -ENOTSUPP;
-
-       lbs_deb_enter_args(LBS_DEB_CFG80211, "iface %s freq %d",
-                          netdev_name(netdev), channel->center_freq);
-
-       if (netdev != priv->mesh_dev)
-               goto out;
-
-       ret = lbs_mesh_set_channel(priv, channel->hw_value);
-
- out:
-       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
-       return ret;
-}
-
-
-
-/*
- * Scanning
- */
-
-/*
- * When scanning, the firmware doesn't send a nul packet with the power-safe
- * bit to the AP. So we cannot stay away from our current channel too long,
- * otherwise we loose data. So take a "nap" while scanning every other
- * while.
- */
-#define LBS_SCAN_BEFORE_NAP 4
-
-
-/*
- * When the firmware reports back a scan-result, it gives us an "u8 rssi",
- * which isn't really an RSSI, as it becomes larger when moving away from
- * the AP. Anyway, we need to convert that into mBm.
- */
-#define LBS_SCAN_RSSI_TO_MBM(rssi) \
-       ((-(int)rssi + 3)*100)
-
-static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
-       struct cmd_header *resp)
-{
-       struct cfg80211_bss *bss;
-       struct cmd_ds_802_11_scan_rsp *scanresp = (void *)resp;
-       int bsssize;
-       const u8 *pos;
-       const u8 *tsfdesc;
-       int tsfsize;
-       int i;
-       int ret = -EILSEQ;
-
-       lbs_deb_enter(LBS_DEB_CFG80211);
-
-       bsssize = get_unaligned_le16(&scanresp->bssdescriptsize);
-
-       lbs_deb_scan("scan response: %d BSSs (%d bytes); resp size %d bytes\n",
-                       scanresp->nr_sets, bsssize, le16_to_cpu(resp->size));
-
-       if (scanresp->nr_sets == 0) {
-               ret = 0;
-               goto done;
-       }
-
-       /*
-        * The general layout of the scan response is described in chapter
-        * 5.7.1. Basically we have a common part, then any number of BSS
-        * descriptor sections. Finally we have section with the same number
-        * of TSFs.
-        *
-        * cmd_ds_802_11_scan_rsp
-        *   cmd_header
-        *   pos_size
-        *   nr_sets
-        *   bssdesc 1
-        *     bssid
-        *     rssi
-        *     timestamp
-        *     intvl
-        *     capa
-        *     IEs
-        *   bssdesc 2
-        *   bssdesc n
-        *   MrvlIEtypes_TsfFimestamp_t
-        *     TSF for BSS 1
-        *     TSF for BSS 2
-        *     TSF for BSS n
-        */
-
-       pos = scanresp->bssdesc_and_tlvbuffer;
-
-       lbs_deb_hex(LBS_DEB_SCAN, "SCAN_RSP", scanresp->bssdesc_and_tlvbuffer,
-                       scanresp->bssdescriptsize);
-
-       tsfdesc = pos + bsssize;
-       tsfsize = 4 + 8 * scanresp->nr_sets;
-       lbs_deb_hex(LBS_DEB_SCAN, "SCAN_TSF", (u8 *) tsfdesc, tsfsize);
-
-       /* Validity check: we expect a Marvell-Local TLV */
-       i = get_unaligned_le16(tsfdesc);
-       tsfdesc += 2;
-       if (i != TLV_TYPE_TSFTIMESTAMP) {
-               lbs_deb_scan("scan response: invalid TSF Timestamp %d\n", i);
-               goto done;
-       }
-
-       /*
-        * Validity check: the TLV holds TSF values with 8 bytes each, so
-        * the size in the TLV must match the nr_sets value
-        */
-       i = get_unaligned_le16(tsfdesc);
-       tsfdesc += 2;
-       if (i / 8 != scanresp->nr_sets) {
-               lbs_deb_scan("scan response: invalid number of TSF timestamp "
-                            "sets (expected %d got %d)\n", scanresp->nr_sets,
-                            i / 8);
-               goto done;
-       }
-
-       for (i = 0; i < scanresp->nr_sets; i++) {
-               const u8 *bssid;
-               const u8 *ie;
-               int left;
-               int ielen;
-               int rssi;
-               u16 intvl;
-               u16 capa;
-               int chan_no = -1;
-               const u8 *ssid = NULL;
-               u8 ssid_len = 0;
-
-               int len = get_unaligned_le16(pos);
-               pos += 2;
-
-               /* BSSID */
-               bssid = pos;
-               pos += ETH_ALEN;
-               /* RSSI */
-               rssi = *pos++;
-               /* Packet time stamp */
-               pos += 8;
-               /* Beacon interval */
-               intvl = get_unaligned_le16(pos);
-               pos += 2;
-               /* Capabilities */
-               capa = get_unaligned_le16(pos);
-               pos += 2;
-
-               /* To find out the channel, we must parse the IEs */
-               ie = pos;
-               /*
-                * 6+1+8+2+2: size of BSSID, RSSI, time stamp, beacon
-                * interval, capabilities
-                */
-               ielen = left = len - (6 + 1 + 8 + 2 + 2);
-               while (left >= 2) {
-                       u8 id, elen;
-                       id = *pos++;
-                       elen = *pos++;
-                       left -= 2;
-                       if (elen > left) {
-                               lbs_deb_scan("scan response: invalid IE fmt\n");
-                               goto done;
-                       }
-
-                       if (id == WLAN_EID_DS_PARAMS)
-                               chan_no = *pos;
-                       if (id == WLAN_EID_SSID) {
-                               ssid = pos;
-                               ssid_len = elen;
-                       }
-                       left -= elen;
-                       pos += elen;
-               }
-
-               /* No channel, no luck */
-               if (chan_no != -1) {
-                       struct wiphy *wiphy = priv->wdev->wiphy;
-                       int freq = ieee80211_channel_to_frequency(chan_no,
-                                                       IEEE80211_BAND_2GHZ);
-                       struct ieee80211_channel *channel =
-                               ieee80211_get_channel(wiphy, freq);
-
-                       lbs_deb_scan("scan: %pM, capa %04x, chan %2d, %*pE, %d dBm\n",
-                                    bssid, capa, chan_no, ssid_len, ssid,
-                                    LBS_SCAN_RSSI_TO_MBM(rssi)/100);
-
-                       if (channel &&
-                           !(channel->flags & IEEE80211_CHAN_DISABLED)) {
-                               bss = cfg80211_inform_bss(wiphy, channel,
-                                       CFG80211_BSS_FTYPE_UNKNOWN,
-                                       bssid, get_unaligned_le64(tsfdesc),
-                                       capa, intvl, ie, ielen,
-                                       LBS_SCAN_RSSI_TO_MBM(rssi),
-                                       GFP_KERNEL);
-                               cfg80211_put_bss(wiphy, bss);
-                       }
-               } else
-                       lbs_deb_scan("scan response: missing BSS channel IE\n");
-
-               tsfdesc += 8;
-       }
-       ret = 0;
-
- done:
-       lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
-       return ret;
-}
-
-
-/*
- * Our scan command contains a TLV, consting of a SSID TLV, a channel list
- * TLV and a rates TLV. Determine the maximum size of them:
- */
-#define LBS_SCAN_MAX_CMD_SIZE                  \
-       (sizeof(struct cmd_ds_802_11_scan)      \
-        + LBS_MAX_SSID_TLV_SIZE                \
-        + LBS_MAX_CHANNEL_LIST_TLV_SIZE        \
-        + LBS_MAX_RATES_TLV_SIZE)
-
-/*
- * Assumes priv->scan_req is initialized and valid
- * Assumes priv->scan_channel is initialized
- */
-static void lbs_scan_worker(struct work_struct *work)
-{
-       struct lbs_private *priv =
-               container_of(work, struct lbs_private, scan_work.work);
-       struct cmd_ds_802_11_scan *scan_cmd;
-       u8 *tlv; /* pointer into our current, growing TLV storage area */
-       int last_channel;
-       int running, carrier;
-
-       lbs_deb_enter(LBS_DEB_SCAN);
-
-       scan_cmd = kzalloc(LBS_SCAN_MAX_CMD_SIZE, GFP_KERNEL);
-       if (scan_cmd == NULL)
-               goto out_no_scan_cmd;
-
-       /* prepare fixed part of scan command */
-       scan_cmd->bsstype = CMD_BSS_TYPE_ANY;
-
-       /* stop network while we're away from our main channel */
-       running = !netif_queue_stopped(priv->dev);
-       carrier = netif_carrier_ok(priv->dev);
-       if (running)
-               netif_stop_queue(priv->dev);
-       if (carrier)
-               netif_carrier_off(priv->dev);
-
-       /* prepare fixed part of scan command */
-       tlv = scan_cmd->tlvbuffer;
-
-       /* add SSID TLV */
-       if (priv->scan_req->n_ssids && priv->scan_req->ssids[0].ssid_len > 0)
-               tlv += lbs_add_ssid_tlv(tlv,
-                                       priv->scan_req->ssids[0].ssid,
-                                       priv->scan_req->ssids[0].ssid_len);
-
-       /* add channel TLVs */
-       last_channel = priv->scan_channel + LBS_SCAN_BEFORE_NAP;
-       if (last_channel > priv->scan_req->n_channels)
-               last_channel = priv->scan_req->n_channels;
-       tlv += lbs_add_channel_list_tlv(priv, tlv, last_channel,
-               priv->scan_req->n_ssids);
-
-       /* add rates TLV */
-       tlv += lbs_add_supported_rates_tlv(tlv);
-
-       if (priv->scan_channel < priv->scan_req->n_channels) {
-               cancel_delayed_work(&priv->scan_work);
-               if (netif_running(priv->dev))
-                       queue_delayed_work(priv->work_thread, &priv->scan_work,
-                               msecs_to_jiffies(300));
-       }
-
-       /* This is the final data we are about to send */
-       scan_cmd->hdr.size = cpu_to_le16(tlv - (u8 *)scan_cmd);
-       lbs_deb_hex(LBS_DEB_SCAN, "SCAN_CMD", (void *)scan_cmd,
-                   sizeof(*scan_cmd));
-       lbs_deb_hex(LBS_DEB_SCAN, "SCAN_TLV", scan_cmd->tlvbuffer,
-                   tlv - scan_cmd->tlvbuffer);
-
-       __lbs_cmd(priv, CMD_802_11_SCAN, &scan_cmd->hdr,
-               le16_to_cpu(scan_cmd->hdr.size),
-               lbs_ret_scan, 0);
-
-       if (priv->scan_channel >= priv->scan_req->n_channels) {
-               /* Mark scan done */
-               cancel_delayed_work(&priv->scan_work);
-               lbs_scan_done(priv);
-       }
-
-       /* Restart network */
-       if (carrier)
-               netif_carrier_on(priv->dev);
-       if (running && !priv->tx_pending_len)
-               netif_wake_queue(priv->dev);
-
-       kfree(scan_cmd);
-
-       /* Wake up anything waiting on scan completion */
-       if (priv->scan_req == NULL) {
-               lbs_deb_scan("scan: waking up waiters\n");
-               wake_up_all(&priv->scan_q);
-       }
-
- out_no_scan_cmd:
-       lbs_deb_leave(LBS_DEB_SCAN);
-}
-
-static void _internal_start_scan(struct lbs_private *priv, bool internal,
-       struct cfg80211_scan_request *request)
-{
-       lbs_deb_enter(LBS_DEB_CFG80211);
-
-       lbs_deb_scan("scan: ssids %d, channels %d, ie_len %zd\n",
-               request->n_ssids, request->n_channels, request->ie_len);
-
-       priv->scan_channel = 0;
-       priv->scan_req = request;
-       priv->internal_scan = internal;
-
-       queue_delayed_work(priv->work_thread, &priv->scan_work,
-               msecs_to_jiffies(50));
-
-       lbs_deb_leave(LBS_DEB_CFG80211);
-}
-
-/*
- * Clean up priv->scan_req.  Should be used to handle the allocation details.
- */
-void lbs_scan_done(struct lbs_private *priv)
-{
-       WARN_ON(!priv->scan_req);
-
-       if (priv->internal_scan)
-               kfree(priv->scan_req);
-       else
-               cfg80211_scan_done(priv->scan_req, false);
-
-       priv->scan_req = NULL;
-}
-
-static int lbs_cfg_scan(struct wiphy *wiphy,
-       struct cfg80211_scan_request *request)
-{
-       struct lbs_private *priv = wiphy_priv(wiphy);
-       int ret = 0;
-
-       lbs_deb_enter(LBS_DEB_CFG80211);
-
-       if (priv->scan_req || delayed_work_pending(&priv->scan_work)) {
-               /* old scan request not yet processed */
-               ret = -EAGAIN;
-               goto out;
-       }
-
-       _internal_start_scan(priv, false, request);
-
-       if (priv->surpriseremoved)
-               ret = -EIO;
-
- out:
-       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
-       return ret;
-}
-
-
-
-
-/*
- * Events
- */
-
-void lbs_send_disconnect_notification(struct lbs_private *priv,
-                                     bool locally_generated)
-{
-       lbs_deb_enter(LBS_DEB_CFG80211);
-
-       cfg80211_disconnected(priv->dev, 0, NULL, 0, locally_generated,
-                             GFP_KERNEL);
-
-       lbs_deb_leave(LBS_DEB_CFG80211);
-}
-
-void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event)
-{
-       lbs_deb_enter(LBS_DEB_CFG80211);
-
-       cfg80211_michael_mic_failure(priv->dev,
-               priv->assoc_bss,
-               event == MACREG_INT_CODE_MIC_ERR_MULTICAST ?
-                       NL80211_KEYTYPE_GROUP :
-                       NL80211_KEYTYPE_PAIRWISE,
-               -1,
-               NULL,
-               GFP_KERNEL);
-
-       lbs_deb_leave(LBS_DEB_CFG80211);
-}
-
-
-
-
-/*
- * Connect/disconnect
- */
-
-
-/*
- * This removes all WEP keys
- */
-static int lbs_remove_wep_keys(struct lbs_private *priv)
-{
-       struct cmd_ds_802_11_set_wep cmd;
-       int ret;
-
-       lbs_deb_enter(LBS_DEB_CFG80211);
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-       cmd.keyindex = cpu_to_le16(priv->wep_tx_key);
-       cmd.action = cpu_to_le16(CMD_ACT_REMOVE);
-
-       ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd);
-
-       lbs_deb_leave(LBS_DEB_CFG80211);
-       return ret;
-}
-
-/*
- * Set WEP keys
- */
-static int lbs_set_wep_keys(struct lbs_private *priv)
-{
-       struct cmd_ds_802_11_set_wep cmd;
-       int i;
-       int ret;
-
-       lbs_deb_enter(LBS_DEB_CFG80211);
-
-       /*
-        * command         13 00
-        * size            50 00
-        * sequence        xx xx
-        * result          00 00
-        * action          02 00     ACT_ADD
-        * transmit key    00 00
-        * type for key 1  01        WEP40
-        * type for key 2  00
-        * type for key 3  00
-        * type for key 4  00
-        * key 1           39 39 39 39 39 00 00 00
-        *                 00 00 00 00 00 00 00 00
-        * key 2           00 00 00 00 00 00 00 00
-        *                 00 00 00 00 00 00 00 00
-        * key 3           00 00 00 00 00 00 00 00
-        *                 00 00 00 00 00 00 00 00
-        * key 4           00 00 00 00 00 00 00 00
-        */
-       if (priv->wep_key_len[0] || priv->wep_key_len[1] ||
-           priv->wep_key_len[2] || priv->wep_key_len[3]) {
-               /* Only set wep keys if we have at least one of them */
-               memset(&cmd, 0, sizeof(cmd));
-               cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-               cmd.keyindex = cpu_to_le16(priv->wep_tx_key);
-               cmd.action = cpu_to_le16(CMD_ACT_ADD);
-
-               for (i = 0; i < 4; i++) {
-                       switch (priv->wep_key_len[i]) {
-                       case WLAN_KEY_LEN_WEP40:
-                               cmd.keytype[i] = CMD_TYPE_WEP_40_BIT;
-                               break;
-                       case WLAN_KEY_LEN_WEP104:
-                               cmd.keytype[i] = CMD_TYPE_WEP_104_BIT;
-                               break;
-                       default:
-                               cmd.keytype[i] = 0;
-                               break;
-                       }
-                       memcpy(cmd.keymaterial[i], priv->wep_key[i],
-                              priv->wep_key_len[i]);
-               }
-
-               ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd);
-       } else {
-               /* Otherwise remove all wep keys */
-               ret = lbs_remove_wep_keys(priv);
-       }
-
-       lbs_deb_leave(LBS_DEB_CFG80211);
-       return ret;
-}
-
-
-/*
- * Enable/Disable RSN status
- */
-static int lbs_enable_rsn(struct lbs_private *priv, int enable)
-{
-       struct cmd_ds_802_11_enable_rsn cmd;
-       int ret;
-
-       lbs_deb_enter_args(LBS_DEB_CFG80211, "%d", enable);
-
-       /*
-        * cmd       2f 00
-        * size      0c 00
-        * sequence  xx xx
-        * result    00 00
-        * action    01 00    ACT_SET
-        * enable    01 00
-        */
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-       cmd.action = cpu_to_le16(CMD_ACT_SET);
-       cmd.enable = cpu_to_le16(enable);
-
-       ret = lbs_cmd_with_response(priv, CMD_802_11_ENABLE_RSN, &cmd);
-
-       lbs_deb_leave(LBS_DEB_CFG80211);
-       return ret;
-}
-
-
-/*
- * Set WPA/WPA key material
- */
-
-/*
- * like "struct cmd_ds_802_11_key_material", but with cmd_header. Once we
- * get rid of WEXT, this should go into host.h
- */
-
-struct cmd_key_material {
-       struct cmd_header hdr;
-
-       __le16 action;
-       struct MrvlIEtype_keyParamSet param;
-} __packed;
-
-static int lbs_set_key_material(struct lbs_private *priv,
-                               int key_type, int key_info,
-                               const u8 *key, u16 key_len)
-{
-       struct cmd_key_material cmd;
-       int ret;
-
-       lbs_deb_enter(LBS_DEB_CFG80211);
-
-       /*
-        * Example for WPA (TKIP):
-        *
-        * cmd       5e 00
-        * size      34 00
-        * sequence  xx xx
-        * result    00 00
-        * action    01 00
-        * TLV type  00 01    key param
-        * length    00 26
-        * key type  01 00    TKIP
-        * key info  06 00    UNICAST | ENABLED
-        * key len   20 00
-        * key       32 bytes
-        */
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-       cmd.action = cpu_to_le16(CMD_ACT_SET);
-       cmd.param.type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
-       cmd.param.length = cpu_to_le16(sizeof(cmd.param) - 4);
-       cmd.param.keytypeid = cpu_to_le16(key_type);
-       cmd.param.keyinfo = cpu_to_le16(key_info);
-       cmd.param.keylen = cpu_to_le16(key_len);
-       if (key && key_len)
-               memcpy(cmd.param.key, key, key_len);
-
-       ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd);
-
-       lbs_deb_leave(LBS_DEB_CFG80211);
-       return ret;
-}
-
-
-/*
- * Sets the auth type (open, shared, etc) in the firmware. That
- * we use CMD_802_11_AUTHENTICATE is misleading, this firmware
- * command doesn't send an authentication frame at all, it just
- * stores the auth_type.
- */
-static int lbs_set_authtype(struct lbs_private *priv,
-                           struct cfg80211_connect_params *sme)
-{
-       struct cmd_ds_802_11_authenticate cmd;
-       int ret;
-
-       lbs_deb_enter_args(LBS_DEB_CFG80211, "%d", sme->auth_type);
-
-       /*
-        * cmd        11 00
-        * size       19 00
-        * sequence   xx xx
-        * result     00 00
-        * BSS id     00 13 19 80 da 30
-        * auth type  00
-        * reserved   00 00 00 00 00 00 00 00 00 00
-        */
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-       if (sme->bssid)
-               memcpy(cmd.bssid, sme->bssid, ETH_ALEN);
-       /* convert auth_type */
-       ret = lbs_auth_to_authtype(sme->auth_type);
-       if (ret < 0)
-               goto done;
-
-       cmd.authtype = ret;
-       ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd);
-
- done:
-       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
-       return ret;
-}
-
-
-/*
- * Create association request
- */
-#define LBS_ASSOC_MAX_CMD_SIZE                     \
-       (sizeof(struct cmd_ds_802_11_associate)    \
-        - 512 /* cmd_ds_802_11_associate.iebuf */ \
-        + LBS_MAX_SSID_TLV_SIZE                   \
-        + LBS_MAX_CHANNEL_TLV_SIZE                \
-        + LBS_MAX_CF_PARAM_TLV_SIZE               \
-        + LBS_MAX_AUTH_TYPE_TLV_SIZE              \
-        + LBS_MAX_WPA_TLV_SIZE)
-
-static int lbs_associate(struct lbs_private *priv,
-               struct cfg80211_bss *bss,
-               struct cfg80211_connect_params *sme)
-{
-       struct cmd_ds_802_11_associate_response *resp;
-       struct cmd_ds_802_11_associate *cmd = kzalloc(LBS_ASSOC_MAX_CMD_SIZE,
-                                                     GFP_KERNEL);
-       const u8 *ssid_eid;
-       size_t len, resp_ie_len;
-       int status;
-       int ret;
-       u8 *pos = &(cmd->iebuf[0]);
-       u8 *tmp;
-
-       lbs_deb_enter(LBS_DEB_CFG80211);
-
-       if (!cmd) {
-               ret = -ENOMEM;
-               goto done;
-       }
-
-       /*
-        * cmd              50 00
-        * length           34 00
-        * sequence         xx xx
-        * result           00 00
-        * BSS id           00 13 19 80 da 30
-        * capabilities     11 00
-        * listen interval  0a 00
-        * beacon interval  00 00
-        * DTIM period      00
-        * TLVs             xx   (up to 512 bytes)
-        */
-       cmd->hdr.command = cpu_to_le16(CMD_802_11_ASSOCIATE);
-
-       /* Fill in static fields */
-       memcpy(cmd->bssid, bss->bssid, ETH_ALEN);
-       cmd->listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL);
-       cmd->capability = cpu_to_le16(bss->capability);
-
-       /* add SSID TLV */
-       rcu_read_lock();
-       ssid_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SSID);
-       if (ssid_eid)
-               pos += lbs_add_ssid_tlv(pos, ssid_eid + 2, ssid_eid[1]);
-       else
-               lbs_deb_assoc("no SSID\n");
-       rcu_read_unlock();
-
-       /* add DS param TLV */
-       if (bss->channel)
-               pos += lbs_add_channel_tlv(pos, bss->channel->hw_value);
-       else
-               lbs_deb_assoc("no channel\n");
-
-       /* add (empty) CF param TLV */
-       pos += lbs_add_cf_param_tlv(pos);
-
-       /* add rates TLV */
-       tmp = pos + 4; /* skip Marvell IE header */
-       pos += lbs_add_common_rates_tlv(pos, bss);
-       lbs_deb_hex(LBS_DEB_ASSOC, "Common Rates", tmp, pos - tmp);
-
-       /* add auth type TLV */
-       if (MRVL_FW_MAJOR_REV(priv->fwrelease) >= 9)
-               pos += lbs_add_auth_type_tlv(pos, sme->auth_type);
-
-       /* add WPA/WPA2 TLV */
-       if (sme->ie && sme->ie_len)
-               pos += lbs_add_wpa_tlv(pos, sme->ie, sme->ie_len);
-
-       len = (sizeof(*cmd) - sizeof(cmd->iebuf)) +
-               (u16)(pos - (u8 *) &cmd->iebuf);
-       cmd->hdr.size = cpu_to_le16(len);
-
-       lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_CMD", (u8 *) cmd,
-                       le16_to_cpu(cmd->hdr.size));
-
-       /* store for later use */
-       memcpy(priv->assoc_bss, bss->bssid, ETH_ALEN);
-
-       ret = lbs_cmd_with_response(priv, CMD_802_11_ASSOCIATE, cmd);
-       if (ret)
-               goto done;
-
-       /* generate connect message to cfg80211 */
-
-       resp = (void *) cmd; /* recast for easier field access */
-       status = le16_to_cpu(resp->statuscode);
-
-       /* Older FW versions map the IEEE 802.11 Status Code in the association
-        * response to the following values returned in resp->statuscode:
-        *
-        *    IEEE Status Code                Marvell Status Code
-        *    0                       ->      0x0000 ASSOC_RESULT_SUCCESS
-        *    13                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
-        *    14                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
-        *    15                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
-        *    16                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
-        *    others                  ->      0x0003 ASSOC_RESULT_REFUSED
-        *
-        * Other response codes:
-        *    0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused)
-        *    0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for
-        *                                    association response from the AP)
-        */
-       if (MRVL_FW_MAJOR_REV(priv->fwrelease) <= 8) {
-               switch (status) {
-               case 0:
-                       break;
-               case 1:
-                       lbs_deb_assoc("invalid association parameters\n");
-                       status = WLAN_STATUS_CAPS_UNSUPPORTED;
-                       break;
-               case 2:
-                       lbs_deb_assoc("timer expired while waiting for AP\n");
-                       status = WLAN_STATUS_AUTH_TIMEOUT;
-                       break;
-               case 3:
-                       lbs_deb_assoc("association refused by AP\n");
-                       status = WLAN_STATUS_ASSOC_DENIED_UNSPEC;
-                       break;
-               case 4:
-                       lbs_deb_assoc("authentication refused by AP\n");
-                       status = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
-                       break;
-               default:
-                       lbs_deb_assoc("association failure %d\n", status);
-                       /* v5 OLPC firmware does return the AP status code if
-                        * it's not one of the values above.  Let that through.
-                        */
-                       break;
-               }
-       }
-
-       lbs_deb_assoc("status %d, statuscode 0x%04x, capability 0x%04x, "
-                     "aid 0x%04x\n", status, le16_to_cpu(resp->statuscode),
-                     le16_to_cpu(resp->capability), le16_to_cpu(resp->aid));
-
-       resp_ie_len = le16_to_cpu(resp->hdr.size)
-               - sizeof(resp->hdr)
-               - 6;
-       cfg80211_connect_result(priv->dev,
-                               priv->assoc_bss,
-                               sme->ie, sme->ie_len,
-                               resp->iebuf, resp_ie_len,
-                               status,
-                               GFP_KERNEL);
-
-       if (status == 0) {
-               /* TODO: get rid of priv->connect_status */
-               priv->connect_status = LBS_CONNECTED;
-               netif_carrier_on(priv->dev);
-               if (!priv->tx_pending_len)
-                       netif_tx_wake_all_queues(priv->dev);
-       }
-
-       kfree(cmd);
-done:
-       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
-       return ret;
-}
-
-static struct cfg80211_scan_request *
-_new_connect_scan_req(struct wiphy *wiphy, struct cfg80211_connect_params *sme)
-{
-       struct cfg80211_scan_request *creq = NULL;
-       int i, n_channels = ieee80211_get_num_supported_channels(wiphy);
-       enum ieee80211_band band;
-
-       creq = kzalloc(sizeof(*creq) + sizeof(struct cfg80211_ssid) +
-                      n_channels * sizeof(void *),
-                      GFP_ATOMIC);
-       if (!creq)
-               return NULL;
-
-       /* SSIDs come after channels */
-       creq->ssids = (void *)&creq->channels[n_channels];
-       creq->n_channels = n_channels;
-       creq->n_ssids = 1;
-
-       /* Scan all available channels */
-       i = 0;
-       for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
-               int j;
-
-               if (!wiphy->bands[band])
-                       continue;
-
-               for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
-                       /* ignore disabled channels */
-                       if (wiphy->bands[band]->channels[j].flags &
-                                               IEEE80211_CHAN_DISABLED)
-                               continue;
-
-                       creq->channels[i] = &wiphy->bands[band]->channels[j];
-                       i++;
-               }
-       }
-       if (i) {
-               /* Set real number of channels specified in creq->channels[] */
-               creq->n_channels = i;
-
-               /* Scan for the SSID we're going to connect to */
-               memcpy(creq->ssids[0].ssid, sme->ssid, sme->ssid_len);
-               creq->ssids[0].ssid_len = sme->ssid_len;
-       } else {
-               /* No channels found... */
-               kfree(creq);
-               creq = NULL;
-       }
-
-       return creq;
-}
-
-static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
-                          struct cfg80211_connect_params *sme)
-{
-       struct lbs_private *priv = wiphy_priv(wiphy);
-       struct cfg80211_bss *bss = NULL;
-       int ret = 0;
-       u8 preamble = RADIO_PREAMBLE_SHORT;
-
-       if (dev == priv->mesh_dev)
-               return -EOPNOTSUPP;
-
-       lbs_deb_enter(LBS_DEB_CFG80211);
-
-       if (!sme->bssid) {
-               struct cfg80211_scan_request *creq;
-
-               /*
-                * Scan for the requested network after waiting for existing
-                * scans to finish.
-                */
-               lbs_deb_assoc("assoc: waiting for existing scans\n");
-               wait_event_interruptible_timeout(priv->scan_q,
-                                                (priv->scan_req == NULL),
-                                                (15 * HZ));
-
-               creq = _new_connect_scan_req(wiphy, sme);
-               if (!creq) {
-                       ret = -EINVAL;
-                       goto done;
-               }
-
-               lbs_deb_assoc("assoc: scanning for compatible AP\n");
-               _internal_start_scan(priv, true, creq);
-
-               lbs_deb_assoc("assoc: waiting for scan to complete\n");
-               wait_event_interruptible_timeout(priv->scan_q,
-                                                (priv->scan_req == NULL),
-                                                (15 * HZ));
-               lbs_deb_assoc("assoc: scanning completed\n");
-       }
-
-       /* Find the BSS we want using available scan results */
-       bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,
-               sme->ssid, sme->ssid_len, IEEE80211_BSS_TYPE_ESS,
-               IEEE80211_PRIVACY_ANY);
-       if (!bss) {
-               wiphy_err(wiphy, "assoc: bss %pM not in scan results\n",
-                         sme->bssid);
-               ret = -ENOENT;
-               goto done;
-       }
-       lbs_deb_assoc("trying %pM\n", bss->bssid);
-       lbs_deb_assoc("cipher 0x%x, key index %d, key len %d\n",
-                     sme->crypto.cipher_group,
-                     sme->key_idx, sme->key_len);
-
-       /* As this is a new connection, clear locally stored WEP keys */
-       priv->wep_tx_key = 0;
-       memset(priv->wep_key, 0, sizeof(priv->wep_key));
-       memset(priv->wep_key_len, 0, sizeof(priv->wep_key_len));
-
-       /* set/remove WEP keys */
-       switch (sme->crypto.cipher_group) {
-       case WLAN_CIPHER_SUITE_WEP40:
-       case WLAN_CIPHER_SUITE_WEP104:
-               /* Store provided WEP keys in priv-> */
-               priv->wep_tx_key = sme->key_idx;
-               priv->wep_key_len[sme->key_idx] = sme->key_len;
-               memcpy(priv->wep_key[sme->key_idx], sme->key, sme->key_len);
-               /* Set WEP keys and WEP mode */
-               lbs_set_wep_keys(priv);
-               priv->mac_control |= CMD_ACT_MAC_WEP_ENABLE;
-               lbs_set_mac_control(priv);
-               /* No RSN mode for WEP */
-               lbs_enable_rsn(priv, 0);
-               break;
-       case 0: /* there's no WLAN_CIPHER_SUITE_NONE definition */
-               /*
-                * If we don't have no WEP, no WPA and no WPA2,
-                * we remove all keys like in the WPA/WPA2 setup,
-                * we just don't set RSN.
-                *
-                * Therefore: fall-through
-                */
-       case WLAN_CIPHER_SUITE_TKIP:
-       case WLAN_CIPHER_SUITE_CCMP:
-               /* Remove WEP keys and WEP mode */
-               lbs_remove_wep_keys(priv);
-               priv->mac_control &= ~CMD_ACT_MAC_WEP_ENABLE;
-               lbs_set_mac_control(priv);
-
-               /* clear the WPA/WPA2 keys */
-               lbs_set_key_material(priv,
-                       KEY_TYPE_ID_WEP, /* doesn't matter */
-                       KEY_INFO_WPA_UNICAST,
-                       NULL, 0);
-               lbs_set_key_material(priv,
-                       KEY_TYPE_ID_WEP, /* doesn't matter */
-                       KEY_INFO_WPA_MCAST,
-                       NULL, 0);
-               /* RSN mode for WPA/WPA2 */
-               lbs_enable_rsn(priv, sme->crypto.cipher_group != 0);
-               break;
-       default:
-               wiphy_err(wiphy, "unsupported cipher group 0x%x\n",
-                         sme->crypto.cipher_group);
-               ret = -ENOTSUPP;
-               goto done;
-       }
-
-       ret = lbs_set_authtype(priv, sme);
-       if (ret == -ENOTSUPP) {
-               wiphy_err(wiphy, "unsupported authtype 0x%x\n", sme->auth_type);
-               goto done;
-       }
-
-       lbs_set_radio(priv, preamble, 1);
-
-       /* Do the actual association */
-       ret = lbs_associate(priv, bss, sme);
-
- done:
-       if (bss)
-               cfg80211_put_bss(wiphy, bss);
-       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
-       return ret;
-}
-
-int lbs_disconnect(struct lbs_private *priv, u16 reason)
-{
-       struct cmd_ds_802_11_deauthenticate cmd;
-       int ret;
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-       /* Mildly ugly to use a locally store my own BSSID ... */
-       memcpy(cmd.macaddr, &priv->assoc_bss, ETH_ALEN);
-       cmd.reasoncode = cpu_to_le16(reason);
-
-       ret = lbs_cmd_with_response(priv, CMD_802_11_DEAUTHENTICATE, &cmd);
-       if (ret)
-               return ret;
-
-       cfg80211_disconnected(priv->dev,
-                       reason,
-                       NULL, 0, true,
-                       GFP_KERNEL);
-       priv->connect_status = LBS_DISCONNECTED;
-
-       return 0;
-}
-
-static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev,
-       u16 reason_code)
-{
-       struct lbs_private *priv = wiphy_priv(wiphy);
-
-       if (dev == priv->mesh_dev)
-               return -EOPNOTSUPP;
-
-       lbs_deb_enter_args(LBS_DEB_CFG80211, "reason_code %d", reason_code);
-
-       /* store for lbs_cfg_ret_disconnect() */
-       priv->disassoc_reason = reason_code;
-
-       return lbs_disconnect(priv, reason_code);
-}
-
-static int lbs_cfg_set_default_key(struct wiphy *wiphy,
-                                  struct net_device *netdev,
-                                  u8 key_index, bool unicast,
-                                  bool multicast)
-{
-       struct lbs_private *priv = wiphy_priv(wiphy);
-
-       if (netdev == priv->mesh_dev)
-               return -EOPNOTSUPP;
-
-       lbs_deb_enter(LBS_DEB_CFG80211);
-
-       if (key_index != priv->wep_tx_key) {
-               lbs_deb_assoc("set_default_key: to %d\n", key_index);
-               priv->wep_tx_key = key_index;
-               lbs_set_wep_keys(priv);
-       }
-
-       return 0;
-}
-
-
-static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev,
-                          u8 idx, bool pairwise, const u8 *mac_addr,
-                          struct key_params *params)
-{
-       struct lbs_private *priv = wiphy_priv(wiphy);
-       u16 key_info;
-       u16 key_type;
-       int ret = 0;
-
-       if (netdev == priv->mesh_dev)
-               return -EOPNOTSUPP;
-
-       lbs_deb_enter(LBS_DEB_CFG80211);
-
-       lbs_deb_assoc("add_key: cipher 0x%x, mac_addr %pM\n",
-                     params->cipher, mac_addr);
-       lbs_deb_assoc("add_key: key index %d, key len %d\n",
-                     idx, params->key_len);
-       if (params->key_len)
-               lbs_deb_hex(LBS_DEB_CFG80211, "KEY",
-                           params->key, params->key_len);
-
-       lbs_deb_assoc("add_key: seq len %d\n", params->seq_len);
-       if (params->seq_len)
-               lbs_deb_hex(LBS_DEB_CFG80211, "SEQ",
-                           params->seq, params->seq_len);
-
-       switch (params->cipher) {
-       case WLAN_CIPHER_SUITE_WEP40:
-       case WLAN_CIPHER_SUITE_WEP104:
-               /* actually compare if something has changed ... */
-               if ((priv->wep_key_len[idx] != params->key_len) ||
-                       memcmp(priv->wep_key[idx],
-                              params->key, params->key_len) != 0) {
-                       priv->wep_key_len[idx] = params->key_len;
-                       memcpy(priv->wep_key[idx],
-                              params->key, params->key_len);
-                       lbs_set_wep_keys(priv);
-               }
-               break;
-       case WLAN_CIPHER_SUITE_TKIP:
-       case WLAN_CIPHER_SUITE_CCMP:
-               key_info = KEY_INFO_WPA_ENABLED | ((idx == 0)
-                                                  ? KEY_INFO_WPA_UNICAST
-                                                  : KEY_INFO_WPA_MCAST);
-               key_type = (params->cipher == WLAN_CIPHER_SUITE_TKIP)
-                       ? KEY_TYPE_ID_TKIP
-                       : KEY_TYPE_ID_AES;
-               lbs_set_key_material(priv,
-                                    key_type,
-                                    key_info,
-                                    params->key, params->key_len);
-               break;
-       default:
-               wiphy_err(wiphy, "unhandled cipher 0x%x\n", params->cipher);
-               ret = -ENOTSUPP;
-               break;
-       }
-
-       return ret;
-}
-
-
-static int lbs_cfg_del_key(struct wiphy *wiphy, struct net_device *netdev,
-                          u8 key_index, bool pairwise, const u8 *mac_addr)
-{
-
-       lbs_deb_enter(LBS_DEB_CFG80211);
-
-       lbs_deb_assoc("del_key: key_idx %d, mac_addr %pM\n",
-                     key_index, mac_addr);
-
-#ifdef TODO
-       struct lbs_private *priv = wiphy_priv(wiphy);
-       /*
-        * I think can keep this a NO-OP, because:
-
-        * - we clear all keys whenever we do lbs_cfg_connect() anyway
-        * - neither "iw" nor "wpa_supplicant" won't call this during
-        *   an ongoing connection
-        * - TODO: but I have to check if this is still true when
-        *   I set the AP to periodic re-keying
-        * - we've not kzallec() something when we've added a key at
-        *   lbs_cfg_connect() or lbs_cfg_add_key().
-        *
-        * This causes lbs_cfg_del_key() only called at disconnect time,
-        * where we'd just waste time deleting a key that is not going
-        * to be used anyway.
-        */
-       if (key_index < 3 && priv->wep_key_len[key_index]) {
-               priv->wep_key_len[key_index] = 0;
-               lbs_set_wep_keys(priv);
-       }
-#endif
-
-       return 0;
-}
-
-
-/*
- * Get station
- */
-
-static int lbs_cfg_get_station(struct wiphy *wiphy, struct net_device *dev,
-                              const u8 *mac, struct station_info *sinfo)
-{
-       struct lbs_private *priv = wiphy_priv(wiphy);
-       s8 signal, noise;
-       int ret;
-       size_t i;
-
-       lbs_deb_enter(LBS_DEB_CFG80211);
-
-       sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES) |
-                        BIT(NL80211_STA_INFO_TX_PACKETS) |
-                        BIT(NL80211_STA_INFO_RX_BYTES) |
-                        BIT(NL80211_STA_INFO_RX_PACKETS);
-       sinfo->tx_bytes = priv->dev->stats.tx_bytes;
-       sinfo->tx_packets = priv->dev->stats.tx_packets;
-       sinfo->rx_bytes = priv->dev->stats.rx_bytes;
-       sinfo->rx_packets = priv->dev->stats.rx_packets;
-
-       /* Get current RSSI */
-       ret = lbs_get_rssi(priv, &signal, &noise);
-       if (ret == 0) {
-               sinfo->signal = signal;
-               sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
-       }
-
-       /* Convert priv->cur_rate from hw_value to NL80211 value */
-       for (i = 0; i < ARRAY_SIZE(lbs_rates); i++) {
-               if (priv->cur_rate == lbs_rates[i].hw_value) {
-                       sinfo->txrate.legacy = lbs_rates[i].bitrate;
-                       sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
-                       break;
-               }
-       }
-
-       return 0;
-}
-
-
-
-
-/*
- * Change interface
- */
-
-static int lbs_change_intf(struct wiphy *wiphy, struct net_device *dev,
-       enum nl80211_iftype type, u32 *flags,
-              struct vif_params *params)
-{
-       struct lbs_private *priv = wiphy_priv(wiphy);
-       int ret = 0;
-
-       if (dev == priv->mesh_dev)
-               return -EOPNOTSUPP;
-
-       switch (type) {
-       case NL80211_IFTYPE_MONITOR:
-       case NL80211_IFTYPE_STATION:
-       case NL80211_IFTYPE_ADHOC:
-               break;
-       default:
-               return -EOPNOTSUPP;
-       }
-
-       lbs_deb_enter(LBS_DEB_CFG80211);
-
-       if (priv->iface_running)
-               ret = lbs_set_iface_type(priv, type);
-
-       if (!ret)
-               priv->wdev->iftype = type;
-
-       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
-       return ret;
-}
-
-
-
-/*
- * IBSS (Ad-Hoc)
- */
-
-/*
- * The firmware needs the following bits masked out of the beacon-derived
- * capability field when associating/joining to a BSS:
- *  9 (QoS), 11 (APSD), 12 (unused), 14 (unused), 15 (unused)
- */
-#define CAPINFO_MASK (~(0xda00))
-
-
-static void lbs_join_post(struct lbs_private *priv,
-                         struct cfg80211_ibss_params *params,
-                         u8 *bssid, u16 capability)
-{
-       u8 fake_ie[2 + IEEE80211_MAX_SSID_LEN + /* ssid */
-                  2 + 4 +                      /* basic rates */
-                  2 + 1 +                      /* DS parameter */
-                  2 + 2 +                      /* atim */
-                  2 + 8];                      /* extended rates */
-       u8 *fake = fake_ie;
-       struct cfg80211_bss *bss;
-
-       lbs_deb_enter(LBS_DEB_CFG80211);
-
-       /*
-        * For cfg80211_inform_bss, we'll need a fake IE, as we can't get
-        * the real IE from the firmware. So we fabricate a fake IE based on
-        * what the firmware actually sends (sniffed with wireshark).
-        */
-       /* Fake SSID IE */
-       *fake++ = WLAN_EID_SSID;
-       *fake++ = params->ssid_len;
-       memcpy(fake, params->ssid, params->ssid_len);
-       fake += params->ssid_len;
-       /* Fake supported basic rates IE */
-       *fake++ = WLAN_EID_SUPP_RATES;
-       *fake++ = 4;
-       *fake++ = 0x82;
-       *fake++ = 0x84;
-       *fake++ = 0x8b;
-       *fake++ = 0x96;
-       /* Fake DS channel IE */
-       *fake++ = WLAN_EID_DS_PARAMS;
-       *fake++ = 1;
-       *fake++ = params->chandef.chan->hw_value;
-       /* Fake IBSS params IE */
-       *fake++ = WLAN_EID_IBSS_PARAMS;
-       *fake++ = 2;
-       *fake++ = 0; /* ATIM=0 */
-       *fake++ = 0;
-       /* Fake extended rates IE, TODO: don't add this for 802.11b only,
-        * but I don't know how this could be checked */
-       *fake++ = WLAN_EID_EXT_SUPP_RATES;
-       *fake++ = 8;
-       *fake++ = 0x0c;
-       *fake++ = 0x12;
-       *fake++ = 0x18;
-       *fake++ = 0x24;
-       *fake++ = 0x30;
-       *fake++ = 0x48;
-       *fake++ = 0x60;
-       *fake++ = 0x6c;
-       lbs_deb_hex(LBS_DEB_CFG80211, "IE", fake_ie, fake - fake_ie);
-
-       bss = cfg80211_inform_bss(priv->wdev->wiphy,
-                                 params->chandef.chan,
-                                 CFG80211_BSS_FTYPE_UNKNOWN,
-                                 bssid,
-                                 0,
-                                 capability,
-                                 params->beacon_interval,
-                                 fake_ie, fake - fake_ie,
-                                 0, GFP_KERNEL);
-       cfg80211_put_bss(priv->wdev->wiphy, bss);
-
-       memcpy(priv->wdev->ssid, params->ssid, params->ssid_len);
-       priv->wdev->ssid_len = params->ssid_len;
-
-       cfg80211_ibss_joined(priv->dev, bssid, params->chandef.chan,
-                            GFP_KERNEL);
-
-       /* TODO: consider doing this at MACREG_INT_CODE_LINK_SENSED time */
-       priv->connect_status = LBS_CONNECTED;
-       netif_carrier_on(priv->dev);
-       if (!priv->tx_pending_len)
-               netif_wake_queue(priv->dev);
-
-       lbs_deb_leave(LBS_DEB_CFG80211);
-}
-
-static int lbs_ibss_join_existing(struct lbs_private *priv,
-       struct cfg80211_ibss_params *params,
-       struct cfg80211_bss *bss)
-{
-       const u8 *rates_eid;
-       struct cmd_ds_802_11_ad_hoc_join cmd;
-       u8 preamble = RADIO_PREAMBLE_SHORT;
-       int ret = 0;
-
-       lbs_deb_enter(LBS_DEB_CFG80211);
-
-       /* TODO: set preamble based on scan result */
-       ret = lbs_set_radio(priv, preamble, 1);
-       if (ret)
-               goto out;
-
-       /*
-        * Example CMD_802_11_AD_HOC_JOIN command:
-        *
-        * command         2c 00         CMD_802_11_AD_HOC_JOIN
-        * size            65 00
-        * sequence        xx xx
-        * result          00 00
-        * bssid           02 27 27 97 2f 96
-        * ssid            49 42 53 53 00 00 00 00
-        *                 00 00 00 00 00 00 00 00
-        *                 00 00 00 00 00 00 00 00
-        *                 00 00 00 00 00 00 00 00
-        * type            02            CMD_BSS_TYPE_IBSS
-        * beacon period   64 00
-        * dtim period     00
-        * timestamp       00 00 00 00 00 00 00 00
-        * localtime       00 00 00 00 00 00 00 00
-        * IE DS           03
-        * IE DS len       01
-        * IE DS channel   01
-        * reserveed       00 00 00 00
-        * IE IBSS         06
-        * IE IBSS len     02
-        * IE IBSS atim    00 00
-        * reserved        00 00 00 00
-        * capability      02 00
-        * rates           82 84 8b 96 0c 12 18 24 30 48 60 6c 00
-        * fail timeout    ff 00
-        * probe delay     00 00
-        */
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
-       memcpy(cmd.bss.bssid, bss->bssid, ETH_ALEN);
-       memcpy(cmd.bss.ssid, params->ssid, params->ssid_len);
-       cmd.bss.type = CMD_BSS_TYPE_IBSS;
-       cmd.bss.beaconperiod = cpu_to_le16(params->beacon_interval);
-       cmd.bss.ds.header.id = WLAN_EID_DS_PARAMS;
-       cmd.bss.ds.header.len = 1;
-       cmd.bss.ds.channel = params->chandef.chan->hw_value;
-       cmd.bss.ibss.header.id = WLAN_EID_IBSS_PARAMS;
-       cmd.bss.ibss.header.len = 2;
-       cmd.bss.ibss.atimwindow = 0;
-       cmd.bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK);
-
-       /* set rates to the intersection of our rates and the rates in the
-          bss */
-       rcu_read_lock();
-       rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
-       if (!rates_eid) {
-               lbs_add_rates(cmd.bss.rates);
-       } else {
-               int hw, i;
-               u8 rates_max = rates_eid[1];
-               u8 *rates = cmd.bss.rates;
-               for (hw = 0; hw < ARRAY_SIZE(lbs_rates); hw++) {
-                       u8 hw_rate = lbs_rates[hw].bitrate / 5;
-                       for (i = 0; i < rates_max; i++) {
-                               if (hw_rate == (rates_eid[i+2] & 0x7f)) {
-                                       u8 rate = rates_eid[i+2];
-                                       if (rate == 0x02 || rate == 0x04 ||
-                                           rate == 0x0b || rate == 0x16)
-                                               rate |= 0x80;
-                                       *rates++ = rate;
-                               }
-                       }
-               }
-       }
-       rcu_read_unlock();
-
-       /* Only v8 and below support setting this */
-       if (MRVL_FW_MAJOR_REV(priv->fwrelease) <= 8) {
-               cmd.failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
-               cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
-       }
-       ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd);
-       if (ret)
-               goto out;
-
-       /*
-        * This is a sample response to CMD_802_11_AD_HOC_JOIN:
-        *
-        * response        2c 80
-        * size            09 00
-        * sequence        xx xx
-        * result          00 00
-        * reserved        00
-        */
-       lbs_join_post(priv, params, bss->bssid, bss->capability);
-
- out:
-       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
-       return ret;
-}
-
-
-
-static int lbs_ibss_start_new(struct lbs_private *priv,
-       struct cfg80211_ibss_params *params)
-{
-       struct cmd_ds_802_11_ad_hoc_start cmd;
-       struct cmd_ds_802_11_ad_hoc_result *resp =
-               (struct cmd_ds_802_11_ad_hoc_result *) &cmd;
-       u8 preamble = RADIO_PREAMBLE_SHORT;
-       int ret = 0;
-       u16 capability;
-
-       lbs_deb_enter(LBS_DEB_CFG80211);
-
-       ret = lbs_set_radio(priv, preamble, 1);
-       if (ret)
-               goto out;
-
-       /*
-        * Example CMD_802_11_AD_HOC_START command:
-        *
-        * command         2b 00         CMD_802_11_AD_HOC_START
-        * size            b1 00
-        * sequence        xx xx
-        * result          00 00
-        * ssid            54 45 53 54 00 00 00 00
-        *                 00 00 00 00 00 00 00 00
-        *                 00 00 00 00 00 00 00 00
-        *                 00 00 00 00 00 00 00 00
-        * bss type        02
-        * beacon period   64 00
-        * dtim period     00
-        * IE IBSS         06
-        * IE IBSS len     02
-        * IE IBSS atim    00 00
-        * reserved        00 00 00 00
-        * IE DS           03
-        * IE DS len       01
-        * IE DS channel   01
-        * reserved        00 00 00 00
-        * probe delay     00 00
-        * capability      02 00
-        * rates           82 84 8b 96   (basic rates with have bit 7 set)
-        *                 0c 12 18 24 30 48 60 6c
-        * padding         100 bytes
-        */
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-       memcpy(cmd.ssid, params->ssid, params->ssid_len);
-       cmd.bsstype = CMD_BSS_TYPE_IBSS;
-       cmd.beaconperiod = cpu_to_le16(params->beacon_interval);
-       cmd.ibss.header.id = WLAN_EID_IBSS_PARAMS;
-       cmd.ibss.header.len = 2;
-       cmd.ibss.atimwindow = 0;
-       cmd.ds.header.id = WLAN_EID_DS_PARAMS;
-       cmd.ds.header.len = 1;
-       cmd.ds.channel = params->chandef.chan->hw_value;
-       /* Only v8 and below support setting probe delay */
-       if (MRVL_FW_MAJOR_REV(priv->fwrelease) <= 8)
-               cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
-       /* TODO: mix in WLAN_CAPABILITY_PRIVACY */
-       capability = WLAN_CAPABILITY_IBSS;
-       cmd.capability = cpu_to_le16(capability);
-       lbs_add_rates(cmd.rates);
-
-
-       ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_START, &cmd);
-       if (ret)
-               goto out;
-
-       /*
-        * This is a sample response to CMD_802_11_AD_HOC_JOIN:
-        *
-        * response        2b 80
-        * size            14 00
-        * sequence        xx xx
-        * result          00 00
-        * reserved        00
-        * bssid           02 2b 7b 0f 86 0e
-        */
-       lbs_join_post(priv, params, resp->bssid, capability);
-
- out:
-       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
-       return ret;
-}
-
-
-static int lbs_join_ibss(struct wiphy *wiphy, struct net_device *dev,
-               struct cfg80211_ibss_params *params)
-{
-       struct lbs_private *priv = wiphy_priv(wiphy);
-       int ret = 0;
-       struct cfg80211_bss *bss;
-
-       if (dev == priv->mesh_dev)
-               return -EOPNOTSUPP;
-
-       lbs_deb_enter(LBS_DEB_CFG80211);
-
-       if (!params->chandef.chan) {
-               ret = -ENOTSUPP;
-               goto out;
-       }
-
-       ret = lbs_set_channel(priv, params->chandef.chan->hw_value);
-       if (ret)
-               goto out;
-
-       /* Search if someone is beaconing. This assumes that the
-        * bss list is populated already */
-       bss = cfg80211_get_bss(wiphy, params->chandef.chan, params->bssid,
-               params->ssid, params->ssid_len,
-               IEEE80211_BSS_TYPE_IBSS, IEEE80211_PRIVACY_ANY);
-
-       if (bss) {
-               ret = lbs_ibss_join_existing(priv, params, bss);
-               cfg80211_put_bss(wiphy, bss);
-       } else
-               ret = lbs_ibss_start_new(priv, params);
-
-
- out:
-       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
-       return ret;
-}
-
-
-static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
-{
-       struct lbs_private *priv = wiphy_priv(wiphy);
-       struct cmd_ds_802_11_ad_hoc_stop cmd;
-       int ret = 0;
-
-       if (dev == priv->mesh_dev)
-               return -EOPNOTSUPP;
-
-       lbs_deb_enter(LBS_DEB_CFG80211);
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-       ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_STOP, &cmd);
-
-       /* TODO: consider doing this at MACREG_INT_CODE_ADHOC_BCN_LOST time */
-       lbs_mac_event_disconnected(priv, true);
-
-       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
-       return ret;
-}
-
-
-
-
-/*
- * Initialization
- */
-
-static struct cfg80211_ops lbs_cfg80211_ops = {
-       .set_monitor_channel = lbs_cfg_set_monitor_channel,
-       .libertas_set_mesh_channel = lbs_cfg_set_mesh_channel,
-       .scan = lbs_cfg_scan,
-       .connect = lbs_cfg_connect,
-       .disconnect = lbs_cfg_disconnect,
-       .add_key = lbs_cfg_add_key,
-       .del_key = lbs_cfg_del_key,
-       .set_default_key = lbs_cfg_set_default_key,
-       .get_station = lbs_cfg_get_station,
-       .change_virtual_intf = lbs_change_intf,
-       .join_ibss = lbs_join_ibss,
-       .leave_ibss = lbs_leave_ibss,
-};
-
-
-/*
- * At this time lbs_private *priv doesn't even exist, so we just allocate
- * memory and don't initialize the wiphy further. This is postponed until we
- * can talk to the firmware and happens at registration time in
- * lbs_cfg_wiphy_register().
- */
-struct wireless_dev *lbs_cfg_alloc(struct device *dev)
-{
-       int ret = 0;
-       struct wireless_dev *wdev;
-
-       lbs_deb_enter(LBS_DEB_CFG80211);
-
-       wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
-       if (!wdev)
-               return ERR_PTR(-ENOMEM);
-
-       wdev->wiphy = wiphy_new(&lbs_cfg80211_ops, sizeof(struct lbs_private));
-       if (!wdev->wiphy) {
-               dev_err(dev, "cannot allocate wiphy\n");
-               ret = -ENOMEM;
-               goto err_wiphy_new;
-       }
-
-       lbs_deb_leave(LBS_DEB_CFG80211);
-       return wdev;
-
- err_wiphy_new:
-       kfree(wdev);
-       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
-       return ERR_PTR(ret);
-}
-
-
-static void lbs_cfg_set_regulatory_hint(struct lbs_private *priv)
-{
-       struct region_code_mapping {
-               const char *cn;
-               int code;
-       };
-
-       /* Section 5.17.2 */
-       static const struct region_code_mapping regmap[] = {
-               {"US ", 0x10}, /* US FCC */
-               {"CA ", 0x20}, /* Canada */
-               {"EU ", 0x30}, /* ETSI   */
-               {"ES ", 0x31}, /* Spain  */
-               {"FR ", 0x32}, /* France */
-               {"JP ", 0x40}, /* Japan  */
-       };
-       size_t i;
-
-       lbs_deb_enter(LBS_DEB_CFG80211);
-
-       for (i = 0; i < ARRAY_SIZE(regmap); i++)
-               if (regmap[i].code == priv->regioncode) {
-                       regulatory_hint(priv->wdev->wiphy, regmap[i].cn);
-                       break;
-               }
-
-       lbs_deb_leave(LBS_DEB_CFG80211);
-}
-
-static void lbs_reg_notifier(struct wiphy *wiphy,
-                            struct regulatory_request *request)
-{
-       struct lbs_private *priv = wiphy_priv(wiphy);
-
-       lbs_deb_enter_args(LBS_DEB_CFG80211, "cfg80211 regulatory domain "
-                       "callback for domain %c%c\n", request->alpha2[0],
-                       request->alpha2[1]);
-
-       memcpy(priv->country_code, request->alpha2, sizeof(request->alpha2));
-       if (lbs_iface_active(priv))
-               lbs_set_11d_domain_info(priv);
-
-       lbs_deb_leave(LBS_DEB_CFG80211);
-}
-
-/*
- * This function get's called after lbs_setup_firmware() determined the
- * firmware capabities. So we can setup the wiphy according to our
- * hardware/firmware.
- */
-int lbs_cfg_register(struct lbs_private *priv)
-{
-       struct wireless_dev *wdev = priv->wdev;
-       int ret;
-
-       lbs_deb_enter(LBS_DEB_CFG80211);
-
-       wdev->wiphy->max_scan_ssids = 1;
-       wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
-
-       wdev->wiphy->interface_modes =
-                       BIT(NL80211_IFTYPE_STATION) |
-                       BIT(NL80211_IFTYPE_ADHOC);
-       if (lbs_rtap_supported(priv))
-               wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
-       if (lbs_mesh_activated(priv))
-               wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MESH_POINT);
-
-       wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &lbs_band_2ghz;
-
-       /*
-        * We could check priv->fwcapinfo && FW_CAPINFO_WPA, but I have
-        * never seen a firmware without WPA
-        */
-       wdev->wiphy->cipher_suites = cipher_suites;
-       wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
-       wdev->wiphy->reg_notifier = lbs_reg_notifier;
-
-       ret = wiphy_register(wdev->wiphy);
-       if (ret < 0)
-               pr_err("cannot register wiphy device\n");
-
-       priv->wiphy_registered = true;
-
-       ret = register_netdev(priv->dev);
-       if (ret)
-               pr_err("cannot register network device\n");
-
-       INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker);
-
-       lbs_cfg_set_regulatory_hint(priv);
-
-       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
-       return ret;
-}
-
-void lbs_scan_deinit(struct lbs_private *priv)
-{
-       lbs_deb_enter(LBS_DEB_CFG80211);
-       cancel_delayed_work_sync(&priv->scan_work);
-}
-
-
-void lbs_cfg_free(struct lbs_private *priv)
-{
-       struct wireless_dev *wdev = priv->wdev;
-
-       lbs_deb_enter(LBS_DEB_CFG80211);
-
-       if (!wdev)
-               return;
-
-       if (priv->wiphy_registered)
-               wiphy_unregister(wdev->wiphy);
-
-       if (wdev->wiphy)
-               wiphy_free(wdev->wiphy);
-
-       kfree(wdev);
-}
diff --git a/drivers/net/wireless/libertas/cfg.h b/drivers/net/wireless/libertas/cfg.h
deleted file mode 100644 (file)
index acccc29..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef __LBS_CFG80211_H__
-#define __LBS_CFG80211_H__
-
-struct device;
-struct lbs_private;
-struct regulatory_request;
-struct wiphy;
-
-struct wireless_dev *lbs_cfg_alloc(struct device *dev);
-int lbs_cfg_register(struct lbs_private *priv);
-void lbs_cfg_free(struct lbs_private *priv);
-
-void lbs_send_disconnect_notification(struct lbs_private *priv,
-                                     bool locally_generated);
-void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event);
-
-void lbs_scan_done(struct lbs_private *priv);
-void lbs_scan_deinit(struct lbs_private *priv);
-int lbs_disconnect(struct lbs_private *priv, u16 reason);
-
-#endif
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
deleted file mode 100644 (file)
index 0387a5b..0000000
+++ /dev/null
@@ -1,1725 +0,0 @@
-/*
- * This file contains the handling of command.
- * It prepares command and sends it to firmware when it is ready.
- */
-
-#include <linux/hardirq.h>
-#include <linux/kfifo.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/if_arp.h>
-#include <linux/export.h>
-
-#include "decl.h"
-#include "cfg.h"
-#include "cmd.h"
-
-#define CAL_NF(nf)             ((s32)(-(s32)(nf)))
-#define CAL_RSSI(snr, nf)      ((s32)((s32)(snr) + CAL_NF(nf)))
-
-/**
- * lbs_cmd_copyback - Simple callback that copies response back into command
- *
- * @priv:      A pointer to &struct lbs_private structure
- * @extra:     A pointer to the original command structure for which
- *             'resp' is a response
- * @resp:      A pointer to the command response
- *
- * returns:    0 on success, error on failure
- */
-int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra,
-                    struct cmd_header *resp)
-{
-       struct cmd_header *buf = (void *)extra;
-       uint16_t copy_len;
-
-       copy_len = min(le16_to_cpu(buf->size), le16_to_cpu(resp->size));
-       memcpy(buf, resp, copy_len);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(lbs_cmd_copyback);
-
-/**
- *  lbs_cmd_async_callback - Simple callback that ignores the result.
- *  Use this if you just want to send a command to the hardware, but don't
- *  care for the result.
- *
- *  @priv:     ignored
- *  @extra:    ignored
- *  @resp:     ignored
- *
- *  returns:   0 for success
- */
-static int lbs_cmd_async_callback(struct lbs_private *priv, unsigned long extra,
-                    struct cmd_header *resp)
-{
-       return 0;
-}
-
-
-/**
- *  is_command_allowed_in_ps - tests if a command is allowed in Power Save mode
- *
- *  @cmd:      the command ID
- *
- *  returns:   1 if allowed, 0 if not allowed
- */
-static u8 is_command_allowed_in_ps(u16 cmd)
-{
-       switch (cmd) {
-       case CMD_802_11_RSSI:
-               return 1;
-       case CMD_802_11_HOST_SLEEP_CFG:
-               return 1;
-       default:
-               break;
-       }
-       return 0;
-}
-
-/**
- *  lbs_update_hw_spec - Updates the hardware details like MAC address
- *  and regulatory region
- *
- *  @priv:     A pointer to &struct lbs_private structure
- *
- *  returns:   0 on success, error on failure
- */
-int lbs_update_hw_spec(struct lbs_private *priv)
-{
-       struct cmd_ds_get_hw_spec cmd;
-       int ret = -1;
-       u32 i;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-       memcpy(cmd.permanentaddr, priv->current_addr, ETH_ALEN);
-       ret = lbs_cmd_with_response(priv, CMD_GET_HW_SPEC, &cmd);
-       if (ret)
-               goto out;
-
-       priv->fwcapinfo = le32_to_cpu(cmd.fwcapinfo);
-
-       /* The firmware release is in an interesting format: the patch
-        * level is in the most significant nibble ... so fix that: */
-       priv->fwrelease = le32_to_cpu(cmd.fwrelease);
-       priv->fwrelease = (priv->fwrelease << 8) |
-               (priv->fwrelease >> 24 & 0xff);
-
-       /* Some firmware capabilities:
-        * CF card    firmware 5.0.16p0:   cap 0x00000303
-        * USB dongle firmware 5.110.17p2: cap 0x00000303
-        */
-       netdev_info(priv->dev, "%pM, fw %u.%u.%up%u, cap 0x%08x\n",
-               cmd.permanentaddr,
-               priv->fwrelease >> 24 & 0xff,
-               priv->fwrelease >> 16 & 0xff,
-               priv->fwrelease >>  8 & 0xff,
-               priv->fwrelease       & 0xff,
-               priv->fwcapinfo);
-       lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n",
-                   cmd.hwifversion, cmd.version);
-
-       /* Clamp region code to 8-bit since FW spec indicates that it should
-        * only ever be 8-bit, even though the field size is 16-bit.  Some firmware
-        * returns non-zero high 8 bits here.
-        *
-        * Firmware version 4.0.102 used in CF8381 has region code shifted.  We
-        * need to check for this problem and handle it properly.
-        */
-       if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V4)
-               priv->regioncode = (le16_to_cpu(cmd.regioncode) >> 8) & 0xFF;
-       else
-               priv->regioncode = le16_to_cpu(cmd.regioncode) & 0xFF;
-
-       for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
-               /* use the region code to search for the index */
-               if (priv->regioncode == lbs_region_code_to_index[i])
-                       break;
-       }
-
-       /* if it's unidentified region code, use the default (USA) */
-       if (i >= MRVDRV_MAX_REGION_CODE) {
-               priv->regioncode = 0x10;
-               netdev_info(priv->dev,
-                           "unidentified region code; using the default (USA)\n");
-       }
-
-       if (priv->current_addr[0] == 0xff)
-               memmove(priv->current_addr, cmd.permanentaddr, ETH_ALEN);
-
-       if (!priv->copied_hwaddr) {
-               memcpy(priv->dev->dev_addr, priv->current_addr, ETH_ALEN);
-               if (priv->mesh_dev)
-                       memcpy(priv->mesh_dev->dev_addr,
-                               priv->current_addr, ETH_ALEN);
-               priv->copied_hwaddr = 1;
-       }
-
-out:
-       lbs_deb_leave(LBS_DEB_CMD);
-       return ret;
-}
-
-static int lbs_ret_host_sleep_cfg(struct lbs_private *priv, unsigned long dummy,
-                       struct cmd_header *resp)
-{
-       lbs_deb_enter(LBS_DEB_CMD);
-       if (priv->is_host_sleep_activated) {
-               priv->is_host_sleep_configured = 0;
-               if (priv->psstate == PS_STATE_FULL_POWER) {
-                       priv->is_host_sleep_activated = 0;
-                       wake_up_interruptible(&priv->host_sleep_q);
-               }
-       } else {
-               priv->is_host_sleep_configured = 1;
-       }
-       lbs_deb_leave(LBS_DEB_CMD);
-       return 0;
-}
-
-int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
-               struct wol_config *p_wol_config)
-{
-       struct cmd_ds_host_sleep cmd_config;
-       int ret;
-
-       /*
-        * Certain firmware versions do not support EHS_REMOVE_WAKEUP command
-        * and the card will return a failure.  Since we need to be
-        * able to reset the mask, in those cases we set a 0 mask instead.
-        */
-       if (criteria == EHS_REMOVE_WAKEUP && !priv->ehs_remove_supported)
-               criteria = 0;
-
-       cmd_config.hdr.size = cpu_to_le16(sizeof(cmd_config));
-       cmd_config.criteria = cpu_to_le32(criteria);
-       cmd_config.gpio = priv->wol_gpio;
-       cmd_config.gap = priv->wol_gap;
-
-       if (p_wol_config != NULL)
-               memcpy((uint8_t *)&cmd_config.wol_conf, (uint8_t *)p_wol_config,
-                               sizeof(struct wol_config));
-       else
-               cmd_config.wol_conf.action = CMD_ACT_ACTION_NONE;
-
-       ret = __lbs_cmd(priv, CMD_802_11_HOST_SLEEP_CFG, &cmd_config.hdr,
-                       le16_to_cpu(cmd_config.hdr.size),
-                       lbs_ret_host_sleep_cfg, 0);
-       if (!ret) {
-               if (p_wol_config)
-                       memcpy((uint8_t *) p_wol_config,
-                                       (uint8_t *)&cmd_config.wol_conf,
-                                       sizeof(struct wol_config));
-       } else {
-               netdev_info(priv->dev, "HOST_SLEEP_CFG failed %d\n", ret);
-       }
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(lbs_host_sleep_cfg);
-
-/**
- *  lbs_set_ps_mode - Sets the Power Save mode
- *
- *  @priv:     A pointer to &struct lbs_private structure
- *  @cmd_action: The Power Save operation (PS_MODE_ACTION_ENTER_PS or
- *                         PS_MODE_ACTION_EXIT_PS)
- *  @block:    Whether to block on a response or not
- *
- *  returns:   0 on success, error on failure
- */
-int lbs_set_ps_mode(struct lbs_private *priv, u16 cmd_action, bool block)
-{
-       struct cmd_ds_802_11_ps_mode cmd;
-       int ret = 0;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-       cmd.action = cpu_to_le16(cmd_action);
-
-       if (cmd_action == PS_MODE_ACTION_ENTER_PS) {
-               lbs_deb_cmd("PS_MODE: action ENTER_PS\n");
-               cmd.multipledtim = cpu_to_le16(1);  /* Default DTIM multiple */
-       } else if (cmd_action == PS_MODE_ACTION_EXIT_PS) {
-               lbs_deb_cmd("PS_MODE: action EXIT_PS\n");
-       } else {
-               /* We don't handle CONFIRM_SLEEP here because it needs to
-                * be fastpathed to the firmware.
-                */
-               lbs_deb_cmd("PS_MODE: unknown action 0x%X\n", cmd_action);
-               ret = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (block)
-               ret = lbs_cmd_with_response(priv, CMD_802_11_PS_MODE, &cmd);
-       else
-               lbs_cmd_async(priv, CMD_802_11_PS_MODE, &cmd.hdr, sizeof (cmd));
-
-out:
-       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
-       return ret;
-}
-
-int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
-                               struct sleep_params *sp)
-{
-       struct cmd_ds_802_11_sleep_params cmd;
-       int ret;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       if (cmd_action == CMD_ACT_GET) {
-               memset(&cmd, 0, sizeof(cmd));
-       } else {
-               cmd.error = cpu_to_le16(sp->sp_error);
-               cmd.offset = cpu_to_le16(sp->sp_offset);
-               cmd.stabletime = cpu_to_le16(sp->sp_stabletime);
-               cmd.calcontrol = sp->sp_calcontrol;
-               cmd.externalsleepclk = sp->sp_extsleepclk;
-               cmd.reserved = cpu_to_le16(sp->sp_reserved);
-       }
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-       cmd.action = cpu_to_le16(cmd_action);
-
-       ret = lbs_cmd_with_response(priv, CMD_802_11_SLEEP_PARAMS, &cmd);
-
-       if (!ret) {
-               lbs_deb_cmd("error 0x%x, offset 0x%x, stabletime 0x%x, "
-                           "calcontrol 0x%x extsleepclk 0x%x\n",
-                           le16_to_cpu(cmd.error), le16_to_cpu(cmd.offset),
-                           le16_to_cpu(cmd.stabletime), cmd.calcontrol,
-                           cmd.externalsleepclk);
-
-               sp->sp_error = le16_to_cpu(cmd.error);
-               sp->sp_offset = le16_to_cpu(cmd.offset);
-               sp->sp_stabletime = le16_to_cpu(cmd.stabletime);
-               sp->sp_calcontrol = cmd.calcontrol;
-               sp->sp_extsleepclk = cmd.externalsleepclk;
-               sp->sp_reserved = le16_to_cpu(cmd.reserved);
-       }
-
-       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
-       return 0;
-}
-
-static int lbs_wait_for_ds_awake(struct lbs_private *priv)
-{
-       int ret = 0;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       if (priv->is_deep_sleep) {
-               if (!wait_event_interruptible_timeout(priv->ds_awake_q,
-                                       !priv->is_deep_sleep, (10 * HZ))) {
-                       netdev_err(priv->dev, "ds_awake_q: timer expired\n");
-                       ret = -1;
-               }
-       }
-
-       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
-       return ret;
-}
-
-int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep)
-{
-       int ret =  0;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       if (deep_sleep) {
-               if (priv->is_deep_sleep != 1) {
-                       lbs_deb_cmd("deep sleep: sleep\n");
-                       BUG_ON(!priv->enter_deep_sleep);
-                       ret = priv->enter_deep_sleep(priv);
-                       if (!ret) {
-                               netif_stop_queue(priv->dev);
-                               netif_carrier_off(priv->dev);
-                       }
-               } else {
-                       netdev_err(priv->dev, "deep sleep: already enabled\n");
-               }
-       } else {
-               if (priv->is_deep_sleep) {
-                       lbs_deb_cmd("deep sleep: wakeup\n");
-                       BUG_ON(!priv->exit_deep_sleep);
-                       ret = priv->exit_deep_sleep(priv);
-                       if (!ret) {
-                               ret = lbs_wait_for_ds_awake(priv);
-                               if (ret)
-                                       netdev_err(priv->dev,
-                                                  "deep sleep: wakeup failed\n");
-                       }
-               }
-       }
-
-       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
-       return ret;
-}
-
-static int lbs_ret_host_sleep_activate(struct lbs_private *priv,
-               unsigned long dummy,
-               struct cmd_header *cmd)
-{
-       lbs_deb_enter(LBS_DEB_FW);
-       priv->is_host_sleep_activated = 1;
-       wake_up_interruptible(&priv->host_sleep_q);
-       lbs_deb_leave(LBS_DEB_FW);
-       return 0;
-}
-
-int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep)
-{
-       struct cmd_header cmd;
-       int ret = 0;
-       uint32_t criteria = EHS_REMOVE_WAKEUP;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       if (host_sleep) {
-               if (priv->is_host_sleep_activated != 1) {
-                       memset(&cmd, 0, sizeof(cmd));
-                       ret = lbs_host_sleep_cfg(priv, priv->wol_criteria,
-                                       (struct wol_config *)NULL);
-                       if (ret) {
-                               netdev_info(priv->dev,
-                                           "Host sleep configuration failed: %d\n",
-                                           ret);
-                               return ret;
-                       }
-                       if (priv->psstate == PS_STATE_FULL_POWER) {
-                               ret = __lbs_cmd(priv,
-                                               CMD_802_11_HOST_SLEEP_ACTIVATE,
-                                               &cmd,
-                                               sizeof(cmd),
-                                               lbs_ret_host_sleep_activate, 0);
-                               if (ret)
-                                       netdev_info(priv->dev,
-                                                   "HOST_SLEEP_ACTIVATE failed: %d\n",
-                                                   ret);
-                       }
-
-                       if (!wait_event_interruptible_timeout(
-                                               priv->host_sleep_q,
-                                               priv->is_host_sleep_activated,
-                                               (10 * HZ))) {
-                               netdev_err(priv->dev,
-                                          "host_sleep_q: timer expired\n");
-                               ret = -1;
-                       }
-               } else {
-                       netdev_err(priv->dev, "host sleep: already enabled\n");
-               }
-       } else {
-               if (priv->is_host_sleep_activated)
-                       ret = lbs_host_sleep_cfg(priv, criteria,
-                                       (struct wol_config *)NULL);
-       }
-
-       return ret;
-}
-
-/**
- *  lbs_set_snmp_mib - Set an SNMP MIB value
- *
- *  @priv:     A pointer to &struct lbs_private structure
- *  @oid:      The OID to set in the firmware
- *  @val:      Value to set the OID to
- *
- *  returns:           0 on success, error on failure
- */
-int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val)
-{
-       struct cmd_ds_802_11_snmp_mib cmd;
-       int ret;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       memset(&cmd, 0, sizeof (cmd));
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-       cmd.action = cpu_to_le16(CMD_ACT_SET);
-       cmd.oid = cpu_to_le16((u16) oid);
-
-       switch (oid) {
-       case SNMP_MIB_OID_BSS_TYPE:
-               cmd.bufsize = cpu_to_le16(sizeof(u8));
-               cmd.value[0] = val;
-               break;
-       case SNMP_MIB_OID_11D_ENABLE:
-       case SNMP_MIB_OID_FRAG_THRESHOLD:
-       case SNMP_MIB_OID_RTS_THRESHOLD:
-       case SNMP_MIB_OID_SHORT_RETRY_LIMIT:
-       case SNMP_MIB_OID_LONG_RETRY_LIMIT:
-               cmd.bufsize = cpu_to_le16(sizeof(u16));
-               *((__le16 *)(&cmd.value)) = cpu_to_le16(val);
-               break;
-       default:
-               lbs_deb_cmd("SNMP_CMD: (set) unhandled OID 0x%x\n", oid);
-               ret = -EINVAL;
-               goto out;
-       }
-
-       lbs_deb_cmd("SNMP_CMD: (set) oid 0x%x, oid size 0x%x, value 0x%x\n",
-                   le16_to_cpu(cmd.oid), le16_to_cpu(cmd.bufsize), val);
-
-       ret = lbs_cmd_with_response(priv, CMD_802_11_SNMP_MIB, &cmd);
-
-out:
-       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
-       return ret;
-}
-
-/**
- *  lbs_get_snmp_mib - Get an SNMP MIB value
- *
- *  @priv:     A pointer to &struct lbs_private structure
- *  @oid:      The OID to retrieve from the firmware
- *  @out_val:  Location for the returned value
- *
- *  returns:   0 on success, error on failure
- */
-int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val)
-{
-       struct cmd_ds_802_11_snmp_mib cmd;
-       int ret;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       memset(&cmd, 0, sizeof (cmd));
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-       cmd.action = cpu_to_le16(CMD_ACT_GET);
-       cmd.oid = cpu_to_le16(oid);
-
-       ret = lbs_cmd_with_response(priv, CMD_802_11_SNMP_MIB, &cmd);
-       if (ret)
-               goto out;
-
-       switch (le16_to_cpu(cmd.bufsize)) {
-       case sizeof(u8):
-               *out_val = cmd.value[0];
-               break;
-       case sizeof(u16):
-               *out_val = le16_to_cpu(*((__le16 *)(&cmd.value)));
-               break;
-       default:
-               lbs_deb_cmd("SNMP_CMD: (get) unhandled OID 0x%x size %d\n",
-                           oid, le16_to_cpu(cmd.bufsize));
-               break;
-       }
-
-out:
-       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
-       return ret;
-}
-
-/**
- *  lbs_get_tx_power - Get the min, max, and current TX power
- *
- *  @priv:     A pointer to &struct lbs_private structure
- *  @curlevel: Current power level in dBm
- *  @minlevel: Minimum supported power level in dBm (optional)
- *  @maxlevel: Maximum supported power level in dBm (optional)
- *
- *  returns:   0 on success, error on failure
- */
-int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel,
-                    s16 *maxlevel)
-{
-       struct cmd_ds_802_11_rf_tx_power cmd;
-       int ret;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-       cmd.action = cpu_to_le16(CMD_ACT_GET);
-
-       ret = lbs_cmd_with_response(priv, CMD_802_11_RF_TX_POWER, &cmd);
-       if (ret == 0) {
-               *curlevel = le16_to_cpu(cmd.curlevel);
-               if (minlevel)
-                       *minlevel = cmd.minlevel;
-               if (maxlevel)
-                       *maxlevel = cmd.maxlevel;
-       }
-
-       lbs_deb_leave(LBS_DEB_CMD);
-       return ret;
-}
-
-/**
- *  lbs_set_tx_power - Set the TX power
- *
- *  @priv:     A pointer to &struct lbs_private structure
- *  @dbm:      The desired power level in dBm
- *
- *  returns:           0 on success, error on failure
- */
-int lbs_set_tx_power(struct lbs_private *priv, s16 dbm)
-{
-       struct cmd_ds_802_11_rf_tx_power cmd;
-       int ret;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-       cmd.action = cpu_to_le16(CMD_ACT_SET);
-       cmd.curlevel = cpu_to_le16(dbm);
-
-       lbs_deb_cmd("SET_RF_TX_POWER: %d dBm\n", dbm);
-
-       ret = lbs_cmd_with_response(priv, CMD_802_11_RF_TX_POWER, &cmd);
-
-       lbs_deb_leave(LBS_DEB_CMD);
-       return ret;
-}
-
-/**
- *  lbs_set_monitor_mode - Enable or disable monitor mode
- *  (only implemented on OLPC usb8388 FW)
- *
- *  @priv:     A pointer to &struct lbs_private structure
- *  @enable:   1 to enable monitor mode, 0 to disable
- *
- *  returns:   0 on success, error on failure
- */
-int lbs_set_monitor_mode(struct lbs_private *priv, int enable)
-{
-       struct cmd_ds_802_11_monitor_mode cmd;
-       int ret;
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-       cmd.action = cpu_to_le16(CMD_ACT_SET);
-       if (enable)
-               cmd.mode = cpu_to_le16(0x1);
-
-       lbs_deb_cmd("SET_MONITOR_MODE: %d\n", enable);
-
-       ret = lbs_cmd_with_response(priv, CMD_802_11_MONITOR_MODE, &cmd);
-       if (ret == 0) {
-               priv->dev->type = enable ? ARPHRD_IEEE80211_RADIOTAP :
-                                               ARPHRD_ETHER;
-       }
-
-       lbs_deb_leave(LBS_DEB_CMD);
-       return ret;
-}
-
-/**
- *  lbs_get_channel - Get the radio channel
- *
- *  @priv:     A pointer to &struct lbs_private structure
- *
- *  returns:   The channel on success, error on failure
- */
-static int lbs_get_channel(struct lbs_private *priv)
-{
-       struct cmd_ds_802_11_rf_channel cmd;
-       int ret = 0;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-       cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_GET);
-
-       ret = lbs_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
-       if (ret)
-               goto out;
-
-       ret = le16_to_cpu(cmd.channel);
-       lbs_deb_cmd("current radio channel is %d\n", ret);
-
-out:
-       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
-       return ret;
-}
-
-int lbs_update_channel(struct lbs_private *priv)
-{
-       int ret;
-
-       /* the channel in f/w could be out of sync; get the current channel */
-       lbs_deb_enter(LBS_DEB_ASSOC);
-
-       ret = lbs_get_channel(priv);
-       if (ret > 0) {
-               priv->channel = ret;
-               ret = 0;
-       }
-       lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-       return ret;
-}
-
-/**
- *  lbs_set_channel - Set the radio channel
- *
- *  @priv:     A pointer to &struct lbs_private structure
- *  @channel:  The desired channel, or 0 to clear a locked channel
- *
- *  returns:   0 on success, error on failure
- */
-int lbs_set_channel(struct lbs_private *priv, u8 channel)
-{
-       struct cmd_ds_802_11_rf_channel cmd;
-#ifdef DEBUG
-       u8 old_channel = priv->channel;
-#endif
-       int ret = 0;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-       cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_SET);
-       cmd.channel = cpu_to_le16(channel);
-
-       ret = lbs_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
-       if (ret)
-               goto out;
-
-       priv->channel = (uint8_t) le16_to_cpu(cmd.channel);
-       lbs_deb_cmd("channel switch from %d to %d\n", old_channel,
-               priv->channel);
-
-out:
-       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
-       return ret;
-}
-
-/**
- * lbs_get_rssi - Get current RSSI and noise floor
- *
- * @priv:      A pointer to &struct lbs_private structure
- * @rssi:      On successful return, signal level in mBm
- * @nf:                On successful return, Noise floor
- *
- * returns:    The channel on success, error on failure
- */
-int lbs_get_rssi(struct lbs_private *priv, s8 *rssi, s8 *nf)
-{
-       struct cmd_ds_802_11_rssi cmd;
-       int ret = 0;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       BUG_ON(rssi == NULL);
-       BUG_ON(nf == NULL);
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-       /* Average SNR over last 8 beacons */
-       cmd.n_or_snr = cpu_to_le16(8);
-
-       ret = lbs_cmd_with_response(priv, CMD_802_11_RSSI, &cmd);
-       if (ret == 0) {
-               *nf = CAL_NF(le16_to_cpu(cmd.nf));
-               *rssi = CAL_RSSI(le16_to_cpu(cmd.n_or_snr), le16_to_cpu(cmd.nf));
-       }
-
-       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
-       return ret;
-}
-
-/**
- *  lbs_set_11d_domain_info - Send regulatory and 802.11d domain information
- *  to the firmware
- *
- *  @priv:     pointer to &struct lbs_private
- *
- *  returns:   0 on success, error code on failure
-*/
-int lbs_set_11d_domain_info(struct lbs_private *priv)
-{
-       struct wiphy *wiphy = priv->wdev->wiphy;
-       struct ieee80211_supported_band **bands = wiphy->bands;
-       struct cmd_ds_802_11d_domain_info cmd;
-       struct mrvl_ie_domain_param_set *domain = &cmd.domain;
-       struct ieee80211_country_ie_triplet *t;
-       enum ieee80211_band band;
-       struct ieee80211_channel *ch;
-       u8 num_triplet = 0;
-       u8 num_parsed_chan = 0;
-       u8 first_channel = 0, next_chan = 0, max_pwr = 0;
-       u8 i, flag = 0;
-       size_t triplet_size;
-       int ret = 0;
-
-       lbs_deb_enter(LBS_DEB_11D);
-       if (!priv->country_code[0])
-               goto out;
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.action = cpu_to_le16(CMD_ACT_SET);
-
-       lbs_deb_11d("Setting country code '%c%c'\n",
-                   priv->country_code[0], priv->country_code[1]);
-
-       domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
-
-       /* Set country code */
-       domain->country_code[0] = priv->country_code[0];
-       domain->country_code[1] = priv->country_code[1];
-       domain->country_code[2] = ' ';
-
-       /* Now set up the channel triplets; firmware is somewhat picky here
-        * and doesn't validate channel numbers and spans; hence it would
-        * interpret a triplet of (36, 4, 20) as channels 36, 37, 38, 39.  Since
-        * the last 3 aren't valid channels, the driver is responsible for
-        * splitting that up into 4 triplet pairs of (36, 1, 20) + (40, 1, 20)
-        * etc.
-        */
-       for (band = 0;
-            (band < IEEE80211_NUM_BANDS) && (num_triplet < MAX_11D_TRIPLETS);
-            band++) {
-
-               if (!bands[band])
-                       continue;
-
-               for (i = 0;
-                    (i < bands[band]->n_channels) && (num_triplet < MAX_11D_TRIPLETS);
-                    i++) {
-                       ch = &bands[band]->channels[i];
-                       if (ch->flags & IEEE80211_CHAN_DISABLED)
-                               continue;
-
-                       if (!flag) {
-                               flag = 1;
-                               next_chan = first_channel = (u32) ch->hw_value;
-                               max_pwr = ch->max_power;
-                               num_parsed_chan = 1;
-                               continue;
-                       }
-
-                       if ((ch->hw_value == next_chan + 1) &&
-                                       (ch->max_power == max_pwr)) {
-                               /* Consolidate adjacent channels */
-                               next_chan++;
-                               num_parsed_chan++;
-                       } else {
-                               /* Add this triplet */
-                               lbs_deb_11d("11D triplet (%d, %d, %d)\n",
-                                       first_channel, num_parsed_chan,
-                                       max_pwr);
-                               t = &domain->triplet[num_triplet];
-                               t->chans.first_channel = first_channel;
-                               t->chans.num_channels = num_parsed_chan;
-                               t->chans.max_power = max_pwr;
-                               num_triplet++;
-                               flag = 0;
-                       }
-               }
-
-               if (flag) {
-                       /* Add last triplet */
-                       lbs_deb_11d("11D triplet (%d, %d, %d)\n", first_channel,
-                               num_parsed_chan, max_pwr);
-                       t = &domain->triplet[num_triplet];
-                       t->chans.first_channel = first_channel;
-                       t->chans.num_channels = num_parsed_chan;
-                       t->chans.max_power = max_pwr;
-                       num_triplet++;
-               }
-       }
-
-       lbs_deb_11d("# triplets %d\n", num_triplet);
-
-       /* Set command header sizes */
-       triplet_size = num_triplet * sizeof(struct ieee80211_country_ie_triplet);
-       domain->header.len = cpu_to_le16(sizeof(domain->country_code) +
-                                       triplet_size);
-
-       lbs_deb_hex(LBS_DEB_11D, "802.11D domain param set",
-                       (u8 *) &cmd.domain.country_code,
-                       le16_to_cpu(domain->header.len));
-
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd.hdr) +
-                                  sizeof(cmd.action) +
-                                  sizeof(cmd.domain.header) +
-                                  sizeof(cmd.domain.country_code) +
-                                  triplet_size);
-
-       ret = lbs_cmd_with_response(priv, CMD_802_11D_DOMAIN_INFO, &cmd);
-
-out:
-       lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
-       return ret;
-}
-
-/**
- *  lbs_get_reg - Read a MAC, Baseband, or RF register
- *
- *  @priv:     pointer to &struct lbs_private
- *  @reg:      register command, one of CMD_MAC_REG_ACCESS,
- *             CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS
- *  @offset:   byte offset of the register to get
- *  @value:    on success, the value of the register at 'offset'
- *
- *  returns:   0 on success, error code on failure
-*/
-int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value)
-{
-       struct cmd_ds_reg_access cmd;
-       int ret = 0;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       BUG_ON(value == NULL);
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-       cmd.action = cpu_to_le16(CMD_ACT_GET);
-       cmd.offset = cpu_to_le16(offset);
-
-       if (reg != CMD_MAC_REG_ACCESS &&
-           reg != CMD_BBP_REG_ACCESS &&
-           reg != CMD_RF_REG_ACCESS) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       ret = lbs_cmd_with_response(priv, reg, &cmd);
-       if (!ret) {
-               if (reg == CMD_BBP_REG_ACCESS || reg == CMD_RF_REG_ACCESS)
-                       *value = cmd.value.bbp_rf;
-               else if (reg == CMD_MAC_REG_ACCESS)
-                       *value = le32_to_cpu(cmd.value.mac);
-       }
-
-out:
-       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
-       return ret;
-}
-
-/**
- *  lbs_set_reg - Write a MAC, Baseband, or RF register
- *
- *  @priv:     pointer to &struct lbs_private
- *  @reg:      register command, one of CMD_MAC_REG_ACCESS,
- *             CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS
- *  @offset:   byte offset of the register to set
- *  @value:    the value to write to the register at 'offset'
- *
- *  returns:   0 on success, error code on failure
-*/
-int lbs_set_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 value)
-{
-       struct cmd_ds_reg_access cmd;
-       int ret = 0;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-       cmd.action = cpu_to_le16(CMD_ACT_SET);
-       cmd.offset = cpu_to_le16(offset);
-
-       if (reg == CMD_BBP_REG_ACCESS || reg == CMD_RF_REG_ACCESS)
-               cmd.value.bbp_rf = (u8) (value & 0xFF);
-       else if (reg == CMD_MAC_REG_ACCESS)
-               cmd.value.mac = cpu_to_le32(value);
-       else {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       ret = lbs_cmd_with_response(priv, reg, &cmd);
-
-out:
-       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
-       return ret;
-}
-
-static void lbs_queue_cmd(struct lbs_private *priv,
-                         struct cmd_ctrl_node *cmdnode)
-{
-       unsigned long flags;
-       int addtail = 1;
-
-       lbs_deb_enter(LBS_DEB_HOST);
-
-       if (!cmdnode) {
-               lbs_deb_host("QUEUE_CMD: cmdnode is NULL\n");
-               goto done;
-       }
-       if (!cmdnode->cmdbuf->size) {
-               lbs_deb_host("DNLD_CMD: cmd size is zero\n");
-               goto done;
-       }
-       cmdnode->result = 0;
-
-       /* Exit_PS command needs to be queued in the header always. */
-       if (le16_to_cpu(cmdnode->cmdbuf->command) == CMD_802_11_PS_MODE) {
-               struct cmd_ds_802_11_ps_mode *psm = (void *) &cmdnode->cmdbuf;
-
-               if (psm->action == cpu_to_le16(PS_MODE_ACTION_EXIT_PS)) {
-                       if (priv->psstate != PS_STATE_FULL_POWER)
-                               addtail = 0;
-               }
-       }
-
-       if (le16_to_cpu(cmdnode->cmdbuf->command) == CMD_802_11_WAKEUP_CONFIRM)
-               addtail = 0;
-
-       spin_lock_irqsave(&priv->driver_lock, flags);
-
-       if (addtail)
-               list_add_tail(&cmdnode->list, &priv->cmdpendingq);
-       else
-               list_add(&cmdnode->list, &priv->cmdpendingq);
-
-       spin_unlock_irqrestore(&priv->driver_lock, flags);
-
-       lbs_deb_host("QUEUE_CMD: inserted command 0x%04x into cmdpendingq\n",
-                    le16_to_cpu(cmdnode->cmdbuf->command));
-
-done:
-       lbs_deb_leave(LBS_DEB_HOST);
-}
-
-static void lbs_submit_command(struct lbs_private *priv,
-                              struct cmd_ctrl_node *cmdnode)
-{
-       unsigned long flags;
-       struct cmd_header *cmd;
-       uint16_t cmdsize;
-       uint16_t command;
-       int timeo = 3 * HZ;
-       int ret;
-
-       lbs_deb_enter(LBS_DEB_HOST);
-
-       cmd = cmdnode->cmdbuf;
-
-       spin_lock_irqsave(&priv->driver_lock, flags);
-       priv->seqnum++;
-       cmd->seqnum = cpu_to_le16(priv->seqnum);
-       priv->cur_cmd = cmdnode;
-       spin_unlock_irqrestore(&priv->driver_lock, flags);
-
-       cmdsize = le16_to_cpu(cmd->size);
-       command = le16_to_cpu(cmd->command);
-
-       /* These commands take longer */
-       if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE)
-               timeo = 5 * HZ;
-
-       lbs_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d\n",
-                    command, le16_to_cpu(cmd->seqnum), cmdsize);
-       lbs_deb_hex(LBS_DEB_CMD, "DNLD_CMD", (void *) cmdnode->cmdbuf, cmdsize);
-
-       ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize);
-
-       if (ret) {
-               netdev_info(priv->dev, "DNLD_CMD: hw_host_to_card failed: %d\n",
-                           ret);
-               /* Reset dnld state machine, report failure */
-               priv->dnld_sent = DNLD_RES_RECEIVED;
-               lbs_complete_command(priv, cmdnode, ret);
-       }
-
-       if (command == CMD_802_11_DEEP_SLEEP) {
-               if (priv->is_auto_deep_sleep_enabled) {
-                       priv->wakeup_dev_required = 1;
-                       priv->dnld_sent = 0;
-               }
-               priv->is_deep_sleep = 1;
-               lbs_complete_command(priv, cmdnode, 0);
-       } else {
-               /* Setup the timer after transmit command */
-               mod_timer(&priv->command_timer, jiffies + timeo);
-       }
-
-       lbs_deb_leave(LBS_DEB_HOST);
-}
-
-/*
- *  This function inserts command node to cmdfreeq
- *  after cleans it. Requires priv->driver_lock held.
- */
-static void __lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
-                                        struct cmd_ctrl_node *cmdnode)
-{
-       lbs_deb_enter(LBS_DEB_HOST);
-
-       if (!cmdnode)
-               goto out;
-
-       cmdnode->callback = NULL;
-       cmdnode->callback_arg = 0;
-
-       memset(cmdnode->cmdbuf, 0, LBS_CMD_BUFFER_SIZE);
-
-       list_add_tail(&cmdnode->list, &priv->cmdfreeq);
- out:
-       lbs_deb_leave(LBS_DEB_HOST);
-}
-
-static void lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
-       struct cmd_ctrl_node *ptempcmd)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&priv->driver_lock, flags);
-       __lbs_cleanup_and_insert_cmd(priv, ptempcmd);
-       spin_unlock_irqrestore(&priv->driver_lock, flags);
-}
-
-void __lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
-                           int result)
-{
-       /*
-        * Normally, commands are removed from cmdpendingq before being
-        * submitted. However, we can arrive here on alternative codepaths
-        * where the command is still pending. Make sure the command really
-        * isn't part of a list at this point.
-        */
-       list_del_init(&cmd->list);
-
-       cmd->result = result;
-       cmd->cmdwaitqwoken = 1;
-       wake_up(&cmd->cmdwait_q);
-
-       if (!cmd->callback || cmd->callback == lbs_cmd_async_callback)
-               __lbs_cleanup_and_insert_cmd(priv, cmd);
-       priv->cur_cmd = NULL;
-       wake_up(&priv->waitq);
-}
-
-void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
-                         int result)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&priv->driver_lock, flags);
-       __lbs_complete_command(priv, cmd, result);
-       spin_unlock_irqrestore(&priv->driver_lock, flags);
-}
-
-int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on)
-{
-       struct cmd_ds_802_11_radio_control cmd;
-       int ret = -EINVAL;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-       cmd.action = cpu_to_le16(CMD_ACT_SET);
-       cmd.control = 0;
-
-       /* Only v8 and below support setting the preamble */
-       if (priv->fwrelease < 0x09000000) {
-               switch (preamble) {
-               case RADIO_PREAMBLE_SHORT:
-               case RADIO_PREAMBLE_AUTO:
-               case RADIO_PREAMBLE_LONG:
-                       cmd.control = cpu_to_le16(preamble);
-                       break;
-               default:
-                       goto out;
-               }
-       }
-
-       if (radio_on)
-               cmd.control |= cpu_to_le16(0x1);
-       else {
-               cmd.control &= cpu_to_le16(~0x1);
-               priv->txpower_cur = 0;
-       }
-
-       lbs_deb_cmd("RADIO_CONTROL: radio %s, preamble %d\n",
-                   radio_on ? "ON" : "OFF", preamble);
-
-       priv->radio_on = radio_on;
-
-       ret = lbs_cmd_with_response(priv, CMD_802_11_RADIO_CONTROL, &cmd);
-
-out:
-       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
-       return ret;
-}
-
-void lbs_set_mac_control(struct lbs_private *priv)
-{
-       struct cmd_ds_mac_control cmd;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-       cmd.action = cpu_to_le16(priv->mac_control);
-       cmd.reserved = 0;
-
-       lbs_cmd_async(priv, CMD_MAC_CONTROL, &cmd.hdr, sizeof(cmd));
-
-       lbs_deb_leave(LBS_DEB_CMD);
-}
-
-int lbs_set_mac_control_sync(struct lbs_private *priv)
-{
-       struct cmd_ds_mac_control cmd;
-       int ret = 0;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-       cmd.action = cpu_to_le16(priv->mac_control);
-       cmd.reserved = 0;
-       ret = lbs_cmd_with_response(priv, CMD_MAC_CONTROL, &cmd);
-
-       lbs_deb_leave(LBS_DEB_CMD);
-       return ret;
-}
-
-/**
- *  lbs_allocate_cmd_buffer - allocates the command buffer and links
- *  it to command free queue
- *
- *  @priv:     A pointer to &struct lbs_private structure
- *
- *  returns:   0 for success or -1 on error
- */
-int lbs_allocate_cmd_buffer(struct lbs_private *priv)
-{
-       int ret = 0;
-       u32 bufsize;
-       u32 i;
-       struct cmd_ctrl_node *cmdarray;
-
-       lbs_deb_enter(LBS_DEB_HOST);
-
-       /* Allocate and initialize the command array */
-       bufsize = sizeof(struct cmd_ctrl_node) * LBS_NUM_CMD_BUFFERS;
-       if (!(cmdarray = kzalloc(bufsize, GFP_KERNEL))) {
-               lbs_deb_host("ALLOC_CMD_BUF: tempcmd_array is NULL\n");
-               ret = -1;
-               goto done;
-       }
-       priv->cmd_array = cmdarray;
-
-       /* Allocate and initialize each command buffer in the command array */
-       for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
-               cmdarray[i].cmdbuf = kzalloc(LBS_CMD_BUFFER_SIZE, GFP_KERNEL);
-               if (!cmdarray[i].cmdbuf) {
-                       lbs_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n");
-                       ret = -1;
-                       goto done;
-               }
-       }
-
-       for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
-               init_waitqueue_head(&cmdarray[i].cmdwait_q);
-               lbs_cleanup_and_insert_cmd(priv, &cmdarray[i]);
-       }
-       ret = 0;
-
-done:
-       lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
-       return ret;
-}
-
-/**
- *  lbs_free_cmd_buffer - free the command buffer
- *
- *  @priv:     A pointer to &struct lbs_private structure
- *
- *  returns:   0 for success
- */
-int lbs_free_cmd_buffer(struct lbs_private *priv)
-{
-       struct cmd_ctrl_node *cmdarray;
-       unsigned int i;
-
-       lbs_deb_enter(LBS_DEB_HOST);
-
-       /* need to check if cmd array is allocated or not */
-       if (priv->cmd_array == NULL) {
-               lbs_deb_host("FREE_CMD_BUF: cmd_array is NULL\n");
-               goto done;
-       }
-
-       cmdarray = priv->cmd_array;
-
-       /* Release shared memory buffers */
-       for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
-               if (cmdarray[i].cmdbuf) {
-                       kfree(cmdarray[i].cmdbuf);
-                       cmdarray[i].cmdbuf = NULL;
-               }
-       }
-
-       /* Release cmd_ctrl_node */
-       if (priv->cmd_array) {
-               kfree(priv->cmd_array);
-               priv->cmd_array = NULL;
-       }
-
-done:
-       lbs_deb_leave(LBS_DEB_HOST);
-       return 0;
-}
-
-/**
- *  lbs_get_free_cmd_node - gets a free command node if available in
- *  command free queue
- *
- *  @priv:     A pointer to &struct lbs_private structure
- *
- *  returns:   A pointer to &cmd_ctrl_node structure on success
- *             or %NULL on error
- */
-static struct cmd_ctrl_node *lbs_get_free_cmd_node(struct lbs_private *priv)
-{
-       struct cmd_ctrl_node *tempnode;
-       unsigned long flags;
-
-       lbs_deb_enter(LBS_DEB_HOST);
-
-       if (!priv)
-               return NULL;
-
-       spin_lock_irqsave(&priv->driver_lock, flags);
-
-       if (!list_empty(&priv->cmdfreeq)) {
-               tempnode = list_first_entry(&priv->cmdfreeq,
-                                           struct cmd_ctrl_node, list);
-               list_del_init(&tempnode->list);
-       } else {
-               lbs_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n");
-               tempnode = NULL;
-       }
-
-       spin_unlock_irqrestore(&priv->driver_lock, flags);
-
-       lbs_deb_leave(LBS_DEB_HOST);
-       return tempnode;
-}
-
-/**
- *  lbs_execute_next_command - execute next command in command
- *  pending queue. Will put firmware back to PS mode if applicable.
- *
- *  @priv:     A pointer to &struct lbs_private structure
- *
- *  returns:   0 on success or -1 on error
- */
-int lbs_execute_next_command(struct lbs_private *priv)
-{
-       struct cmd_ctrl_node *cmdnode = NULL;
-       struct cmd_header *cmd;
-       unsigned long flags;
-       int ret = 0;
-
-       /* Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the
-        * only caller to us is lbs_thread() and we get even when a
-        * data packet is received */
-       lbs_deb_enter(LBS_DEB_THREAD);
-
-       spin_lock_irqsave(&priv->driver_lock, flags);
-
-       if (priv->cur_cmd) {
-               netdev_alert(priv->dev,
-                            "EXEC_NEXT_CMD: already processing command!\n");
-               spin_unlock_irqrestore(&priv->driver_lock, flags);
-               ret = -1;
-               goto done;
-       }
-
-       if (!list_empty(&priv->cmdpendingq)) {
-               cmdnode = list_first_entry(&priv->cmdpendingq,
-                                          struct cmd_ctrl_node, list);
-       }
-
-       spin_unlock_irqrestore(&priv->driver_lock, flags);
-
-       if (cmdnode) {
-               cmd = cmdnode->cmdbuf;
-
-               if (is_command_allowed_in_ps(le16_to_cpu(cmd->command))) {
-                       if ((priv->psstate == PS_STATE_SLEEP) ||
-                           (priv->psstate == PS_STATE_PRE_SLEEP)) {
-                               lbs_deb_host(
-                                      "EXEC_NEXT_CMD: cannot send cmd 0x%04x in psstate %d\n",
-                                      le16_to_cpu(cmd->command),
-                                      priv->psstate);
-                               ret = -1;
-                               goto done;
-                       }
-                       lbs_deb_host("EXEC_NEXT_CMD: OK to send command "
-                                    "0x%04x in psstate %d\n",
-                                    le16_to_cpu(cmd->command), priv->psstate);
-               } else if (priv->psstate != PS_STATE_FULL_POWER) {
-                       /*
-                        * 1. Non-PS command:
-                        * Queue it. set needtowakeup to TRUE if current state
-                        * is SLEEP, otherwise call send EXIT_PS.
-                        * 2. PS command but not EXIT_PS:
-                        * Ignore it.
-                        * 3. PS command EXIT_PS:
-                        * Set needtowakeup to TRUE if current state is SLEEP,
-                        * otherwise send this command down to firmware
-                        * immediately.
-                        */
-                       if (cmd->command != cpu_to_le16(CMD_802_11_PS_MODE)) {
-                               /*  Prepare to send Exit PS,
-                                *  this non PS command will be sent later */
-                               if ((priv->psstate == PS_STATE_SLEEP)
-                                   || (priv->psstate == PS_STATE_PRE_SLEEP)
-                                   ) {
-                                       /* w/ new scheme, it will not reach here.
-                                          since it is blocked in main_thread. */
-                                       priv->needtowakeup = 1;
-                               } else {
-                                       lbs_set_ps_mode(priv,
-                                                       PS_MODE_ACTION_EXIT_PS,
-                                                       false);
-                               }
-
-                               ret = 0;
-                               goto done;
-                       } else {
-                               /*
-                                * PS command. Ignore it if it is not Exit_PS.
-                                * otherwise send it down immediately.
-                                */
-                               struct cmd_ds_802_11_ps_mode *psm = (void *)&cmd[1];
-
-                               lbs_deb_host(
-                                      "EXEC_NEXT_CMD: PS cmd, action 0x%02x\n",
-                                      psm->action);
-                               if (psm->action !=
-                                   cpu_to_le16(PS_MODE_ACTION_EXIT_PS)) {
-                                       lbs_deb_host(
-                                              "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");
-                                       lbs_complete_command(priv, cmdnode, 0);
-
-                                       ret = 0;
-                                       goto done;
-                               }
-
-                               if ((priv->psstate == PS_STATE_SLEEP) ||
-                                   (priv->psstate == PS_STATE_PRE_SLEEP)) {
-                                       lbs_deb_host(
-                                              "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n");
-                                       lbs_complete_command(priv, cmdnode, 0);
-                                       priv->needtowakeup = 1;
-
-                                       ret = 0;
-                                       goto done;
-                               }
-
-                               lbs_deb_host(
-                                      "EXEC_NEXT_CMD: sending EXIT_PS\n");
-                       }
-               }
-               spin_lock_irqsave(&priv->driver_lock, flags);
-               list_del_init(&cmdnode->list);
-               spin_unlock_irqrestore(&priv->driver_lock, flags);
-               lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n",
-                           le16_to_cpu(cmd->command));
-               lbs_submit_command(priv, cmdnode);
-       } else {
-               /*
-                * check if in power save mode, if yes, put the device back
-                * to PS mode
-                */
-#ifdef TODO
-               /*
-                * This was the old code for libertas+wext. Someone that
-                * understands this beast should re-code it in a sane way.
-                *
-                * I actually don't understand why this is related to WPA
-                * and to connection status, shouldn't powering should be
-                * independ of such things?
-                */
-               if ((priv->psmode != LBS802_11POWERMODECAM) &&
-                   (priv->psstate == PS_STATE_FULL_POWER) &&
-                   ((priv->connect_status == LBS_CONNECTED) ||
-                   lbs_mesh_connected(priv))) {
-                       if (priv->secinfo.WPAenabled ||
-                           priv->secinfo.WPA2enabled) {
-                               /* check for valid WPA group keys */
-                               if (priv->wpa_mcast_key.len ||
-                                   priv->wpa_unicast_key.len) {
-                                       lbs_deb_host(
-                                              "EXEC_NEXT_CMD: WPA enabled and GTK_SET"
-                                              " go back to PS_SLEEP");
-                                       lbs_set_ps_mode(priv,
-                                                       PS_MODE_ACTION_ENTER_PS,
-                                                       false);
-                               }
-                       } else {
-                               lbs_deb_host(
-                                      "EXEC_NEXT_CMD: cmdpendingq empty, "
-                                      "go back to PS_SLEEP");
-                               lbs_set_ps_mode(priv, PS_MODE_ACTION_ENTER_PS,
-                                               false);
-                       }
-               }
-#endif
-       }
-
-       ret = 0;
-done:
-       lbs_deb_leave(LBS_DEB_THREAD);
-       return ret;
-}
-
-static void lbs_send_confirmsleep(struct lbs_private *priv)
-{
-       unsigned long flags;
-       int ret;
-
-       lbs_deb_enter(LBS_DEB_HOST);
-       lbs_deb_hex(LBS_DEB_HOST, "sleep confirm", (u8 *) &confirm_sleep,
-               sizeof(confirm_sleep));
-
-       ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &confirm_sleep,
-               sizeof(confirm_sleep));
-       if (ret) {
-               netdev_alert(priv->dev, "confirm_sleep failed\n");
-               goto out;
-       }
-
-       spin_lock_irqsave(&priv->driver_lock, flags);
-
-       /* We don't get a response on the sleep-confirmation */
-       priv->dnld_sent = DNLD_RES_RECEIVED;
-
-       if (priv->is_host_sleep_configured) {
-               priv->is_host_sleep_activated = 1;
-               wake_up_interruptible(&priv->host_sleep_q);
-       }
-
-       /* If nothing to do, go back to sleep (?) */
-       if (!kfifo_len(&priv->event_fifo) && !priv->resp_len[priv->resp_idx])
-               priv->psstate = PS_STATE_SLEEP;
-
-       spin_unlock_irqrestore(&priv->driver_lock, flags);
-
-out:
-       lbs_deb_leave(LBS_DEB_HOST);
-}
-
-/**
- * lbs_ps_confirm_sleep - checks condition and prepares to
- * send sleep confirm command to firmware if ok
- *
- * @priv:      A pointer to &struct lbs_private structure
- *
- * returns:    n/a
- */
-void lbs_ps_confirm_sleep(struct lbs_private *priv)
-{
-       unsigned long flags =0;
-       int allowed = 1;
-
-       lbs_deb_enter(LBS_DEB_HOST);
-
-       spin_lock_irqsave(&priv->driver_lock, flags);
-       if (priv->dnld_sent) {
-               allowed = 0;
-               lbs_deb_host("dnld_sent was set\n");
-       }
-
-       /* In-progress command? */
-       if (priv->cur_cmd) {
-               allowed = 0;
-               lbs_deb_host("cur_cmd was set\n");
-       }
-
-       /* Pending events or command responses? */
-       if (kfifo_len(&priv->event_fifo) || priv->resp_len[priv->resp_idx]) {
-               allowed = 0;
-               lbs_deb_host("pending events or command responses\n");
-       }
-       spin_unlock_irqrestore(&priv->driver_lock, flags);
-
-       if (allowed) {
-               lbs_deb_host("sending lbs_ps_confirm_sleep\n");
-               lbs_send_confirmsleep(priv);
-       } else {
-               lbs_deb_host("sleep confirm has been delayed\n");
-       }
-
-       lbs_deb_leave(LBS_DEB_HOST);
-}
-
-
-/**
- * lbs_set_tpc_cfg - Configures the transmission power control functionality
- *
- * @priv:      A pointer to &struct lbs_private structure
- * @enable:    Transmission power control enable
- * @p0:                Power level when link quality is good (dBm).
- * @p1:                Power level when link quality is fair (dBm).
- * @p2:                Power level when link quality is poor (dBm).
- * @usesnr:    Use Signal to Noise Ratio in TPC
- *
- * returns:    0 on success
- */
-int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1,
-               int8_t p2, int usesnr)
-{
-       struct cmd_ds_802_11_tpc_cfg cmd;
-       int ret;
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-       cmd.action = cpu_to_le16(CMD_ACT_SET);
-       cmd.enable = !!enable;
-       cmd.usesnr = !!usesnr;
-       cmd.P0 = p0;
-       cmd.P1 = p1;
-       cmd.P2 = p2;
-
-       ret = lbs_cmd_with_response(priv, CMD_802_11_TPC_CFG, &cmd);
-
-       return ret;
-}
-
-/**
- * lbs_set_power_adapt_cfg - Configures the power adaptation settings
- *
- * @priv:      A pointer to &struct lbs_private structure
- * @enable:    Power adaptation enable
- * @p0:                Power level for 1, 2, 5.5 and 11 Mbps (dBm).
- * @p1:                Power level for 6, 9, 12, 18, 22, 24 and 36 Mbps (dBm).
- * @p2:                Power level for 48 and 54 Mbps (dBm).
- *
- * returns:    0 on Success
- */
-
-int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
-               int8_t p1, int8_t p2)
-{
-       struct cmd_ds_802_11_pa_cfg cmd;
-       int ret;
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-       cmd.action = cpu_to_le16(CMD_ACT_SET);
-       cmd.enable = !!enable;
-       cmd.P0 = p0;
-       cmd.P1 = p1;
-       cmd.P2 = p2;
-
-       ret = lbs_cmd_with_response(priv, CMD_802_11_PA_CFG , &cmd);
-
-       return ret;
-}
-
-
-struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
-       uint16_t command, struct cmd_header *in_cmd, int in_cmd_size,
-       int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
-       unsigned long callback_arg)
-{
-       struct cmd_ctrl_node *cmdnode;
-
-       lbs_deb_enter(LBS_DEB_HOST);
-
-       if (priv->surpriseremoved) {
-               lbs_deb_host("PREP_CMD: card removed\n");
-               cmdnode = ERR_PTR(-ENOENT);
-               goto done;
-       }
-
-       /* No commands are allowed in Deep Sleep until we toggle the GPIO
-        * to wake up the card and it has signaled that it's ready.
-        */
-       if (!priv->is_auto_deep_sleep_enabled) {
-               if (priv->is_deep_sleep) {
-                       lbs_deb_cmd("command not allowed in deep sleep\n");
-                       cmdnode = ERR_PTR(-EBUSY);
-                       goto done;
-               }
-       }
-
-       cmdnode = lbs_get_free_cmd_node(priv);
-       if (cmdnode == NULL) {
-               lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
-
-               /* Wake up main thread to execute next command */
-               wake_up(&priv->waitq);
-               cmdnode = ERR_PTR(-ENOBUFS);
-               goto done;
-       }
-
-       cmdnode->callback = callback;
-       cmdnode->callback_arg = callback_arg;
-
-       /* Copy the incoming command to the buffer */
-       memcpy(cmdnode->cmdbuf, in_cmd, in_cmd_size);
-
-       /* Set command, clean result, move to buffer */
-       cmdnode->cmdbuf->command = cpu_to_le16(command);
-       cmdnode->cmdbuf->size    = cpu_to_le16(in_cmd_size);
-       cmdnode->cmdbuf->result  = 0;
-
-       lbs_deb_host("PREP_CMD: command 0x%04x\n", command);
-
-       cmdnode->cmdwaitqwoken = 0;
-       lbs_queue_cmd(priv, cmdnode);
-       wake_up(&priv->waitq);
-
- done:
-       lbs_deb_leave_args(LBS_DEB_HOST, "ret %p", cmdnode);
-       return cmdnode;
-}
-
-void lbs_cmd_async(struct lbs_private *priv, uint16_t command,
-       struct cmd_header *in_cmd, int in_cmd_size)
-{
-       lbs_deb_enter(LBS_DEB_CMD);
-       __lbs_cmd_async(priv, command, in_cmd, in_cmd_size,
-               lbs_cmd_async_callback, 0);
-       lbs_deb_leave(LBS_DEB_CMD);
-}
-
-int __lbs_cmd(struct lbs_private *priv, uint16_t command,
-             struct cmd_header *in_cmd, int in_cmd_size,
-             int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
-             unsigned long callback_arg)
-{
-       struct cmd_ctrl_node *cmdnode;
-       unsigned long flags;
-       int ret = 0;
-
-       lbs_deb_enter(LBS_DEB_HOST);
-
-       cmdnode = __lbs_cmd_async(priv, command, in_cmd, in_cmd_size,
-                                 callback, callback_arg);
-       if (IS_ERR(cmdnode)) {
-               ret = PTR_ERR(cmdnode);
-               goto done;
-       }
-
-       might_sleep();
-
-       /*
-        * Be careful with signals here. A signal may be received as the system
-        * goes into suspend or resume. We do not want this to interrupt the
-        * command, so we perform an uninterruptible sleep.
-        */
-       wait_event(cmdnode->cmdwait_q, cmdnode->cmdwaitqwoken);
-
-       spin_lock_irqsave(&priv->driver_lock, flags);
-       ret = cmdnode->result;
-       if (ret)
-               netdev_info(priv->dev, "PREP_CMD: command 0x%04x failed: %d\n",
-                           command, ret);
-
-       __lbs_cleanup_and_insert_cmd(priv, cmdnode);
-       spin_unlock_irqrestore(&priv->driver_lock, flags);
-
-done:
-       lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(__lbs_cmd);
diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h
deleted file mode 100644 (file)
index 0c5444b..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/* Copyright (C) 2007, Red Hat, Inc. */
-
-#ifndef _LBS_CMD_H_
-#define _LBS_CMD_H_
-
-#include <net/cfg80211.h>
-
-#include "host.h"
-#include "dev.h"
-
-
-/* Command & response transfer between host and card */
-
-struct cmd_ctrl_node {
-       struct list_head list;
-       int result;
-       /* command response */
-       int (*callback)(struct lbs_private *,
-                       unsigned long,
-                       struct cmd_header *);
-       unsigned long callback_arg;
-       /* command data */
-       struct cmd_header *cmdbuf;
-       /* wait queue */
-       u16 cmdwaitqwoken;
-       wait_queue_head_t cmdwait_q;
-};
-
-
-/* lbs_cmd() infers the size of the buffer to copy data back into, from
-   the size of the target of the pointer. Since the command to be sent
-   may often be smaller, that size is set in cmd->size by the caller.*/
-#define lbs_cmd(priv, cmdnr, cmd, cb, cb_arg)  ({              \
-       uint16_t __sz = le16_to_cpu((cmd)->hdr.size);           \
-       (cmd)->hdr.size = cpu_to_le16(sizeof(*(cmd)));          \
-       __lbs_cmd(priv, cmdnr, &(cmd)->hdr, __sz, cb, cb_arg);  \
-})
-
-#define lbs_cmd_with_response(priv, cmdnr, cmd)        \
-       lbs_cmd(priv, cmdnr, cmd, lbs_cmd_copyback, (unsigned long) (cmd))
-
-void lbs_cmd_async(struct lbs_private *priv, uint16_t command,
-       struct cmd_header *in_cmd, int in_cmd_size);
-
-int __lbs_cmd(struct lbs_private *priv, uint16_t command,
-             struct cmd_header *in_cmd, int in_cmd_size,
-             int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
-             unsigned long callback_arg);
-
-struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
-       uint16_t command, struct cmd_header *in_cmd, int in_cmd_size,
-       int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
-       unsigned long callback_arg);
-
-int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra,
-                    struct cmd_header *resp);
-
-int lbs_allocate_cmd_buffer(struct lbs_private *priv);
-int lbs_free_cmd_buffer(struct lbs_private *priv);
-
-int lbs_execute_next_command(struct lbs_private *priv);
-void __lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
-                           int result);
-void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
-                         int result);
-int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len);
-
-
-/* From cmdresp.c */
-
-void lbs_mac_event_disconnected(struct lbs_private *priv,
-                               bool locally_generated);
-
-
-
-/* Events */
-
-int lbs_process_event(struct lbs_private *priv, u32 event);
-
-
-/* Actual commands */
-
-int lbs_update_hw_spec(struct lbs_private *priv);
-
-int lbs_set_channel(struct lbs_private *priv, u8 channel);
-
-int lbs_update_channel(struct lbs_private *priv);
-
-int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
-               struct wol_config *p_wol_config);
-
-int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
-                               struct sleep_params *sp);
-
-void lbs_ps_confirm_sleep(struct lbs_private *priv);
-
-int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on);
-
-void lbs_set_mac_control(struct lbs_private *priv);
-int lbs_set_mac_control_sync(struct lbs_private *priv);
-
-int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel,
-                    s16 *maxlevel);
-
-int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val);
-
-int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val);
-
-
-/* Commands only used in wext.c, assoc. and scan.c */
-
-int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
-               int8_t p1, int8_t p2);
-
-int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1,
-               int8_t p2, int usesnr);
-
-int lbs_set_data_rate(struct lbs_private *priv, u8 rate);
-
-int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
-                                     uint16_t cmd_action);
-
-int lbs_set_tx_power(struct lbs_private *priv, s16 dbm);
-
-int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep);
-
-int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep);
-
-int lbs_set_monitor_mode(struct lbs_private *priv, int enable);
-
-int lbs_get_rssi(struct lbs_private *priv, s8 *snr, s8 *nf);
-
-int lbs_set_11d_domain_info(struct lbs_private *priv);
-
-int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value);
-
-int lbs_set_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 value);
-
-int lbs_set_ps_mode(struct lbs_private *priv, u16 cmd_action, bool block);
-
-#endif /* _LBS_CMD_H */
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
deleted file mode 100644 (file)
index e5442e8..0000000
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
- * This file contains the handling of command
- * responses as well as events generated by firmware.
- */
-
-#include <linux/hardirq.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <asm/unaligned.h>
-#include <net/cfg80211.h>
-
-#include "cfg.h"
-#include "cmd.h"
-
-/**
- * lbs_mac_event_disconnected - handles disconnect event. It
- * reports disconnect to upper layer, clean tx/rx packets,
- * reset link state etc.
- *
- * @priv:      A pointer to struct lbs_private structure
- * @locally_generated: indicates disconnect was requested locally
- *             (usually by userspace)
- *
- * returns:    n/a
- */
-void lbs_mac_event_disconnected(struct lbs_private *priv,
-                               bool locally_generated)
-{
-       if (priv->connect_status != LBS_CONNECTED)
-               return;
-
-       lbs_deb_enter(LBS_DEB_ASSOC);
-
-       /*
-        * Cisco AP sends EAP failure and de-auth in less than 0.5 ms.
-        * It causes problem in the Supplicant
-        */
-       msleep_interruptible(1000);
-
-       if (priv->wdev->iftype == NL80211_IFTYPE_STATION)
-               lbs_send_disconnect_notification(priv, locally_generated);
-
-       /* report disconnect to upper layer */
-       netif_stop_queue(priv->dev);
-       netif_carrier_off(priv->dev);
-
-       /* Free Tx and Rx packets */
-       kfree_skb(priv->currenttxskb);
-       priv->currenttxskb = NULL;
-       priv->tx_pending_len = 0;
-
-       priv->connect_status = LBS_DISCONNECTED;
-
-       if (priv->psstate != PS_STATE_FULL_POWER) {
-               /* make firmware to exit PS mode */
-               lbs_deb_cmd("disconnected, so exit PS mode\n");
-               lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS, false);
-       }
-       lbs_deb_leave(LBS_DEB_ASSOC);
-}
-
-int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
-{
-       uint16_t respcmd, curcmd;
-       struct cmd_header *resp;
-       int ret = 0;
-       unsigned long flags;
-       uint16_t result;
-
-       lbs_deb_enter(LBS_DEB_HOST);
-
-       mutex_lock(&priv->lock);
-       spin_lock_irqsave(&priv->driver_lock, flags);
-
-       if (!priv->cur_cmd) {
-               lbs_deb_host("CMD_RESP: cur_cmd is NULL\n");
-               ret = -1;
-               spin_unlock_irqrestore(&priv->driver_lock, flags);
-               goto done;
-       }
-
-       resp = (void *)data;
-       curcmd = le16_to_cpu(priv->cur_cmd->cmdbuf->command);
-       respcmd = le16_to_cpu(resp->command);
-       result = le16_to_cpu(resp->result);
-
-       lbs_deb_cmd("CMD_RESP: response 0x%04x, seq %d, size %d\n",
-                    respcmd, le16_to_cpu(resp->seqnum), len);
-       lbs_deb_hex(LBS_DEB_CMD, "CMD_RESP", (void *) resp, len);
-
-       if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) {
-               netdev_info(priv->dev,
-                           "Received CMD_RESP with invalid sequence %d (expected %d)\n",
-                           le16_to_cpu(resp->seqnum),
-                           le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum));
-               spin_unlock_irqrestore(&priv->driver_lock, flags);
-               ret = -1;
-               goto done;
-       }
-       if (respcmd != CMD_RET(curcmd) &&
-           respcmd != CMD_RET_802_11_ASSOCIATE && curcmd != CMD_802_11_ASSOCIATE) {
-               netdev_info(priv->dev, "Invalid CMD_RESP %x to command %x!\n",
-                           respcmd, curcmd);
-               spin_unlock_irqrestore(&priv->driver_lock, flags);
-               ret = -1;
-               goto done;
-       }
-
-       if (resp->result == cpu_to_le16(0x0004)) {
-               /* 0x0004 means -EAGAIN. Drop the response, let it time out
-                  and be resubmitted */
-               netdev_info(priv->dev,
-                           "Firmware returns DEFER to command %x. Will let it time out...\n",
-                           le16_to_cpu(resp->command));
-               spin_unlock_irqrestore(&priv->driver_lock, flags);
-               ret = -1;
-               goto done;
-       }
-
-       /* Now we got response from FW, cancel the command timer */
-       del_timer(&priv->command_timer);
-       priv->cmd_timed_out = 0;
-
-       if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) {
-               struct cmd_ds_802_11_ps_mode *psmode = (void *) &resp[1];
-               u16 action = le16_to_cpu(psmode->action);
-
-               lbs_deb_host(
-                      "CMD_RESP: PS_MODE cmd reply result 0x%x, action 0x%x\n",
-                      result, action);
-
-               if (result) {
-                       lbs_deb_host("CMD_RESP: PS command failed with 0x%x\n",
-                                   result);
-                       /*
-                        * We should not re-try enter-ps command in
-                        * ad-hoc mode. It takes place in
-                        * lbs_execute_next_command().
-                        */
-                       if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR &&
-                           action == PS_MODE_ACTION_ENTER_PS)
-                               priv->psmode = LBS802_11POWERMODECAM;
-               } else if (action == PS_MODE_ACTION_ENTER_PS) {
-                       priv->needtowakeup = 0;
-                       priv->psstate = PS_STATE_AWAKE;
-
-                       lbs_deb_host("CMD_RESP: ENTER_PS command response\n");
-                       if (priv->connect_status != LBS_CONNECTED) {
-                               /*
-                                * When Deauth Event received before Enter_PS command
-                                * response, We need to wake up the firmware.
-                                */
-                               lbs_deb_host(
-                                      "disconnected, invoking lbs_ps_wakeup\n");
-
-                               spin_unlock_irqrestore(&priv->driver_lock, flags);
-                               mutex_unlock(&priv->lock);
-                               lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS,
-                                               false);
-                               mutex_lock(&priv->lock);
-                               spin_lock_irqsave(&priv->driver_lock, flags);
-                       }
-               } else if (action == PS_MODE_ACTION_EXIT_PS) {
-                       priv->needtowakeup = 0;
-                       priv->psstate = PS_STATE_FULL_POWER;
-                       lbs_deb_host("CMD_RESP: EXIT_PS command response\n");
-               } else {
-                       lbs_deb_host("CMD_RESP: PS action 0x%X\n", action);
-               }
-
-               __lbs_complete_command(priv, priv->cur_cmd, result);
-               spin_unlock_irqrestore(&priv->driver_lock, flags);
-
-               ret = 0;
-               goto done;
-       }
-
-       /* If the command is not successful, cleanup and return failure */
-       if ((result != 0 || !(respcmd & 0x8000))) {
-               lbs_deb_host("CMD_RESP: error 0x%04x in command reply 0x%04x\n",
-                      result, respcmd);
-               /*
-                * Handling errors here
-                */
-               switch (respcmd) {
-               case CMD_RET(CMD_GET_HW_SPEC):
-               case CMD_RET(CMD_802_11_RESET):
-                       lbs_deb_host("CMD_RESP: reset failed\n");
-                       break;
-
-               }
-               __lbs_complete_command(priv, priv->cur_cmd, result);
-               spin_unlock_irqrestore(&priv->driver_lock, flags);
-
-               ret = -1;
-               goto done;
-       }
-
-       spin_unlock_irqrestore(&priv->driver_lock, flags);
-
-       if (priv->cur_cmd && priv->cur_cmd->callback) {
-               ret = priv->cur_cmd->callback(priv, priv->cur_cmd->callback_arg,
-                               resp);
-       }
-
-       spin_lock_irqsave(&priv->driver_lock, flags);
-
-       if (priv->cur_cmd) {
-               /* Clean up and Put current command back to cmdfreeq */
-               __lbs_complete_command(priv, priv->cur_cmd, result);
-       }
-       spin_unlock_irqrestore(&priv->driver_lock, flags);
-
-done:
-       mutex_unlock(&priv->lock);
-       lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
-       return ret;
-}
-
-int lbs_process_event(struct lbs_private *priv, u32 event)
-{
-       int ret = 0;
-       struct cmd_header cmd;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       switch (event) {
-       case MACREG_INT_CODE_LINK_SENSED:
-               lbs_deb_cmd("EVENT: link sensed\n");
-               break;
-
-       case MACREG_INT_CODE_DEAUTHENTICATED:
-               lbs_deb_cmd("EVENT: deauthenticated\n");
-               lbs_mac_event_disconnected(priv, false);
-               break;
-
-       case MACREG_INT_CODE_DISASSOCIATED:
-               lbs_deb_cmd("EVENT: disassociated\n");
-               lbs_mac_event_disconnected(priv, false);
-               break;
-
-       case MACREG_INT_CODE_LINK_LOST_NO_SCAN:
-               lbs_deb_cmd("EVENT: link lost\n");
-               lbs_mac_event_disconnected(priv, true);
-               break;
-
-       case MACREG_INT_CODE_PS_SLEEP:
-               lbs_deb_cmd("EVENT: ps sleep\n");
-
-               /* handle unexpected PS SLEEP event */
-               if (priv->psstate == PS_STATE_FULL_POWER) {
-                       lbs_deb_cmd(
-                              "EVENT: in FULL POWER mode, ignoring PS_SLEEP\n");
-                       break;
-               }
-               priv->psstate = PS_STATE_PRE_SLEEP;
-
-               lbs_ps_confirm_sleep(priv);
-
-               break;
-
-       case MACREG_INT_CODE_HOST_AWAKE:
-               lbs_deb_cmd("EVENT: host awake\n");
-               if (priv->reset_deep_sleep_wakeup)
-                       priv->reset_deep_sleep_wakeup(priv);
-               priv->is_deep_sleep = 0;
-               lbs_cmd_async(priv, CMD_802_11_WAKEUP_CONFIRM, &cmd,
-                               sizeof(cmd));
-               priv->is_host_sleep_activated = 0;
-               wake_up_interruptible(&priv->host_sleep_q);
-               break;
-
-       case MACREG_INT_CODE_DEEP_SLEEP_AWAKE:
-               if (priv->reset_deep_sleep_wakeup)
-                       priv->reset_deep_sleep_wakeup(priv);
-               lbs_deb_cmd("EVENT: ds awake\n");
-               priv->is_deep_sleep = 0;
-               priv->wakeup_dev_required = 0;
-               wake_up_interruptible(&priv->ds_awake_q);
-               break;
-
-       case MACREG_INT_CODE_PS_AWAKE:
-               lbs_deb_cmd("EVENT: ps awake\n");
-               /* handle unexpected PS AWAKE event */
-               if (priv->psstate == PS_STATE_FULL_POWER) {
-                       lbs_deb_cmd(
-                              "EVENT: In FULL POWER mode - ignore PS AWAKE\n");
-                       break;
-               }
-
-               priv->psstate = PS_STATE_AWAKE;
-
-               if (priv->needtowakeup) {
-                       /*
-                        * wait for the command processing to finish
-                        * before resuming sending
-                        * priv->needtowakeup will be set to FALSE
-                        * in lbs_ps_wakeup()
-                        */
-                       lbs_deb_cmd("waking up ...\n");
-                       lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS, false);
-               }
-               break;
-
-       case MACREG_INT_CODE_MIC_ERR_UNICAST:
-               lbs_deb_cmd("EVENT: UNICAST MIC ERROR\n");
-               lbs_send_mic_failureevent(priv, event);
-               break;
-
-       case MACREG_INT_CODE_MIC_ERR_MULTICAST:
-               lbs_deb_cmd("EVENT: MULTICAST MIC ERROR\n");
-               lbs_send_mic_failureevent(priv, event);
-               break;
-
-       case MACREG_INT_CODE_MIB_CHANGED:
-               lbs_deb_cmd("EVENT: MIB CHANGED\n");
-               break;
-       case MACREG_INT_CODE_INIT_DONE:
-               lbs_deb_cmd("EVENT: INIT DONE\n");
-               break;
-       case MACREG_INT_CODE_ADHOC_BCN_LOST:
-               lbs_deb_cmd("EVENT: ADHOC beacon lost\n");
-               break;
-       case MACREG_INT_CODE_RSSI_LOW:
-               netdev_alert(priv->dev, "EVENT: rssi low\n");
-               break;
-       case MACREG_INT_CODE_SNR_LOW:
-               netdev_alert(priv->dev, "EVENT: snr low\n");
-               break;
-       case MACREG_INT_CODE_MAX_FAIL:
-               netdev_alert(priv->dev, "EVENT: max fail\n");
-               break;
-       case MACREG_INT_CODE_RSSI_HIGH:
-               netdev_alert(priv->dev, "EVENT: rssi high\n");
-               break;
-       case MACREG_INT_CODE_SNR_HIGH:
-               netdev_alert(priv->dev, "EVENT: snr high\n");
-               break;
-
-       case MACREG_INT_CODE_MESH_AUTO_STARTED:
-               /* Ignore spurious autostart events */
-               netdev_info(priv->dev, "EVENT: MESH_AUTO_STARTED (ignoring)\n");
-               break;
-
-       default:
-               netdev_alert(priv->dev, "EVENT: unknown event id %d\n", event);
-               break;
-       }
-
-       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
-       return ret;
-}
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
deleted file mode 100644 (file)
index 26cbf1d..0000000
+++ /dev/null
@@ -1,989 +0,0 @@
-#include <linux/dcache.h>
-#include <linux/debugfs.h>
-#include <linux/delay.h>
-#include <linux/hardirq.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/export.h>
-
-#include "decl.h"
-#include "cmd.h"
-#include "debugfs.h"
-
-static struct dentry *lbs_dir;
-static char *szStates[] = {
-       "Connected",
-       "Disconnected"
-};
-
-#ifdef PROC_DEBUG
-static void lbs_debug_init(struct lbs_private *priv);
-#endif
-
-static ssize_t write_file_dummy(struct file *file, const char __user *buf,
-                                size_t count, loff_t *ppos)
-{
-        return -EINVAL;
-}
-
-static const size_t len = PAGE_SIZE;
-
-static ssize_t lbs_dev_info(struct file *file, char __user *userbuf,
-                                 size_t count, loff_t *ppos)
-{
-       struct lbs_private *priv = file->private_data;
-       size_t pos = 0;
-       unsigned long addr = get_zeroed_page(GFP_KERNEL);
-       char *buf = (char *)addr;
-       ssize_t res;
-       if (!buf)
-               return -ENOMEM;
-
-       pos += snprintf(buf+pos, len-pos, "state = %s\n",
-                               szStates[priv->connect_status]);
-       pos += snprintf(buf+pos, len-pos, "region_code = %02x\n",
-                               (u32) priv->regioncode);
-
-       res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
-
-       free_page(addr);
-       return res;
-}
-
-static ssize_t lbs_sleepparams_write(struct file *file,
-                               const char __user *user_buf, size_t count,
-                               loff_t *ppos)
-{
-       struct lbs_private *priv = file->private_data;
-       ssize_t buf_size, ret;
-       struct sleep_params sp;
-       int p1, p2, p3, p4, p5, p6;
-       unsigned long addr = get_zeroed_page(GFP_KERNEL);
-       char *buf = (char *)addr;
-       if (!buf)
-               return -ENOMEM;
-
-       buf_size = min(count, len - 1);
-       if (copy_from_user(buf, user_buf, buf_size)) {
-               ret = -EFAULT;
-               goto out_unlock;
-       }
-       ret = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6);
-       if (ret != 6) {
-               ret = -EINVAL;
-               goto out_unlock;
-       }
-       sp.sp_error = p1;
-       sp.sp_offset = p2;
-       sp.sp_stabletime = p3;
-       sp.sp_calcontrol = p4;
-       sp.sp_extsleepclk = p5;
-       sp.sp_reserved = p6;
-
-       ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_SET, &sp);
-       if (!ret)
-               ret = count;
-       else if (ret > 0)
-               ret = -EINVAL;
-
-out_unlock:
-       free_page(addr);
-       return ret;
-}
-
-static ssize_t lbs_sleepparams_read(struct file *file, char __user *userbuf,
-                                 size_t count, loff_t *ppos)
-{
-       struct lbs_private *priv = file->private_data;
-       ssize_t ret;
-       size_t pos = 0;
-       struct sleep_params sp;
-       unsigned long addr = get_zeroed_page(GFP_KERNEL);
-       char *buf = (char *)addr;
-       if (!buf)
-               return -ENOMEM;
-
-       ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_GET, &sp);
-       if (ret)
-               goto out_unlock;
-
-       pos += snprintf(buf, len, "%d %d %d %d %d %d\n", sp.sp_error,
-                       sp.sp_offset, sp.sp_stabletime,
-                       sp.sp_calcontrol, sp.sp_extsleepclk,
-                       sp.sp_reserved);
-
-       ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
-
-out_unlock:
-       free_page(addr);
-       return ret;
-}
-
-static ssize_t lbs_host_sleep_write(struct file *file,
-                               const char __user *user_buf, size_t count,
-                               loff_t *ppos)
-{
-       struct lbs_private *priv = file->private_data;
-       ssize_t buf_size, ret;
-       int host_sleep;
-       unsigned long addr = get_zeroed_page(GFP_KERNEL);
-       char *buf = (char *)addr;
-       if (!buf)
-               return -ENOMEM;
-
-       buf_size = min(count, len - 1);
-       if (copy_from_user(buf, user_buf, buf_size)) {
-               ret = -EFAULT;
-               goto out_unlock;
-       }
-       ret = sscanf(buf, "%d", &host_sleep);
-       if (ret != 1) {
-               ret = -EINVAL;
-               goto out_unlock;
-       }
-
-       if (host_sleep == 0)
-               ret = lbs_set_host_sleep(priv, 0);
-       else if (host_sleep == 1) {
-               if (priv->wol_criteria == EHS_REMOVE_WAKEUP) {
-                       netdev_info(priv->dev,
-                                   "wake parameters not configured\n");
-                       ret = -EINVAL;
-                       goto out_unlock;
-               }
-               ret = lbs_set_host_sleep(priv, 1);
-       } else {
-               netdev_err(priv->dev, "invalid option\n");
-               ret = -EINVAL;
-       }
-
-       if (!ret)
-               ret = count;
-
-out_unlock:
-       free_page(addr);
-       return ret;
-}
-
-static ssize_t lbs_host_sleep_read(struct file *file, char __user *userbuf,
-                                 size_t count, loff_t *ppos)
-{
-       struct lbs_private *priv = file->private_data;
-       ssize_t ret;
-       size_t pos = 0;
-       unsigned long addr = get_zeroed_page(GFP_KERNEL);
-       char *buf = (char *)addr;
-       if (!buf)
-               return -ENOMEM;
-
-       pos += snprintf(buf, len, "%d\n", priv->is_host_sleep_activated);
-
-       ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
-
-       free_page(addr);
-       return ret;
-}
-
-/*
- * When calling CMD_802_11_SUBSCRIBE_EVENT with CMD_ACT_GET, me might
- * get a bunch of vendor-specific TLVs (a.k.a. IEs) back from the
- * firmware. Here's an example:
- *     04 01 02 00 00 00 05 01 02 00 00 00 06 01 02 00
- *     00 00 07 01 02 00 3c 00 00 00 00 00 00 00 03 03
- *     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- *
- * The 04 01 is the TLV type (here TLV_TYPE_RSSI_LOW), 02 00 is the length,
- * 00 00 are the data bytes of this TLV. For this TLV, their meaning is
- * defined in mrvlietypes_thresholds
- *
- * This function searches in this TLV data chunk for a given TLV type
- * and returns a pointer to the first data byte of the TLV, or to NULL
- * if the TLV hasn't been found.
- */
-static void *lbs_tlv_find(uint16_t tlv_type, const uint8_t *tlv, uint16_t size)
-{
-       struct mrvl_ie_header *tlv_h;
-       uint16_t length;
-       ssize_t pos = 0;
-
-       while (pos < size) {
-               tlv_h = (struct mrvl_ie_header *) tlv;
-               if (!tlv_h->len)
-                       return NULL;
-               if (tlv_h->type == cpu_to_le16(tlv_type))
-                       return tlv_h;
-               length = le16_to_cpu(tlv_h->len) + sizeof(*tlv_h);
-               pos += length;
-               tlv += length;
-       }
-       return NULL;
-}
-
-
-static ssize_t lbs_threshold_read(uint16_t tlv_type, uint16_t event_mask,
-                                 struct file *file, char __user *userbuf,
-                                 size_t count, loff_t *ppos)
-{
-       struct cmd_ds_802_11_subscribe_event *subscribed;
-       struct mrvl_ie_thresholds *got;
-       struct lbs_private *priv = file->private_data;
-       ssize_t ret = 0;
-       size_t pos = 0;
-       char *buf;
-       u8 value;
-       u8 freq;
-       int events = 0;
-
-       buf = (char *)get_zeroed_page(GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       subscribed = kzalloc(sizeof(*subscribed), GFP_KERNEL);
-       if (!subscribed) {
-               ret = -ENOMEM;
-               goto out_page;
-       }
-
-       subscribed->hdr.size = cpu_to_le16(sizeof(*subscribed));
-       subscribed->action = cpu_to_le16(CMD_ACT_GET);
-
-       ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, subscribed);
-       if (ret)
-               goto out_cmd;
-
-       got = lbs_tlv_find(tlv_type, subscribed->tlv, sizeof(subscribed->tlv));
-       if (got) {
-               value = got->value;
-               freq  = got->freq;
-               events = le16_to_cpu(subscribed->events);
-
-               pos += snprintf(buf, len, "%d %d %d\n", value, freq,
-                               !!(events & event_mask));
-       }
-
-       ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
-
- out_cmd:
-       kfree(subscribed);
-
- out_page:
-       free_page((unsigned long)buf);
-       return ret;
-}
-
-
-static ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask,
-                                  struct file *file,
-                                  const char __user *userbuf, size_t count,
-                                  loff_t *ppos)
-{
-       struct cmd_ds_802_11_subscribe_event *events;
-       struct mrvl_ie_thresholds *tlv;
-       struct lbs_private *priv = file->private_data;
-       ssize_t buf_size;
-       int value, freq, new_mask;
-       uint16_t curr_mask;
-       char *buf;
-       int ret;
-
-       buf = (char *)get_zeroed_page(GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       buf_size = min(count, len - 1);
-       if (copy_from_user(buf, userbuf, buf_size)) {
-               ret = -EFAULT;
-               goto out_page;
-       }
-       ret = sscanf(buf, "%d %d %d", &value, &freq, &new_mask);
-       if (ret != 3) {
-               ret = -EINVAL;
-               goto out_page;
-       }
-       events = kzalloc(sizeof(*events), GFP_KERNEL);
-       if (!events) {
-               ret = -ENOMEM;
-               goto out_page;
-       }
-
-       events->hdr.size = cpu_to_le16(sizeof(*events));
-       events->action = cpu_to_le16(CMD_ACT_GET);
-
-       ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events);
-       if (ret)
-               goto out_events;
-
-       curr_mask = le16_to_cpu(events->events);
-
-       if (new_mask)
-               new_mask = curr_mask | event_mask;
-       else
-               new_mask = curr_mask & ~event_mask;
-
-       /* Now everything is set and we can send stuff down to the firmware */
-
-       tlv = (void *)events->tlv;
-
-       events->action = cpu_to_le16(CMD_ACT_SET);
-       events->events = cpu_to_le16(new_mask);
-       tlv->header.type = cpu_to_le16(tlv_type);
-       tlv->header.len = cpu_to_le16(sizeof(*tlv) - sizeof(tlv->header));
-       tlv->value = value;
-       if (tlv_type != TLV_TYPE_BCNMISS)
-               tlv->freq = freq;
-
-       /* The command header, the action, the event mask, and one TLV */
-       events->hdr.size = cpu_to_le16(sizeof(events->hdr) + 4 + sizeof(*tlv));
-
-       ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events);
-
-       if (!ret)
-               ret = count;
- out_events:
-       kfree(events);
- out_page:
-       free_page((unsigned long)buf);
-       return ret;
-}
-
-
-static ssize_t lbs_lowrssi_read(struct file *file, char __user *userbuf,
-                               size_t count, loff_t *ppos)
-{
-       return lbs_threshold_read(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
-                                 file, userbuf, count, ppos);
-}
-
-
-static ssize_t lbs_lowrssi_write(struct file *file, const char __user *userbuf,
-                                size_t count, loff_t *ppos)
-{
-       return lbs_threshold_write(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
-                                  file, userbuf, count, ppos);
-}
-
-
-static ssize_t lbs_lowsnr_read(struct file *file, char __user *userbuf,
-                              size_t count, loff_t *ppos)
-{
-       return lbs_threshold_read(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW,
-                                 file, userbuf, count, ppos);
-}
-
-
-static ssize_t lbs_lowsnr_write(struct file *file, const char __user *userbuf,
-                               size_t count, loff_t *ppos)
-{
-       return lbs_threshold_write(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW,
-                                  file, userbuf, count, ppos);
-}
-
-
-static ssize_t lbs_failcount_read(struct file *file, char __user *userbuf,
-                                 size_t count, loff_t *ppos)
-{
-       return lbs_threshold_read(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
-                                 file, userbuf, count, ppos);
-}
-
-
-static ssize_t lbs_failcount_write(struct file *file, const char __user *userbuf,
-                                  size_t count, loff_t *ppos)
-{
-       return lbs_threshold_write(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
-                                  file, userbuf, count, ppos);
-}
-
-
-static ssize_t lbs_highrssi_read(struct file *file, char __user *userbuf,
-                                size_t count, loff_t *ppos)
-{
-       return lbs_threshold_read(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH,
-                                 file, userbuf, count, ppos);
-}
-
-
-static ssize_t lbs_highrssi_write(struct file *file, const char __user *userbuf,
-                                 size_t count, loff_t *ppos)
-{
-       return lbs_threshold_write(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH,
-                                  file, userbuf, count, ppos);
-}
-
-
-static ssize_t lbs_highsnr_read(struct file *file, char __user *userbuf,
-                               size_t count, loff_t *ppos)
-{
-       return lbs_threshold_read(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH,
-                                 file, userbuf, count, ppos);
-}
-
-
-static ssize_t lbs_highsnr_write(struct file *file, const char __user *userbuf,
-                                size_t count, loff_t *ppos)
-{
-       return lbs_threshold_write(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH,
-                                  file, userbuf, count, ppos);
-}
-
-static ssize_t lbs_bcnmiss_read(struct file *file, char __user *userbuf,
-                               size_t count, loff_t *ppos)
-{
-       return lbs_threshold_read(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
-                                 file, userbuf, count, ppos);
-}
-
-
-static ssize_t lbs_bcnmiss_write(struct file *file, const char __user *userbuf,
-                                size_t count, loff_t *ppos)
-{
-       return lbs_threshold_write(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
-                                  file, userbuf, count, ppos);
-}
-
-
-static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf,
-                                 size_t count, loff_t *ppos)
-{
-       struct lbs_private *priv = file->private_data;
-       ssize_t pos = 0;
-       int ret;
-       unsigned long addr = get_zeroed_page(GFP_KERNEL);
-       char *buf = (char *)addr;
-       u32 val = 0;
-
-       if (!buf)
-               return -ENOMEM;
-
-       ret = lbs_get_reg(priv, CMD_MAC_REG_ACCESS, priv->mac_offset, &val);
-       mdelay(10);
-       if (!ret) {
-               pos = snprintf(buf, len, "MAC[0x%x] = 0x%08x\n",
-                               priv->mac_offset, val);
-               ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
-       }
-       free_page(addr);
-       return ret;
-}
-
-static ssize_t lbs_rdmac_write(struct file *file,
-                                   const char __user *userbuf,
-                                   size_t count, loff_t *ppos)
-{
-       struct lbs_private *priv = file->private_data;
-       ssize_t res, buf_size;
-       unsigned long addr = get_zeroed_page(GFP_KERNEL);
-       char *buf = (char *)addr;
-       if (!buf)
-               return -ENOMEM;
-
-       buf_size = min(count, len - 1);
-       if (copy_from_user(buf, userbuf, buf_size)) {
-               res = -EFAULT;
-               goto out_unlock;
-       }
-       priv->mac_offset = simple_strtoul(buf, NULL, 16);
-       res = count;
-out_unlock:
-       free_page(addr);
-       return res;
-}
-
-static ssize_t lbs_wrmac_write(struct file *file,
-                                   const char __user *userbuf,
-                                   size_t count, loff_t *ppos)
-{
-
-       struct lbs_private *priv = file->private_data;
-       ssize_t res, buf_size;
-       u32 offset, value;
-       unsigned long addr = get_zeroed_page(GFP_KERNEL);
-       char *buf = (char *)addr;
-       if (!buf)
-               return -ENOMEM;
-
-       buf_size = min(count, len - 1);
-       if (copy_from_user(buf, userbuf, buf_size)) {
-               res = -EFAULT;
-               goto out_unlock;
-       }
-       res = sscanf(buf, "%x %x", &offset, &value);
-       if (res != 2) {
-               res = -EFAULT;
-               goto out_unlock;
-       }
-
-       res = lbs_set_reg(priv, CMD_MAC_REG_ACCESS, offset, value);
-       mdelay(10);
-
-       if (!res)
-               res = count;
-out_unlock:
-       free_page(addr);
-       return res;
-}
-
-static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf,
-                                 size_t count, loff_t *ppos)
-{
-       struct lbs_private *priv = file->private_data;
-       ssize_t pos = 0;
-       int ret;
-       unsigned long addr = get_zeroed_page(GFP_KERNEL);
-       char *buf = (char *)addr;
-       u32 val;
-
-       if (!buf)
-               return -ENOMEM;
-
-       ret = lbs_get_reg(priv, CMD_BBP_REG_ACCESS, priv->bbp_offset, &val);
-       mdelay(10);
-       if (!ret) {
-               pos = snprintf(buf, len, "BBP[0x%x] = 0x%08x\n",
-                               priv->bbp_offset, val);
-               ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
-       }
-       free_page(addr);
-
-       return ret;
-}
-
-static ssize_t lbs_rdbbp_write(struct file *file,
-                                   const char __user *userbuf,
-                                   size_t count, loff_t *ppos)
-{
-       struct lbs_private *priv = file->private_data;
-       ssize_t res, buf_size;
-       unsigned long addr = get_zeroed_page(GFP_KERNEL);
-       char *buf = (char *)addr;
-       if (!buf)
-               return -ENOMEM;
-
-       buf_size = min(count, len - 1);
-       if (copy_from_user(buf, userbuf, buf_size)) {
-               res = -EFAULT;
-               goto out_unlock;
-       }
-       priv->bbp_offset = simple_strtoul(buf, NULL, 16);
-       res = count;
-out_unlock:
-       free_page(addr);
-       return res;
-}
-
-static ssize_t lbs_wrbbp_write(struct file *file,
-                                   const char __user *userbuf,
-                                   size_t count, loff_t *ppos)
-{
-
-       struct lbs_private *priv = file->private_data;
-       ssize_t res, buf_size;
-       u32 offset, value;
-       unsigned long addr = get_zeroed_page(GFP_KERNEL);
-       char *buf = (char *)addr;
-       if (!buf)
-               return -ENOMEM;
-
-       buf_size = min(count, len - 1);
-       if (copy_from_user(buf, userbuf, buf_size)) {
-               res = -EFAULT;
-               goto out_unlock;
-       }
-       res = sscanf(buf, "%x %x", &offset, &value);
-       if (res != 2) {
-               res = -EFAULT;
-               goto out_unlock;
-       }
-
-       res = lbs_set_reg(priv, CMD_BBP_REG_ACCESS, offset, value);
-       mdelay(10);
-
-       if (!res)
-               res = count;
-out_unlock:
-       free_page(addr);
-       return res;
-}
-
-static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf,
-                                 size_t count, loff_t *ppos)
-{
-       struct lbs_private *priv = file->private_data;
-       ssize_t pos = 0;
-       int ret;
-       unsigned long addr = get_zeroed_page(GFP_KERNEL);
-       char *buf = (char *)addr;
-       u32 val;
-
-       if (!buf)
-               return -ENOMEM;
-
-       ret = lbs_get_reg(priv, CMD_RF_REG_ACCESS, priv->rf_offset, &val);
-       mdelay(10);
-       if (!ret) {
-               pos = snprintf(buf, len, "RF[0x%x] = 0x%08x\n",
-                               priv->rf_offset, val);
-               ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
-       }
-       free_page(addr);
-
-       return ret;
-}
-
-static ssize_t lbs_rdrf_write(struct file *file,
-                                   const char __user *userbuf,
-                                   size_t count, loff_t *ppos)
-{
-       struct lbs_private *priv = file->private_data;
-       ssize_t res, buf_size;
-       unsigned long addr = get_zeroed_page(GFP_KERNEL);
-       char *buf = (char *)addr;
-       if (!buf)
-               return -ENOMEM;
-
-       buf_size = min(count, len - 1);
-       if (copy_from_user(buf, userbuf, buf_size)) {
-               res = -EFAULT;
-               goto out_unlock;
-       }
-       priv->rf_offset = simple_strtoul(buf, NULL, 16);
-       res = count;
-out_unlock:
-       free_page(addr);
-       return res;
-}
-
-static ssize_t lbs_wrrf_write(struct file *file,
-                                   const char __user *userbuf,
-                                   size_t count, loff_t *ppos)
-{
-
-       struct lbs_private *priv = file->private_data;
-       ssize_t res, buf_size;
-       u32 offset, value;
-       unsigned long addr = get_zeroed_page(GFP_KERNEL);
-       char *buf = (char *)addr;
-       if (!buf)
-               return -ENOMEM;
-
-       buf_size = min(count, len - 1);
-       if (copy_from_user(buf, userbuf, buf_size)) {
-               res = -EFAULT;
-               goto out_unlock;
-       }
-       res = sscanf(buf, "%x %x", &offset, &value);
-       if (res != 2) {
-               res = -EFAULT;
-               goto out_unlock;
-       }
-
-       res = lbs_set_reg(priv, CMD_RF_REG_ACCESS, offset, value);
-       mdelay(10);
-
-       if (!res)
-               res = count;
-out_unlock:
-       free_page(addr);
-       return res;
-}
-
-#define FOPS(fread, fwrite) { \
-       .owner = THIS_MODULE, \
-       .open = simple_open, \
-       .read = (fread), \
-       .write = (fwrite), \
-       .llseek = generic_file_llseek, \
-}
-
-struct lbs_debugfs_files {
-       const char *name;
-       umode_t perm;
-       struct file_operations fops;
-};
-
-static const struct lbs_debugfs_files debugfs_files[] = {
-       { "info", 0444, FOPS(lbs_dev_info, write_file_dummy), },
-       { "sleepparams", 0644, FOPS(lbs_sleepparams_read,
-                               lbs_sleepparams_write), },
-       { "hostsleep", 0644, FOPS(lbs_host_sleep_read,
-                               lbs_host_sleep_write), },
-};
-
-static const struct lbs_debugfs_files debugfs_events_files[] = {
-       {"low_rssi", 0644, FOPS(lbs_lowrssi_read,
-                               lbs_lowrssi_write), },
-       {"low_snr", 0644, FOPS(lbs_lowsnr_read,
-                               lbs_lowsnr_write), },
-       {"failure_count", 0644, FOPS(lbs_failcount_read,
-                               lbs_failcount_write), },
-       {"beacon_missed", 0644, FOPS(lbs_bcnmiss_read,
-                               lbs_bcnmiss_write), },
-       {"high_rssi", 0644, FOPS(lbs_highrssi_read,
-                               lbs_highrssi_write), },
-       {"high_snr", 0644, FOPS(lbs_highsnr_read,
-                               lbs_highsnr_write), },
-};
-
-static const struct lbs_debugfs_files debugfs_regs_files[] = {
-       {"rdmac", 0644, FOPS(lbs_rdmac_read, lbs_rdmac_write), },
-       {"wrmac", 0600, FOPS(NULL, lbs_wrmac_write), },
-       {"rdbbp", 0644, FOPS(lbs_rdbbp_read, lbs_rdbbp_write), },
-       {"wrbbp", 0600, FOPS(NULL, lbs_wrbbp_write), },
-       {"rdrf", 0644, FOPS(lbs_rdrf_read, lbs_rdrf_write), },
-       {"wrrf", 0600, FOPS(NULL, lbs_wrrf_write), },
-};
-
-void lbs_debugfs_init(void)
-{
-       if (!lbs_dir)
-               lbs_dir = debugfs_create_dir("lbs_wireless", NULL);
-}
-
-void lbs_debugfs_remove(void)
-{
-       debugfs_remove(lbs_dir);
-}
-
-void lbs_debugfs_init_one(struct lbs_private *priv, struct net_device *dev)
-{
-       int i;
-       const struct lbs_debugfs_files *files;
-       if (!lbs_dir)
-               goto exit;
-
-       priv->debugfs_dir = debugfs_create_dir(dev->name, lbs_dir);
-       if (!priv->debugfs_dir)
-               goto exit;
-
-       for (i=0; i<ARRAY_SIZE(debugfs_files); i++) {
-               files = &debugfs_files[i];
-               priv->debugfs_files[i] = debugfs_create_file(files->name,
-                                                            files->perm,
-                                                            priv->debugfs_dir,
-                                                            priv,
-                                                            &files->fops);
-       }
-
-       priv->events_dir = debugfs_create_dir("subscribed_events", priv->debugfs_dir);
-       if (!priv->events_dir)
-               goto exit;
-
-       for (i=0; i<ARRAY_SIZE(debugfs_events_files); i++) {
-               files = &debugfs_events_files[i];
-               priv->debugfs_events_files[i] = debugfs_create_file(files->name,
-                                                            files->perm,
-                                                            priv->events_dir,
-                                                            priv,
-                                                            &files->fops);
-       }
-
-       priv->regs_dir = debugfs_create_dir("registers", priv->debugfs_dir);
-       if (!priv->regs_dir)
-               goto exit;
-
-       for (i=0; i<ARRAY_SIZE(debugfs_regs_files); i++) {
-               files = &debugfs_regs_files[i];
-               priv->debugfs_regs_files[i] = debugfs_create_file(files->name,
-                                                            files->perm,
-                                                            priv->regs_dir,
-                                                            priv,
-                                                            &files->fops);
-       }
-
-#ifdef PROC_DEBUG
-       lbs_debug_init(priv);
-#endif
-exit:
-       return;
-}
-
-void lbs_debugfs_remove_one(struct lbs_private *priv)
-{
-       int i;
-
-       for(i=0; i<ARRAY_SIZE(debugfs_regs_files); i++)
-               debugfs_remove(priv->debugfs_regs_files[i]);
-
-       debugfs_remove(priv->regs_dir);
-
-       for(i=0; i<ARRAY_SIZE(debugfs_events_files); i++)
-               debugfs_remove(priv->debugfs_events_files[i]);
-
-       debugfs_remove(priv->events_dir);
-#ifdef PROC_DEBUG
-       debugfs_remove(priv->debugfs_debug);
-#endif
-       for(i=0; i<ARRAY_SIZE(debugfs_files); i++)
-               debugfs_remove(priv->debugfs_files[i]);
-       debugfs_remove(priv->debugfs_dir);
-}
-
-
-
-/* debug entry */
-
-#ifdef PROC_DEBUG
-
-#define item_size(n)   (FIELD_SIZEOF(struct lbs_private, n))
-#define item_addr(n)   (offsetof(struct lbs_private, n))
-
-
-struct debug_data {
-       char name[32];
-       u32 size;
-       size_t addr;
-};
-
-/* To debug any member of struct lbs_private, simply add one line here.
- */
-static struct debug_data items[] = {
-       {"psmode", item_size(psmode), item_addr(psmode)},
-       {"psstate", item_size(psstate), item_addr(psstate)},
-};
-
-static int num_of_items = ARRAY_SIZE(items);
-
-/**
- * lbs_debugfs_read - proc read function
- *
- * @file:      file to read
- * @userbuf:   pointer to buffer
- * @count:     number of bytes to read
- * @ppos:      read data starting position
- *
- * returns:    amount of data read or negative error code
- */
-static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf,
-                       size_t count, loff_t *ppos)
-{
-       int val = 0;
-       size_t pos = 0;
-       ssize_t res;
-       char *p;
-       int i;
-       struct debug_data *d;
-       unsigned long addr = get_zeroed_page(GFP_KERNEL);
-       char *buf = (char *)addr;
-       if (!buf)
-               return -ENOMEM;
-
-       p = buf;
-
-       d = file->private_data;
-
-       for (i = 0; i < num_of_items; i++) {
-               if (d[i].size == 1)
-                       val = *((u8 *) d[i].addr);
-               else if (d[i].size == 2)
-                       val = *((u16 *) d[i].addr);
-               else if (d[i].size == 4)
-                       val = *((u32 *) d[i].addr);
-               else if (d[i].size == 8)
-                       val = *((u64 *) d[i].addr);
-
-               pos += sprintf(p + pos, "%s=%d\n", d[i].name, val);
-       }
-
-       res = simple_read_from_buffer(userbuf, count, ppos, p, pos);
-
-       free_page(addr);
-       return res;
-}
-
-/**
- * lbs_debugfs_write - proc write function
- *
- * @f:         file pointer
- * @buf:       pointer to data buffer
- * @cnt:       data number to write
- * @ppos:      file position
- *
- * returns:    amount of data written
- */
-static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf,
-                           size_t cnt, loff_t *ppos)
-{
-       int r, i;
-       char *pdata;
-       char *p;
-       char *p0;
-       char *p1;
-       char *p2;
-       struct debug_data *d = f->private_data;
-
-       if (cnt == 0)
-               return 0;
-
-       pdata = kmalloc(cnt + 1, GFP_KERNEL);
-       if (pdata == NULL)
-               return 0;
-
-       if (copy_from_user(pdata, buf, cnt)) {
-               lbs_deb_debugfs("Copy from user failed\n");
-               kfree(pdata);
-               return 0;
-       }
-       pdata[cnt] = '\0';
-
-       p0 = pdata;
-       for (i = 0; i < num_of_items; i++) {
-               do {
-                       p = strstr(p0, d[i].name);
-                       if (p == NULL)
-                               break;
-                       p1 = strchr(p, '\n');
-                       if (p1 == NULL)
-                               break;
-                       p0 = p1++;
-                       p2 = strchr(p, '=');
-                       if (!p2)
-                               break;
-                       p2++;
-                       r = simple_strtoul(p2, NULL, 0);
-                       if (d[i].size == 1)
-                               *((u8 *) d[i].addr) = (u8) r;
-                       else if (d[i].size == 2)
-                               *((u16 *) d[i].addr) = (u16) r;
-                       else if (d[i].size == 4)
-                               *((u32 *) d[i].addr) = (u32) r;
-                       else if (d[i].size == 8)
-                               *((u64 *) d[i].addr) = (u64) r;
-                       break;
-               } while (1);
-       }
-       kfree(pdata);
-
-       return (ssize_t)cnt;
-}
-
-static const struct file_operations lbs_debug_fops = {
-       .owner = THIS_MODULE,
-       .open = simple_open,
-       .write = lbs_debugfs_write,
-       .read = lbs_debugfs_read,
-       .llseek = default_llseek,
-};
-
-/**
- * lbs_debug_init - create debug proc file
- *
- * @priv:      pointer to &struct lbs_private
- *
- * returns:    N/A
- */
-static void lbs_debug_init(struct lbs_private *priv)
-{
-       int i;
-
-       if (!priv->debugfs_dir)
-               return;
-
-       for (i = 0; i < num_of_items; i++)
-               items[i].addr += (size_t) priv;
-
-       priv->debugfs_debug = debugfs_create_file("debug", 0644,
-                                                 priv->debugfs_dir, &items[0],
-                                                 &lbs_debug_fops);
-}
-#endif
diff --git a/drivers/net/wireless/libertas/debugfs.h b/drivers/net/wireless/libertas/debugfs.h
deleted file mode 100644 (file)
index f2b9c7f..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef _LBS_DEBUGFS_H_
-#define _LBS_DEBUGFS_H_
-
-void lbs_debugfs_init(void);
-void lbs_debugfs_remove(void);
-
-void lbs_debugfs_init_one(struct lbs_private *priv, struct net_device *dev);
-void lbs_debugfs_remove_one(struct lbs_private *priv);
-
-#endif
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
deleted file mode 100644 (file)
index 84a3aa7..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-
-/*
- *  This file contains declaration referring to
- *  functions defined in other source files
- */
-
-#ifndef _LBS_DECL_H_
-#define _LBS_DECL_H_
-
-#include <linux/netdevice.h>
-#include <linux/firmware.h>
-#include <linux/nl80211.h>
-
-/* Should be terminated by a NULL entry */
-struct lbs_fw_table {
-       int model;
-       const char *helper;
-       const char *fwname;
-};
-
-struct lbs_private;
-typedef void (*lbs_fw_cb)(struct lbs_private *priv, int ret,
-               const struct firmware *helper, const struct firmware *mainfw);
-
-struct lbs_private;
-struct sk_buff;
-struct net_device;
-struct cmd_ds_command;
-
-
-/* ethtool.c */
-extern const struct ethtool_ops lbs_ethtool_ops;
-
-
-/* tx.c */
-void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count);
-netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb,
-                               struct net_device *dev);
-
-/* rx.c */
-int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *);
-
-
-/* main.c */
-struct lbs_private *lbs_add_card(void *card, struct device *dmdev);
-void lbs_remove_card(struct lbs_private *priv);
-int lbs_start_card(struct lbs_private *priv);
-void lbs_stop_card(struct lbs_private *priv);
-void lbs_host_to_card_done(struct lbs_private *priv);
-
-int lbs_start_iface(struct lbs_private *priv);
-int lbs_stop_iface(struct lbs_private *priv);
-int lbs_set_iface_type(struct lbs_private *priv, enum nl80211_iftype type);
-
-int lbs_rtap_supported(struct lbs_private *priv);
-
-int lbs_set_mac_address(struct net_device *dev, void *addr);
-void lbs_set_multicast_list(struct net_device *dev);
-void lbs_update_mcast(struct lbs_private *priv);
-
-int lbs_suspend(struct lbs_private *priv);
-int lbs_resume(struct lbs_private *priv);
-
-void lbs_queue_event(struct lbs_private *priv, u32 event);
-void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx);
-
-int lbs_enter_auto_deep_sleep(struct lbs_private *priv);
-int lbs_exit_auto_deep_sleep(struct lbs_private *priv);
-
-u32 lbs_fw_index_to_data_rate(u8 index);
-u8 lbs_data_rate_to_fw_index(u32 rate);
-
-int lbs_get_firmware(struct device *dev, u32 card_model,
-                       const struct lbs_fw_table *fw_table,
-                       const struct firmware **helper,
-                       const struct firmware **mainfw);
-int lbs_get_firmware_async(struct lbs_private *priv, struct device *device,
-                          u32 card_model, const struct lbs_fw_table *fw_table,
-                          lbs_fw_cb callback);
-void lbs_wait_for_firmware_load(struct lbs_private *priv);
-
-#endif
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
deleted file mode 100644 (file)
index 407784a..0000000
+++ /dev/null
@@ -1,394 +0,0 @@
-/*
- * This header file contains global constant/enum definitions,
- * global variable declaration.
- */
-#ifndef _LBS_DEFS_H_
-#define _LBS_DEFS_H_
-
-#include <linux/spinlock.h>
-
-#ifdef CONFIG_LIBERTAS_DEBUG
-#define DEBUG
-#define PROC_DEBUG
-#endif
-
-#ifndef DRV_NAME
-#define DRV_NAME "libertas"
-#endif
-
-
-#define LBS_DEB_ENTER  0x00000001
-#define LBS_DEB_LEAVE  0x00000002
-#define LBS_DEB_MAIN   0x00000004
-#define LBS_DEB_NET    0x00000008
-#define LBS_DEB_MESH   0x00000010
-#define LBS_DEB_WEXT   0x00000020
-#define LBS_DEB_IOCTL  0x00000040
-#define LBS_DEB_SCAN   0x00000080
-#define LBS_DEB_ASSOC  0x00000100
-#define LBS_DEB_JOIN   0x00000200
-#define LBS_DEB_11D    0x00000400
-#define LBS_DEB_DEBUGFS        0x00000800
-#define LBS_DEB_ETHTOOL        0x00001000
-#define LBS_DEB_HOST   0x00002000
-#define LBS_DEB_CMD    0x00004000
-#define LBS_DEB_RX     0x00008000
-#define LBS_DEB_TX     0x00010000
-#define LBS_DEB_USB    0x00020000
-#define LBS_DEB_CS     0x00040000
-#define LBS_DEB_FW     0x00080000
-#define LBS_DEB_THREAD 0x00100000
-#define LBS_DEB_HEX    0x00200000
-#define LBS_DEB_SDIO   0x00400000
-#define LBS_DEB_SYSFS  0x00800000
-#define LBS_DEB_SPI    0x01000000
-#define LBS_DEB_CFG80211 0x02000000
-
-extern unsigned int lbs_debug;
-
-#ifdef DEBUG
-#define LBS_DEB_LL(grp, grpnam, fmt, args...) \
-do { if ((lbs_debug & (grp)) == (grp)) \
-  printk(KERN_DEBUG DRV_NAME grpnam "%s: " fmt, \
-         in_interrupt() ? " (INT)" : "", ## args); } while (0)
-#else
-#define LBS_DEB_LL(grp, grpnam, fmt, args...) do {} while (0)
-#endif
-
-#define lbs_deb_enter(grp) \
-  LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s()\n", __func__);
-#define lbs_deb_enter_args(grp, fmt, args...) \
-  LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s(" fmt ")\n", __func__, ## args);
-#define lbs_deb_leave(grp) \
-  LBS_DEB_LL(grp | LBS_DEB_LEAVE, " leave", "%s()\n", __func__);
-#define lbs_deb_leave_args(grp, fmt, args...) \
-  LBS_DEB_LL(grp | LBS_DEB_LEAVE, " leave", "%s(), " fmt "\n", \
-  __func__, ##args);
-#define lbs_deb_main(fmt, args...)      LBS_DEB_LL(LBS_DEB_MAIN, " main", fmt, ##args)
-#define lbs_deb_net(fmt, args...)       LBS_DEB_LL(LBS_DEB_NET, " net", fmt, ##args)
-#define lbs_deb_mesh(fmt, args...)      LBS_DEB_LL(LBS_DEB_MESH, " mesh", fmt, ##args)
-#define lbs_deb_wext(fmt, args...)      LBS_DEB_LL(LBS_DEB_WEXT, " wext", fmt, ##args)
-#define lbs_deb_ioctl(fmt, args...)     LBS_DEB_LL(LBS_DEB_IOCTL, " ioctl", fmt, ##args)
-#define lbs_deb_scan(fmt, args...)      LBS_DEB_LL(LBS_DEB_SCAN, " scan", fmt, ##args)
-#define lbs_deb_assoc(fmt, args...)     LBS_DEB_LL(LBS_DEB_ASSOC, " assoc", fmt, ##args)
-#define lbs_deb_join(fmt, args...)      LBS_DEB_LL(LBS_DEB_JOIN, " join", fmt, ##args)
-#define lbs_deb_11d(fmt, args...)       LBS_DEB_LL(LBS_DEB_11D, " 11d", fmt, ##args)
-#define lbs_deb_debugfs(fmt, args...)   LBS_DEB_LL(LBS_DEB_DEBUGFS, " debugfs", fmt, ##args)
-#define lbs_deb_ethtool(fmt, args...)   LBS_DEB_LL(LBS_DEB_ETHTOOL, " ethtool", fmt, ##args)
-#define lbs_deb_host(fmt, args...)      LBS_DEB_LL(LBS_DEB_HOST, " host", fmt, ##args)
-#define lbs_deb_cmd(fmt, args...)       LBS_DEB_LL(LBS_DEB_CMD, " cmd", fmt, ##args)
-#define lbs_deb_rx(fmt, args...)        LBS_DEB_LL(LBS_DEB_RX, " rx", fmt, ##args)
-#define lbs_deb_tx(fmt, args...)        LBS_DEB_LL(LBS_DEB_TX, " tx", fmt, ##args)
-#define lbs_deb_fw(fmt, args...)        LBS_DEB_LL(LBS_DEB_FW, " fw", fmt, ##args)
-#define lbs_deb_usb(fmt, args...)       LBS_DEB_LL(LBS_DEB_USB, " usb", fmt, ##args)
-#define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usbd", "%s:" fmt, dev_name(dev), ##args)
-#define lbs_deb_cs(fmt, args...)        LBS_DEB_LL(LBS_DEB_CS, " cs", fmt, ##args)
-#define lbs_deb_thread(fmt, args...)    LBS_DEB_LL(LBS_DEB_THREAD, " thread", fmt, ##args)
-#define lbs_deb_sdio(fmt, args...)      LBS_DEB_LL(LBS_DEB_SDIO, " sdio", fmt, ##args)
-#define lbs_deb_sysfs(fmt, args...)     LBS_DEB_LL(LBS_DEB_SYSFS, " sysfs", fmt, ##args)
-#define lbs_deb_spi(fmt, args...)       LBS_DEB_LL(LBS_DEB_SPI, " spi", fmt, ##args)
-#define lbs_deb_cfg80211(fmt, args...)  LBS_DEB_LL(LBS_DEB_CFG80211, " cfg80211", fmt, ##args)
-
-#ifdef DEBUG
-static inline void lbs_deb_hex(unsigned int grp, const char *prompt,
-                              const u8 *buf, int len)
-{
-       int i = 0;
-
-       if (len &&
-           (lbs_debug & LBS_DEB_HEX) &&
-           (lbs_debug & grp))
-       {
-               for (i = 1; i <= len; i++) {
-                       if ((i & 0xf) == 1) {
-                               if (i != 1)
-                                       printk("\n");
-                               printk(DRV_NAME " %s: ", prompt);
-                       }
-                       printk("%02x ", (u8) * buf);
-                       buf++;
-               }
-               printk("\n");
-       }
-}
-#else
-#define lbs_deb_hex(grp,prompt,buf,len)        do {} while (0)
-#endif
-
-
-
-/* Buffer Constants */
-
-/*     The size of SQ memory PPA, DPA are 8 DWORDs, that keep the physical
- *     addresses of TxPD buffers. Station has only 8 TxPD available, Whereas
- *     driver has more local TxPDs. Each TxPD on the host memory is associated
- *     with a Tx control node. The driver maintains 8 RxPD descriptors for
- *     station firmware to store Rx packet information.
- *
- *     Current version of MAC has a 32x6 multicast address buffer.
- *
- *     802.11b can have up to  14 channels, the driver keeps the
- *     BSSID(MAC address) of each APs or Ad hoc stations it has sensed.
- */
-
-#define MRVDRV_MAX_MULTICAST_LIST_SIZE 32
-#define LBS_NUM_CMD_BUFFERS             10
-#define LBS_CMD_BUFFER_SIZE             (2 * 1024)
-#define MRVDRV_MAX_CHANNEL_SIZE                14
-#define MRVDRV_ASSOCIATION_TIME_OUT    255
-#define MRVDRV_SNAP_HEADER_LEN          8
-
-#define        LBS_UPLD_SIZE                   2312
-#define DEV_NAME_LEN                   32
-
-/* Wake criteria for HOST_SLEEP_CFG command */
-#define EHS_WAKE_ON_BROADCAST_DATA     0x0001
-#define EHS_WAKE_ON_UNICAST_DATA       0x0002
-#define EHS_WAKE_ON_MAC_EVENT          0x0004
-#define EHS_WAKE_ON_MULTICAST_DATA     0x0008
-#define EHS_REMOVE_WAKEUP              0xFFFFFFFF
-/* Wake rules for Host_Sleep_CFG command */
-#define WOL_RULE_NET_TYPE_INFRA_OR_IBSS        0x00
-#define WOL_RULE_NET_TYPE_MESH         0x10
-#define WOL_RULE_ADDR_TYPE_BCAST       0x01
-#define WOL_RULE_ADDR_TYPE_MCAST       0x08
-#define WOL_RULE_ADDR_TYPE_UCAST       0x02
-#define WOL_RULE_OP_AND                        0x01
-#define WOL_RULE_OP_OR                 0x02
-#define WOL_RULE_OP_INVALID            0xFF
-#define WOL_RESULT_VALID_CMD           0
-#define WOL_RESULT_NOSPC_ERR           1
-#define WOL_RESULT_EEXIST_ERR          2
-
-/* Misc constants */
-/* This section defines 802.11 specific contants */
-
-#define MRVDRV_MAX_BSS_DESCRIPTS               16
-#define MRVDRV_MAX_REGION_CODE                 6
-
-#define MRVDRV_DEFAULT_LISTEN_INTERVAL         10
-
-#define        MRVDRV_CHANNELS_PER_SCAN                4
-#define        MRVDRV_MAX_CHANNELS_PER_SCAN            14
-
-#define MRVDRV_MIN_BEACON_INTERVAL             20
-#define MRVDRV_MAX_BEACON_INTERVAL             1000
-#define MRVDRV_BEACON_INTERVAL                 100
-
-#define MARVELL_MESH_IE_LENGTH         9
-
-/*
- * Values used to populate the struct mrvl_mesh_ie.  The only time you need this
- * is when enabling the mesh using CMD_MESH_CONFIG.
- */
-#define MARVELL_MESH_IE_TYPE           4
-#define MARVELL_MESH_IE_SUBTYPE                0
-#define MARVELL_MESH_IE_VERSION                0
-#define MARVELL_MESH_PROTO_ID_HWMP     0
-#define MARVELL_MESH_METRIC_ID         0
-#define MARVELL_MESH_CAPABILITY                0
-
-/* INT status Bit Definition */
-#define MRVDRV_TX_DNLD_RDY             0x0001
-#define MRVDRV_RX_UPLD_RDY             0x0002
-#define MRVDRV_CMD_DNLD_RDY            0x0004
-#define MRVDRV_CMD_UPLD_RDY            0x0008
-#define MRVDRV_CARDEVENT               0x0010
-
-/* Automatic TX control default levels */
-#define POW_ADAPT_DEFAULT_P0 13
-#define POW_ADAPT_DEFAULT_P1 15
-#define POW_ADAPT_DEFAULT_P2 18
-#define TPC_DEFAULT_P0 5
-#define TPC_DEFAULT_P1 10
-#define TPC_DEFAULT_P2 13
-
-/* TxPD status */
-
-/*
- *     Station firmware use TxPD status field to report final Tx transmit
- *     result, Bit masks are used to present combined situations.
- */
-
-#define MRVDRV_TxPD_POWER_MGMT_NULL_PACKET 0x01
-#define MRVDRV_TxPD_POWER_MGMT_LAST_PACKET 0x08
-
-/* Tx mesh flag */
-/*
- * Currently we are using normal WDS flag as mesh flag.
- * TODO: change to proper mesh flag when MAC understands it.
- */
-#define TxPD_CONTROL_WDS_FRAME (1<<17)
-#define TxPD_MESH_FRAME TxPD_CONTROL_WDS_FRAME
-
-/* Mesh interface ID */
-#define MESH_IFACE_ID                                  0x0001
-/* Mesh id should be in bits 14-13-12 */
-#define MESH_IFACE_BIT_OFFSET                          0x000c
-/* Mesh enable bit in FW capability */
-#define MESH_CAPINFO_ENABLE_MASK                       (1<<16)
-
-/* FW definition from Marvell v4 */
-#define MRVL_FW_V4                                     (0x04)
-/* FW definition from Marvell v5 */
-#define MRVL_FW_V5                                     (0x05)
-/* FW definition from Marvell v10 */
-#define MRVL_FW_V10                                    (0x0a)
-/* FW major revision definition */
-#define MRVL_FW_MAJOR_REV(x)                           ((x)>>24)
-
-/* RxPD status */
-
-#define MRVDRV_RXPD_STATUS_OK                0x0001
-
-/* RxPD status - Received packet types */
-/* Rx mesh flag */
-/*
- * Currently we are using normal WDS flag as mesh flag.
- * TODO: change to proper mesh flag when MAC understands it.
- */
-#define RxPD_CONTROL_WDS_FRAME (0x40)
-#define RxPD_MESH_FRAME RxPD_CONTROL_WDS_FRAME
-
-/* RSSI-related defines */
-/*
- *     RSSI constants are used to implement 802.11 RSSI threshold
- *     indication. if the Rx packet signal got too weak for 5 consecutive
- *     times, miniport driver (driver) will report this event to wrapper
- */
-
-#define MRVDRV_NF_DEFAULT_SCAN_VALUE           (-96)
-
-/* RTS/FRAG related defines */
-#define MRVDRV_RTS_MIN_VALUE           0
-#define MRVDRV_RTS_MAX_VALUE           2347
-#define MRVDRV_FRAG_MIN_VALUE          256
-#define MRVDRV_FRAG_MAX_VALUE          2346
-
-/* This is for firmware specific length */
-#define EXTRA_LEN      36
-
-#define MRVDRV_ETH_TX_PACKET_BUFFER_SIZE \
-       (ETH_FRAME_LEN + sizeof(struct txpd) + EXTRA_LEN)
-
-#define MRVDRV_ETH_RX_PACKET_BUFFER_SIZE \
-       (ETH_FRAME_LEN + sizeof(struct rxpd) \
-        + MRVDRV_SNAP_HEADER_LEN + EXTRA_LEN)
-
-#define        CMD_F_HOSTCMD           (1 << 0)
-#define FW_CAPINFO_WPA         (1 << 0)
-#define FW_CAPINFO_PS                  (1 << 1)
-#define FW_CAPINFO_FIRMWARE_UPGRADE    (1 << 13)
-#define FW_CAPINFO_BOOT2_UPGRADE       (1<<14)
-#define FW_CAPINFO_PERSISTENT_CONFIG   (1<<15)
-
-#define KEY_LEN_WPA_AES                        16
-#define KEY_LEN_WPA_TKIP               32
-#define KEY_LEN_WEP_104                        13
-#define KEY_LEN_WEP_40                 5
-
-#define RF_ANTENNA_1           0x1
-#define RF_ANTENNA_2           0x2
-#define RF_ANTENNA_AUTO                0xFFFF
-
-#define        BAND_B                  (0x01)
-#define        BAND_G                  (0x02)
-#define ALL_802_11_BANDS       (BAND_B | BAND_G)
-
-#define MAX_RATES                      14
-
-#define        MAX_LEDS                        8
-
-/* Global Variable Declaration */
-extern const char lbs_driver_version[];
-extern u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE];
-
-
-/* ENUM definition */
-/* SNRNF_TYPE */
-enum SNRNF_TYPE {
-       TYPE_BEACON = 0,
-       TYPE_RXPD,
-       MAX_TYPE_B
-};
-
-/* SNRNF_DATA */
-enum SNRNF_DATA {
-       TYPE_NOAVG = 0,
-       TYPE_AVG,
-       MAX_TYPE_AVG
-};
-
-/* LBS_802_11_POWER_MODE */
-enum LBS_802_11_POWER_MODE {
-       LBS802_11POWERMODECAM,
-       LBS802_11POWERMODEMAX_PSP,
-       LBS802_11POWERMODEFAST_PSP,
-       /* not a real mode, defined as an upper bound */
-       LBS802_11POWEMODEMAX
-};
-
-/* PS_STATE */
-enum PS_STATE {
-       PS_STATE_FULL_POWER,
-       PS_STATE_AWAKE,
-       PS_STATE_PRE_SLEEP,
-       PS_STATE_SLEEP
-};
-
-/* DNLD_STATE */
-enum DNLD_STATE {
-       DNLD_RES_RECEIVED,
-       DNLD_DATA_SENT,
-       DNLD_CMD_SENT,
-       DNLD_BOOTCMD_SENT,
-};
-
-/* LBS_MEDIA_STATE */
-enum LBS_MEDIA_STATE {
-       LBS_CONNECTED,
-       LBS_DISCONNECTED
-};
-
-/* LBS_802_11_PRIVACY_FILTER */
-enum LBS_802_11_PRIVACY_FILTER {
-       LBS802_11PRIVFILTERACCEPTALL,
-       LBS802_11PRIVFILTER8021XWEP
-};
-
-/* mv_ms_type */
-enum mv_ms_type {
-       MVMS_DAT = 0,
-       MVMS_CMD = 1,
-       MVMS_TXDONE = 2,
-       MVMS_EVENT
-};
-
-/* KEY_TYPE_ID */
-enum KEY_TYPE_ID {
-       KEY_TYPE_ID_WEP = 0,
-       KEY_TYPE_ID_TKIP,
-       KEY_TYPE_ID_AES
-};
-
-/* KEY_INFO_WPA (applies to both TKIP and AES/CCMP) */
-enum KEY_INFO_WPA {
-       KEY_INFO_WPA_MCAST = 0x01,
-       KEY_INFO_WPA_UNICAST = 0x02,
-       KEY_INFO_WPA_ENABLED = 0x04
-};
-
-/* Default values for fwt commands. */
-#define FWT_DEFAULT_METRIC 0
-#define FWT_DEFAULT_DIR 1
-/* Default Rate, 11Mbps */
-#define FWT_DEFAULT_RATE 3
-#define FWT_DEFAULT_SSN 0xffffffff
-#define FWT_DEFAULT_DSN 0
-#define FWT_DEFAULT_HOPCOUNT 0
-#define FWT_DEFAULT_TTL 0
-#define FWT_DEFAULT_EXPIRATION 0
-#define FWT_DEFAULT_SLEEPMODE 0
-#define FWT_DEFAULT_SNR 0
-
-#endif
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
deleted file mode 100644 (file)
index 6bd1608..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * This file contains definitions and data structures specific
- * to Marvell 802.11 NIC. It contains the Device Information
- * structure struct lbs_private..
- */
-#ifndef _LBS_DEV_H_
-#define _LBS_DEV_H_
-
-#include "defs.h"
-#include "decl.h"
-#include "host.h"
-
-#include <linux/kfifo.h>
-
-/* sleep_params */
-struct sleep_params {
-       uint16_t sp_error;
-       uint16_t sp_offset;
-       uint16_t sp_stabletime;
-       uint8_t  sp_calcontrol;
-       uint8_t  sp_extsleepclk;
-       uint16_t sp_reserved;
-};
-
-/* Mesh statistics */
-struct lbs_mesh_stats {
-       u32     fwd_bcast_cnt;          /* Fwd: Broadcast counter */
-       u32     fwd_unicast_cnt;        /* Fwd: Unicast counter */
-       u32     fwd_drop_ttl;           /* Fwd: TTL zero */
-       u32     fwd_drop_rbt;           /* Fwd: Recently Broadcasted */
-       u32     fwd_drop_noroute;       /* Fwd: No route to Destination */
-       u32     fwd_drop_nobuf;         /* Fwd: Run out of internal buffers */
-       u32     drop_blind;             /* Rx:  Dropped by blinding table */
-       u32     tx_failed_cnt;          /* Tx:  Failed transmissions */
-};
-
-/* Private structure for the MV device */
-struct lbs_private {
-
-       /* Basic networking */
-       struct net_device *dev;
-       u32 connect_status;
-       struct work_struct mcast_work;
-       u32 nr_of_multicastmacaddr;
-       u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN];
-
-       /* CFG80211 */
-       struct wireless_dev *wdev;
-       bool wiphy_registered;
-       struct cfg80211_scan_request *scan_req;
-       u8 assoc_bss[ETH_ALEN];
-       u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
-       u8 disassoc_reason;
-
-       /* Mesh */
-       struct net_device *mesh_dev; /* Virtual device */
-#ifdef CONFIG_LIBERTAS_MESH
-       struct lbs_mesh_stats mstats;
-       uint16_t mesh_tlv;
-       u8 mesh_ssid[IEEE80211_MAX_SSID_LEN + 1];
-       u8 mesh_ssid_len;
-       u8 mesh_channel;
-#endif
-
-       /* Debugfs */
-       struct dentry *debugfs_dir;
-       struct dentry *debugfs_debug;
-       struct dentry *debugfs_files[6];
-       struct dentry *events_dir;
-       struct dentry *debugfs_events_files[6];
-       struct dentry *regs_dir;
-       struct dentry *debugfs_regs_files[6];
-
-       /* Hardware debugging */
-       u32 mac_offset;
-       u32 bbp_offset;
-       u32 rf_offset;
-
-       /* Power management */
-       u16 psmode;
-       u32 psstate;
-       u8 needtowakeup;
-
-       /* Deep sleep */
-       int is_deep_sleep;
-       int deep_sleep_required;
-       int is_auto_deep_sleep_enabled;
-       int wakeup_dev_required;
-       int is_activity_detected;
-       int auto_deep_sleep_timeout; /* in ms */
-       wait_queue_head_t ds_awake_q;
-       struct timer_list auto_deepsleep_timer;
-
-       /* Host sleep*/
-       int is_host_sleep_configured;
-       int is_host_sleep_activated;
-       wait_queue_head_t host_sleep_q;
-
-       /* Hardware access */
-       void *card;
-       bool iface_running;
-       u8 fw_ready;
-       u8 surpriseremoved;
-       u8 setup_fw_on_resume;
-       int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb);
-       void (*reset_card) (struct lbs_private *priv);
-       int (*power_save) (struct lbs_private *priv);
-       int (*power_restore) (struct lbs_private *priv);
-       int (*enter_deep_sleep) (struct lbs_private *priv);
-       int (*exit_deep_sleep) (struct lbs_private *priv);
-       int (*reset_deep_sleep_wakeup) (struct lbs_private *priv);
-
-       /* Adapter info (from EEPROM) */
-       u32 fwrelease;
-       u32 fwcapinfo;
-       u16 regioncode;
-       u8 current_addr[ETH_ALEN];
-       u8 copied_hwaddr;
-
-       /* Command download */
-       u8 dnld_sent;
-       /* bit0 1/0=data_sent/data_tx_done,
-          bit1 1/0=cmd_sent/cmd_tx_done,
-          all other bits reserved 0 */
-       u16 seqnum;
-       struct cmd_ctrl_node *cmd_array;
-       struct cmd_ctrl_node *cur_cmd;
-       struct list_head cmdfreeq;    /* free command buffers */
-       struct list_head cmdpendingq; /* pending command buffers */
-       struct timer_list command_timer;
-       int cmd_timed_out;
-
-       /* Command responses sent from the hardware to the driver */
-       u8 resp_idx;
-       u8 resp_buf[2][LBS_UPLD_SIZE];
-       u32 resp_len[2];
-
-       /* Events sent from hardware to driver */
-       struct kfifo event_fifo;
-
-       /* thread to service interrupts */
-       struct task_struct *main_thread;
-       wait_queue_head_t waitq;
-       struct workqueue_struct *work_thread;
-
-       /* Encryption stuff */
-       u8 authtype_auto;
-       u8 wep_tx_key;
-       u8 wep_key[4][WLAN_KEY_LEN_WEP104];
-       u8 wep_key_len[4];
-
-       /* Wake On LAN */
-       uint32_t wol_criteria;
-       uint8_t wol_gpio;
-       uint8_t wol_gap;
-       bool ehs_remove_supported;
-
-       /* Transmitting */
-       int tx_pending_len;             /* -1 while building packet */
-       u8 tx_pending_buf[LBS_UPLD_SIZE];
-       /* protected by hard_start_xmit serialization */
-       u8 txretrycount;
-       struct sk_buff *currenttxskb;
-       struct timer_list tx_lockup_timer;
-
-       /* Locks */
-       struct mutex lock;
-       spinlock_t driver_lock;
-
-       /* NIC/link operation characteristics */
-       u16 mac_control;
-       u8 radio_on;
-       u8 cur_rate;
-       u8 channel;
-       s16 txpower_cur;
-       s16 txpower_min;
-       s16 txpower_max;
-
-       /* Scanning */
-       struct delayed_work scan_work;
-       int scan_channel;
-       /* Queue of things waiting for scan completion */
-       wait_queue_head_t scan_q;
-       /* Whether the scan was initiated internally and not by cfg80211 */
-       bool internal_scan;
-
-       /* Firmware load */
-       u32 fw_model;
-       wait_queue_head_t fw_waitq;
-       struct device *fw_device;
-       const struct firmware *helper_fw;
-       const struct lbs_fw_table *fw_table;
-       const struct lbs_fw_table *fw_iter;
-       lbs_fw_cb fw_callback;
-};
-
-extern struct cmd_confirm_sleep confirm_sleep;
-
-/* Check if there is an interface active. */
-static inline int lbs_iface_active(struct lbs_private *priv)
-{
-       int r;
-
-       r = netif_running(priv->dev);
-       if (priv->mesh_dev)
-               r |= netif_running(priv->mesh_dev);
-
-       return r;
-}
-
-#endif
diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c
deleted file mode 100644 (file)
index f955b2d..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-#include <linux/hardirq.h>
-#include <linux/netdevice.h>
-#include <linux/ethtool.h>
-#include <linux/delay.h>
-
-#include "decl.h"
-#include "cmd.h"
-#include "mesh.h"
-
-
-static void lbs_ethtool_get_drvinfo(struct net_device *dev,
-                                        struct ethtool_drvinfo *info)
-{
-       struct lbs_private *priv = dev->ml_priv;
-
-       snprintf(info->fw_version, sizeof(info->fw_version),
-               "%u.%u.%u.p%u",
-               priv->fwrelease >> 24 & 0xff,
-               priv->fwrelease >> 16 & 0xff,
-               priv->fwrelease >>  8 & 0xff,
-               priv->fwrelease       & 0xff);
-       strlcpy(info->driver, "libertas", sizeof(info->driver));
-       strlcpy(info->version, lbs_driver_version, sizeof(info->version));
-}
-
-/*
- * All 8388 parts have 16KiB EEPROM size at the time of writing.
- * In case that changes this needs fixing.
- */
-#define LBS_EEPROM_LEN 16384
-
-static int lbs_ethtool_get_eeprom_len(struct net_device *dev)
-{
-       return LBS_EEPROM_LEN;
-}
-
-static int lbs_ethtool_get_eeprom(struct net_device *dev,
-                                  struct ethtool_eeprom *eeprom, u8 * bytes)
-{
-       struct lbs_private *priv = dev->ml_priv;
-       struct cmd_ds_802_11_eeprom_access cmd;
-       int ret;
-
-       lbs_deb_enter(LBS_DEB_ETHTOOL);
-
-       if (eeprom->offset + eeprom->len > LBS_EEPROM_LEN ||
-           eeprom->len > LBS_EEPROM_READ_LEN) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       cmd.hdr.size = cpu_to_le16(sizeof(struct cmd_ds_802_11_eeprom_access) -
-               LBS_EEPROM_READ_LEN + eeprom->len);
-       cmd.action = cpu_to_le16(CMD_ACT_GET);
-       cmd.offset = cpu_to_le16(eeprom->offset);
-       cmd.len    = cpu_to_le16(eeprom->len);
-       ret = lbs_cmd_with_response(priv, CMD_802_11_EEPROM_ACCESS, &cmd);
-       if (!ret)
-               memcpy(bytes, cmd.value, eeprom->len);
-
-out:
-       lbs_deb_leave_args(LBS_DEB_ETHTOOL, "ret %d", ret);
-        return ret;
-}
-
-static void lbs_ethtool_get_wol(struct net_device *dev,
-                               struct ethtool_wolinfo *wol)
-{
-       struct lbs_private *priv = dev->ml_priv;
-
-       wol->supported = WAKE_UCAST|WAKE_MCAST|WAKE_BCAST|WAKE_PHY;
-
-       if (priv->wol_criteria == EHS_REMOVE_WAKEUP)
-               return;
-
-       if (priv->wol_criteria & EHS_WAKE_ON_UNICAST_DATA)
-               wol->wolopts |= WAKE_UCAST;
-       if (priv->wol_criteria & EHS_WAKE_ON_MULTICAST_DATA)
-               wol->wolopts |= WAKE_MCAST;
-       if (priv->wol_criteria & EHS_WAKE_ON_BROADCAST_DATA)
-               wol->wolopts |= WAKE_BCAST;
-       if (priv->wol_criteria & EHS_WAKE_ON_MAC_EVENT)
-               wol->wolopts |= WAKE_PHY;
-}
-
-static int lbs_ethtool_set_wol(struct net_device *dev,
-                              struct ethtool_wolinfo *wol)
-{
-       struct lbs_private *priv = dev->ml_priv;
-
-       if (wol->wolopts & ~(WAKE_UCAST|WAKE_MCAST|WAKE_BCAST|WAKE_PHY))
-               return -EOPNOTSUPP;
-
-       priv->wol_criteria = 0;
-       if (wol->wolopts & WAKE_UCAST)
-               priv->wol_criteria |= EHS_WAKE_ON_UNICAST_DATA;
-       if (wol->wolopts & WAKE_MCAST)
-               priv->wol_criteria |= EHS_WAKE_ON_MULTICAST_DATA;
-       if (wol->wolopts & WAKE_BCAST)
-               priv->wol_criteria |= EHS_WAKE_ON_BROADCAST_DATA;
-       if (wol->wolopts & WAKE_PHY)
-               priv->wol_criteria |= EHS_WAKE_ON_MAC_EVENT;
-       if (wol->wolopts == 0)
-               priv->wol_criteria |= EHS_REMOVE_WAKEUP;
-       return 0;
-}
-
-const struct ethtool_ops lbs_ethtool_ops = {
-       .get_drvinfo = lbs_ethtool_get_drvinfo,
-       .get_eeprom =  lbs_ethtool_get_eeprom,
-       .get_eeprom_len = lbs_ethtool_get_eeprom_len,
-#ifdef CONFIG_LIBERTAS_MESH
-       .get_sset_count = lbs_mesh_ethtool_get_sset_count,
-       .get_ethtool_stats = lbs_mesh_ethtool_get_stats,
-       .get_strings = lbs_mesh_ethtool_get_strings,
-#endif
-       .get_wol = lbs_ethtool_get_wol,
-       .set_wol = lbs_ethtool_set_wol,
-};
-
diff --git a/drivers/net/wireless/libertas/firmware.c b/drivers/net/wireless/libertas/firmware.c
deleted file mode 100644 (file)
index 51b92b5..0000000
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Firmware loading and handling functions.
- */
-
-#include <linux/sched.h>
-#include <linux/firmware.h>
-#include <linux/module.h>
-
-#include "dev.h"
-#include "decl.h"
-
-static void load_next_firmware_from_table(struct lbs_private *private);
-
-static void lbs_fw_loaded(struct lbs_private *priv, int ret,
-       const struct firmware *helper, const struct firmware *mainfw)
-{
-       unsigned long flags;
-
-       lbs_deb_fw("firmware load complete, code %d\n", ret);
-
-       /* User must free helper/mainfw */
-       priv->fw_callback(priv, ret, helper, mainfw);
-
-       spin_lock_irqsave(&priv->driver_lock, flags);
-       priv->fw_callback = NULL;
-       wake_up(&priv->fw_waitq);
-       spin_unlock_irqrestore(&priv->driver_lock, flags);
-}
-
-static void do_load_firmware(struct lbs_private *priv, const char *name,
-       void (*cb)(const struct firmware *fw, void *context))
-{
-       int ret;
-
-       lbs_deb_fw("Requesting %s\n", name);
-       ret = request_firmware_nowait(THIS_MODULE, true, name,
-                       priv->fw_device, GFP_KERNEL, priv, cb);
-       if (ret) {
-               lbs_deb_fw("request_firmware_nowait error %d\n", ret);
-               lbs_fw_loaded(priv, ret, NULL, NULL);
-       }
-}
-
-static void main_firmware_cb(const struct firmware *firmware, void *context)
-{
-       struct lbs_private *priv = context;
-
-       if (!firmware) {
-               /* Failed to find firmware: try next table entry */
-               load_next_firmware_from_table(priv);
-               return;
-       }
-
-       /* Firmware found! */
-       lbs_fw_loaded(priv, 0, priv->helper_fw, firmware);
-       if (priv->helper_fw) {
-               release_firmware (priv->helper_fw);
-               priv->helper_fw = NULL;
-       }
-       release_firmware (firmware);
-}
-
-static void helper_firmware_cb(const struct firmware *firmware, void *context)
-{
-       struct lbs_private *priv = context;
-
-       if (!firmware) {
-               /* Failed to find firmware: try next table entry */
-               load_next_firmware_from_table(priv);
-               return;
-       }
-
-       /* Firmware found! */
-       if (priv->fw_iter->fwname) {
-               priv->helper_fw = firmware;
-               do_load_firmware(priv, priv->fw_iter->fwname, main_firmware_cb);
-       } else {
-               /* No main firmware needed for this helper --> success! */
-               lbs_fw_loaded(priv, 0, firmware, NULL);
-       }
-}
-
-static void load_next_firmware_from_table(struct lbs_private *priv)
-{
-       const struct lbs_fw_table *iter;
-
-       if (!priv->fw_iter)
-               iter = priv->fw_table;
-       else
-               iter = ++priv->fw_iter;
-
-       if (priv->helper_fw) {
-               release_firmware(priv->helper_fw);
-               priv->helper_fw = NULL;
-       }
-
-next:
-       if (!iter->helper) {
-               /* End of table hit. */
-               lbs_fw_loaded(priv, -ENOENT, NULL, NULL);
-               return;
-       }
-
-       if (iter->model != priv->fw_model) {
-               iter++;
-               goto next;
-       }
-
-       priv->fw_iter = iter;
-       do_load_firmware(priv, iter->helper, helper_firmware_cb);
-}
-
-void lbs_wait_for_firmware_load(struct lbs_private *priv)
-{
-       wait_event(priv->fw_waitq, priv->fw_callback == NULL);
-}
-
-/**
- *  lbs_get_firmware_async - Retrieves firmware asynchronously. Can load
- *  either a helper firmware and a main firmware (2-stage), or just the helper.
- *
- *  @priv:      Pointer to lbs_private instance
- *  @dev:      A pointer to &device structure
- *  @card_model: Bus-specific card model ID used to filter firmware table
- *             elements
- *  @fw_table: Table of firmware file names and device model numbers
- *             terminated by an entry with a NULL helper name
- *     @callback: User callback to invoke when firmware load succeeds or fails.
- */
-int lbs_get_firmware_async(struct lbs_private *priv, struct device *device,
-                           u32 card_model, const struct lbs_fw_table *fw_table,
-                           lbs_fw_cb callback)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&priv->driver_lock, flags);
-       if (priv->fw_callback) {
-               lbs_deb_fw("firmware load already in progress\n");
-               spin_unlock_irqrestore(&priv->driver_lock, flags);
-               return -EBUSY;
-       }
-
-       priv->fw_device = device;
-       priv->fw_callback = callback;
-       priv->fw_table = fw_table;
-       priv->fw_iter = NULL;
-       priv->fw_model = card_model;
-       spin_unlock_irqrestore(&priv->driver_lock, flags);
-
-       lbs_deb_fw("Starting async firmware load\n");
-       load_next_firmware_from_table(priv);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(lbs_get_firmware_async);
-
-/**
- *  lbs_get_firmware - Retrieves two-stage firmware
- *
- *  @dev:      A pointer to &device structure
- *  @card_model: Bus-specific card model ID used to filter firmware table
- *             elements
- *  @fw_table: Table of firmware file names and device model numbers
- *             terminated by an entry with a NULL helper name
- *  @helper:   On success, the helper firmware; caller must free
- *  @mainfw:   On success, the main firmware; caller must free
- *
- * Deprecated: use lbs_get_firmware_async() instead.
- *
- *  returns:           0 on success, non-zero on failure
- */
-int lbs_get_firmware(struct device *dev, u32 card_model,
-                       const struct lbs_fw_table *fw_table,
-                       const struct firmware **helper,
-                       const struct firmware **mainfw)
-{
-       const struct lbs_fw_table *iter;
-       int ret;
-
-       BUG_ON(helper == NULL);
-       BUG_ON(mainfw == NULL);
-
-       /* Search for firmware to use from the table. */
-       iter = fw_table;
-       while (iter && iter->helper) {
-               if (iter->model != card_model)
-                       goto next;
-
-               if (*helper == NULL) {
-                       ret = request_firmware(helper, iter->helper, dev);
-                       if (ret)
-                               goto next;
-
-                       /* If the device has one-stage firmware (ie cf8305) and
-                        * we've got it then we don't need to bother with the
-                        * main firmware.
-                        */
-                       if (iter->fwname == NULL)
-                               return 0;
-               }
-
-               if (*mainfw == NULL) {
-                       ret = request_firmware(mainfw, iter->fwname, dev);
-                       if (ret) {
-                               /* Clear the helper to ensure we don't have
-                                * mismatched firmware pairs.
-                                */
-                               release_firmware(*helper);
-                               *helper = NULL;
-                       }
-               }
-
-               if (*helper && *mainfw)
-                       return 0;
-
-  next:
-               iter++;
-       }
-
-       /* Failed */
-       release_firmware(*helper);
-       *helper = NULL;
-       release_firmware(*mainfw);
-       *mainfw = NULL;
-
-       return -ENOENT;
-}
-EXPORT_SYMBOL_GPL(lbs_get_firmware);
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
deleted file mode 100644 (file)
index 96726f7..0000000
+++ /dev/null
@@ -1,978 +0,0 @@
-/*
- * This file function prototypes, data structure
- * and  definitions for all the host/station commands
- */
-
-#ifndef _LBS_HOST_H_
-#define _LBS_HOST_H_
-
-#include "types.h"
-#include "defs.h"
-
-#define DEFAULT_AD_HOC_CHANNEL                  6
-
-#define CMD_OPTION_WAITFORRSP                   0x0002
-
-/* Host command IDs */
-
-/*
- * Return command are almost always the same as the host command, but with
- * bit 15 set high.  There are a few exceptions, though...
- */
-#define CMD_RET(cmd)                            (0x8000 | cmd)
-
-/* Return command convention exceptions: */
-#define CMD_RET_802_11_ASSOCIATE                0x8012
-
-/* Command codes */
-#define CMD_GET_HW_SPEC                         0x0003
-#define CMD_EEPROM_UPDATE                       0x0004
-#define CMD_802_11_RESET                        0x0005
-#define CMD_802_11_SCAN                         0x0006
-#define CMD_802_11_GET_LOG                      0x000b
-#define CMD_MAC_MULTICAST_ADR                   0x0010
-#define CMD_802_11_AUTHENTICATE                 0x0011
-#define CMD_802_11_EEPROM_ACCESS                0x0059
-#define CMD_802_11_ASSOCIATE                    0x0050
-#define CMD_802_11_SET_WEP                      0x0013
-#define CMD_802_11_GET_STAT                     0x0014
-#define CMD_802_3_GET_STAT                      0x0015
-#define CMD_802_11_SNMP_MIB                     0x0016
-#define CMD_MAC_REG_MAP                         0x0017
-#define CMD_BBP_REG_MAP                         0x0018
-#define CMD_MAC_REG_ACCESS                      0x0019
-#define CMD_BBP_REG_ACCESS                      0x001a
-#define CMD_RF_REG_ACCESS                       0x001b
-#define CMD_802_11_RADIO_CONTROL                0x001c
-#define CMD_802_11_RF_CHANNEL                   0x001d
-#define CMD_802_11_RF_TX_POWER                  0x001e
-#define CMD_802_11_RSSI                         0x001f
-#define CMD_802_11_RF_ANTENNA                   0x0020
-#define CMD_802_11_PS_MODE                      0x0021
-#define CMD_802_11_DATA_RATE                    0x0022
-#define CMD_RF_REG_MAP                          0x0023
-#define CMD_802_11_DEAUTHENTICATE               0x0024
-#define CMD_802_11_REASSOCIATE                  0x0025
-#define CMD_MAC_CONTROL                         0x0028
-#define CMD_802_11_AD_HOC_START                 0x002b
-#define CMD_802_11_AD_HOC_JOIN                  0x002c
-#define CMD_802_11_QUERY_TKIP_REPLY_CNTRS       0x002e
-#define CMD_802_11_ENABLE_RSN                   0x002f
-#define CMD_802_11_SET_AFC                      0x003c
-#define CMD_802_11_GET_AFC                      0x003d
-#define CMD_802_11_DEEP_SLEEP                   0x003e
-#define CMD_802_11_AD_HOC_STOP                  0x0040
-#define CMD_802_11_HOST_SLEEP_CFG               0x0043
-#define CMD_802_11_WAKEUP_CONFIRM               0x0044
-#define CMD_802_11_HOST_SLEEP_ACTIVATE          0x0045
-#define CMD_802_11_BEACON_STOP                  0x0049
-#define CMD_802_11_MAC_ADDRESS                  0x004d
-#define CMD_802_11_LED_GPIO_CTRL                0x004e
-#define CMD_802_11_BAND_CONFIG                  0x0058
-#define CMD_GSPI_BUS_CONFIG                     0x005a
-#define CMD_802_11D_DOMAIN_INFO                 0x005b
-#define CMD_802_11_KEY_MATERIAL                 0x005e
-#define CMD_802_11_SLEEP_PARAMS                 0x0066
-#define CMD_802_11_INACTIVITY_TIMEOUT           0x0067
-#define CMD_802_11_SLEEP_PERIOD                 0x0068
-#define CMD_802_11_TPC_CFG                      0x0072
-#define CMD_802_11_PA_CFG                       0x0073
-#define CMD_802_11_FW_WAKE_METHOD               0x0074
-#define CMD_802_11_SUBSCRIBE_EVENT              0x0075
-#define CMD_802_11_RATE_ADAPT_RATESET           0x0076
-#define CMD_802_11_TX_RATE_QUERY                0x007f
-#define CMD_GET_TSF                             0x0080
-#define CMD_BT_ACCESS                           0x0087
-#define CMD_FWT_ACCESS                          0x0095
-#define CMD_802_11_MONITOR_MODE                 0x0098
-#define CMD_MESH_ACCESS                         0x009b
-#define CMD_MESH_CONFIG_OLD                     0x00a3
-#define CMD_MESH_CONFIG                         0x00ac
-#define CMD_SET_BOOT2_VER                       0x00a5
-#define CMD_FUNC_INIT                           0x00a9
-#define CMD_FUNC_SHUTDOWN                       0x00aa
-#define CMD_802_11_BEACON_CTRL                  0x00b0
-
-/* For the IEEE Power Save */
-#define PS_MODE_ACTION_ENTER_PS                 0x0030
-#define PS_MODE_ACTION_EXIT_PS                  0x0031
-#define PS_MODE_ACTION_SLEEP_CONFIRMED          0x0034
-
-#define CMD_ENABLE_RSN                          0x0001
-#define CMD_DISABLE_RSN                         0x0000
-
-#define CMD_ACT_GET                             0x0000
-#define CMD_ACT_SET                             0x0001
-
-/* Define action or option for CMD_802_11_SET_WEP */
-#define CMD_ACT_ADD                             0x0002
-#define CMD_ACT_REMOVE                          0x0004
-
-#define CMD_TYPE_WEP_40_BIT                     0x01
-#define CMD_TYPE_WEP_104_BIT                    0x02
-
-#define CMD_NUM_OF_WEP_KEYS                     4
-
-#define CMD_WEP_KEY_INDEX_MASK                  0x3fff
-
-/* Define action or option for CMD_802_11_SCAN */
-#define CMD_BSS_TYPE_BSS                        0x0001
-#define CMD_BSS_TYPE_IBSS                       0x0002
-#define CMD_BSS_TYPE_ANY                        0x0003
-
-/* Define action or option for CMD_802_11_SCAN */
-#define CMD_SCAN_TYPE_ACTIVE                    0x0000
-#define CMD_SCAN_TYPE_PASSIVE                   0x0001
-
-#define CMD_SCAN_RADIO_TYPE_BG                  0
-
-#define CMD_SCAN_PROBE_DELAY_TIME               0
-
-/* Define action or option for CMD_MAC_CONTROL */
-#define CMD_ACT_MAC_RX_ON                       0x0001
-#define CMD_ACT_MAC_TX_ON                       0x0002
-#define CMD_ACT_MAC_LOOPBACK_ON                 0x0004
-#define CMD_ACT_MAC_WEP_ENABLE                  0x0008
-#define CMD_ACT_MAC_INT_ENABLE                  0x0010
-#define CMD_ACT_MAC_MULTICAST_ENABLE            0x0020
-#define CMD_ACT_MAC_BROADCAST_ENABLE            0x0040
-#define CMD_ACT_MAC_PROMISCUOUS_ENABLE          0x0080
-#define CMD_ACT_MAC_ALL_MULTICAST_ENABLE        0x0100
-#define CMD_ACT_MAC_STRICT_PROTECTION_ENABLE    0x0400
-
-/* Event flags for CMD_802_11_SUBSCRIBE_EVENT */
-#define CMD_SUBSCRIBE_RSSI_LOW                  0x0001
-#define CMD_SUBSCRIBE_SNR_LOW                   0x0002
-#define CMD_SUBSCRIBE_FAILCOUNT                 0x0004
-#define CMD_SUBSCRIBE_BCNMISS                   0x0008
-#define CMD_SUBSCRIBE_RSSI_HIGH                 0x0010
-#define CMD_SUBSCRIBE_SNR_HIGH                  0x0020
-
-#define RADIO_PREAMBLE_LONG                     0x00
-#define RADIO_PREAMBLE_SHORT                    0x02
-#define RADIO_PREAMBLE_AUTO                     0x04
-
-/* Define action or option for CMD_802_11_RF_CHANNEL */
-#define CMD_OPT_802_11_RF_CHANNEL_GET           0x00
-#define CMD_OPT_802_11_RF_CHANNEL_SET           0x01
-
-/* Define action or option for CMD_802_11_DATA_RATE */
-#define CMD_ACT_SET_TX_AUTO                     0x0000
-#define CMD_ACT_SET_TX_FIX_RATE                 0x0001
-#define CMD_ACT_GET_TX_RATE                     0x0002
-
-/* Options for CMD_802_11_FW_WAKE_METHOD */
-#define CMD_WAKE_METHOD_UNCHANGED               0x0000
-#define CMD_WAKE_METHOD_COMMAND_INT             0x0001
-#define CMD_WAKE_METHOD_GPIO                    0x0002
-
-/* Object IDs for CMD_802_11_SNMP_MIB */
-#define SNMP_MIB_OID_BSS_TYPE                   0x0000
-#define SNMP_MIB_OID_OP_RATE_SET                0x0001
-#define SNMP_MIB_OID_BEACON_PERIOD              0x0002  /* Reserved on v9+ */
-#define SNMP_MIB_OID_DTIM_PERIOD                0x0003  /* Reserved on v9+ */
-#define SNMP_MIB_OID_ASSOC_TIMEOUT              0x0004  /* Reserved on v9+ */
-#define SNMP_MIB_OID_RTS_THRESHOLD              0x0005
-#define SNMP_MIB_OID_SHORT_RETRY_LIMIT          0x0006
-#define SNMP_MIB_OID_LONG_RETRY_LIMIT           0x0007
-#define SNMP_MIB_OID_FRAG_THRESHOLD             0x0008
-#define SNMP_MIB_OID_11D_ENABLE                 0x0009
-#define SNMP_MIB_OID_11H_ENABLE                 0x000A
-
-/* Define action or option for CMD_BT_ACCESS */
-enum cmd_bt_access_opts {
-       /* The bt commands start at 5 instead of 1 because the old dft commands
-        * are mapped to 1-4.  These old commands are no longer maintained and
-        * should not be called.
-        */
-       CMD_ACT_BT_ACCESS_ADD = 5,
-       CMD_ACT_BT_ACCESS_DEL,
-       CMD_ACT_BT_ACCESS_LIST,
-       CMD_ACT_BT_ACCESS_RESET,
-       CMD_ACT_BT_ACCESS_SET_INVERT,
-       CMD_ACT_BT_ACCESS_GET_INVERT
-};
-
-/* Define action or option for CMD_FWT_ACCESS */
-enum cmd_fwt_access_opts {
-       CMD_ACT_FWT_ACCESS_ADD = 1,
-       CMD_ACT_FWT_ACCESS_DEL,
-       CMD_ACT_FWT_ACCESS_LOOKUP,
-       CMD_ACT_FWT_ACCESS_LIST,
-       CMD_ACT_FWT_ACCESS_LIST_ROUTE,
-       CMD_ACT_FWT_ACCESS_LIST_NEIGHBOR,
-       CMD_ACT_FWT_ACCESS_RESET,
-       CMD_ACT_FWT_ACCESS_CLEANUP,
-       CMD_ACT_FWT_ACCESS_TIME,
-};
-
-/* Define action or option for CMD_802_11_HOST_SLEEP_CFG */
-enum cmd_wol_cfg_opts {
-       CMD_ACT_ACTION_NONE = 0,
-       CMD_ACT_SET_WOL_RULE,
-       CMD_ACT_GET_WOL_RULE,
-       CMD_ACT_RESET_WOL_RULE,
-};
-
-/* Define action or option for CMD_MESH_ACCESS */
-enum cmd_mesh_access_opts {
-       CMD_ACT_MESH_GET_TTL = 1,
-       CMD_ACT_MESH_SET_TTL,
-       CMD_ACT_MESH_GET_STATS,
-       CMD_ACT_MESH_GET_ANYCAST,
-       CMD_ACT_MESH_SET_ANYCAST,
-       CMD_ACT_MESH_SET_LINK_COSTS,
-       CMD_ACT_MESH_GET_LINK_COSTS,
-       CMD_ACT_MESH_SET_BCAST_RATE,
-       CMD_ACT_MESH_GET_BCAST_RATE,
-       CMD_ACT_MESH_SET_RREQ_DELAY,
-       CMD_ACT_MESH_GET_RREQ_DELAY,
-       CMD_ACT_MESH_SET_ROUTE_EXP,
-       CMD_ACT_MESH_GET_ROUTE_EXP,
-       CMD_ACT_MESH_SET_AUTOSTART_ENABLED,
-       CMD_ACT_MESH_GET_AUTOSTART_ENABLED,
-       CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT = 17,
-};
-
-/* Define actions and types for CMD_MESH_CONFIG */
-enum cmd_mesh_config_actions {
-       CMD_ACT_MESH_CONFIG_STOP = 0,
-       CMD_ACT_MESH_CONFIG_START,
-       CMD_ACT_MESH_CONFIG_SET,
-       CMD_ACT_MESH_CONFIG_GET,
-};
-
-enum cmd_mesh_config_types {
-       CMD_TYPE_MESH_SET_BOOTFLAG = 1,
-       CMD_TYPE_MESH_SET_BOOTTIME,
-       CMD_TYPE_MESH_SET_DEF_CHANNEL,
-       CMD_TYPE_MESH_SET_MESH_IE,
-       CMD_TYPE_MESH_GET_DEFAULTS,
-       CMD_TYPE_MESH_GET_MESH_IE, /* GET_DEFAULTS is superset of GET_MESHIE */
-};
-
-/* Card Event definition */
-#define MACREG_INT_CODE_TX_PPA_FREE            0
-#define MACREG_INT_CODE_TX_DMA_DONE            1
-#define MACREG_INT_CODE_LINK_LOST_W_SCAN       2
-#define MACREG_INT_CODE_LINK_LOST_NO_SCAN      3
-#define MACREG_INT_CODE_LINK_SENSED            4
-#define MACREG_INT_CODE_CMD_FINISHED           5
-#define MACREG_INT_CODE_MIB_CHANGED            6
-#define MACREG_INT_CODE_INIT_DONE              7
-#define MACREG_INT_CODE_DEAUTHENTICATED                8
-#define MACREG_INT_CODE_DISASSOCIATED          9
-#define MACREG_INT_CODE_PS_AWAKE               10
-#define MACREG_INT_CODE_PS_SLEEP               11
-#define MACREG_INT_CODE_MIC_ERR_MULTICAST      13
-#define MACREG_INT_CODE_MIC_ERR_UNICAST                14
-#define MACREG_INT_CODE_WM_AWAKE               15
-#define MACREG_INT_CODE_DEEP_SLEEP_AWAKE       16
-#define MACREG_INT_CODE_ADHOC_BCN_LOST         17
-#define MACREG_INT_CODE_HOST_AWAKE             18
-#define MACREG_INT_CODE_STOP_TX                        19
-#define MACREG_INT_CODE_START_TX               20
-#define MACREG_INT_CODE_CHANNEL_SWITCH         21
-#define MACREG_INT_CODE_MEASUREMENT_RDY                22
-#define MACREG_INT_CODE_WMM_CHANGE             23
-#define MACREG_INT_CODE_BG_SCAN_REPORT         24
-#define MACREG_INT_CODE_RSSI_LOW               25
-#define MACREG_INT_CODE_SNR_LOW                        26
-#define MACREG_INT_CODE_MAX_FAIL               27
-#define MACREG_INT_CODE_RSSI_HIGH              28
-#define MACREG_INT_CODE_SNR_HIGH               29
-#define MACREG_INT_CODE_MESH_AUTO_STARTED      35
-#define MACREG_INT_CODE_FIRMWARE_READY         48
-
-
-/* 802.11-related definitions */
-
-/* TxPD descriptor */
-struct txpd {
-       /* union to cope up with later FW revisions */
-       union {
-               /* Current Tx packet status */
-               __le32 tx_status;
-               struct {
-                       /* BSS type: client, AP, etc. */
-                       u8 bss_type;
-                       /* BSS number */
-                       u8 bss_num;
-                       /* Reserved */
-                       __le16 reserved;
-               } bss;
-       } u;
-       /* Tx control */
-       __le32 tx_control;
-       __le32 tx_packet_location;
-       /* Tx packet length */
-       __le16 tx_packet_length;
-       /* First 2 byte of destination MAC address */
-       u8 tx_dest_addr_high[2];
-       /* Last 4 byte of destination MAC address */
-       u8 tx_dest_addr_low[4];
-       /* Pkt Priority */
-       u8 priority;
-       /* Pkt Trasnit Power control */
-       u8 powermgmt;
-       /* Amount of time the packet has been queued (units = 2ms) */
-       u8 pktdelay_2ms;
-       /* reserved */
-       u8 reserved1;
-} __packed;
-
-/* RxPD Descriptor */
-struct rxpd {
-       /* union to cope up with later FW revisions */
-       union {
-               /* Current Rx packet status */
-               __le16 status;
-               struct {
-                       /* BSS type: client, AP, etc. */
-                       u8 bss_type;
-                       /* BSS number */
-                       u8 bss_num;
-               } __packed bss;
-       } __packed u;
-
-       /* SNR */
-       u8 snr;
-
-       /* Tx control */
-       u8 rx_control;
-
-       /* Pkt length */
-       __le16 pkt_len;
-
-       /* Noise Floor */
-       u8 nf;
-
-       /* Rx Packet Rate */
-       u8 rx_rate;
-
-       /* Pkt addr */
-       __le32 pkt_ptr;
-
-       /* Next Rx RxPD addr */
-       __le32 next_rxpd_ptr;
-
-       /* Pkt Priority */
-       u8 priority;
-       u8 reserved[3];
-} __packed;
-
-struct cmd_header {
-       __le16 command;
-       __le16 size;
-       __le16 seqnum;
-       __le16 result;
-} __packed;
-
-/* Generic structure to hold all key types. */
-struct enc_key {
-       u16 len;
-       u16 flags;  /* KEY_INFO_* from defs.h */
-       u16 type; /* KEY_TYPE_* from defs.h */
-       u8 key[32];
-};
-
-/* lbs_offset_value */
-struct lbs_offset_value {
-       u32 offset;
-       u32 value;
-} __packed;
-
-#define MAX_11D_TRIPLETS       83
-
-struct mrvl_ie_domain_param_set {
-       struct mrvl_ie_header header;
-
-       u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
-       struct ieee80211_country_ie_triplet triplet[MAX_11D_TRIPLETS];
-} __packed;
-
-struct cmd_ds_802_11d_domain_info {
-       struct cmd_header hdr;
-
-       __le16 action;
-       struct mrvl_ie_domain_param_set domain;
-} __packed;
-
-/*
- * Define data structure for CMD_GET_HW_SPEC
- * This structure defines the response for the GET_HW_SPEC command
- */
-struct cmd_ds_get_hw_spec {
-       struct cmd_header hdr;
-
-       /* HW Interface version number */
-       __le16 hwifversion;
-       /* HW version number */
-       __le16 version;
-       /* Max number of TxPD FW can handle */
-       __le16 nr_txpd;
-       /* Max no of Multicast address */
-       __le16 nr_mcast_adr;
-       /* MAC address */
-       u8 permanentaddr[6];
-
-       /* region Code */
-       __le16 regioncode;
-
-       /* Number of antenna used */
-       __le16 nr_antenna;
-
-       /* FW release number, example 0x01030304 = 2.3.4p1 */
-       __le32 fwrelease;
-
-       /* Base Address of TxPD queue */
-       __le32 wcb_base;
-       /* Read Pointer of RxPd queue */
-       __le32 rxpd_rdptr;
-
-       /* Write Pointer of RxPd queue */
-       __le32 rxpd_wrptr;
-
-       /*FW/HW capability */
-       __le32 fwcapinfo;
-} __packed;
-
-struct cmd_ds_802_11_subscribe_event {
-       struct cmd_header hdr;
-
-       __le16 action;
-       __le16 events;
-
-       /* A TLV to the CMD_802_11_SUBSCRIBE_EVENT command can contain a
-        * number of TLVs. From the v5.1 manual, those TLVs would add up to
-        * 40 bytes. However, future firmware might add additional TLVs, so I
-        * bump this up a bit.
-        */
-       uint8_t tlv[128];
-} __packed;
-
-/*
- * This scan handle Country Information IE(802.11d compliant)
- * Define data structure for CMD_802_11_SCAN
- */
-struct cmd_ds_802_11_scan {
-       struct cmd_header hdr;
-
-       uint8_t bsstype;
-       uint8_t bssid[ETH_ALEN];
-       uint8_t tlvbuffer[0];
-} __packed;
-
-struct cmd_ds_802_11_scan_rsp {
-       struct cmd_header hdr;
-
-       __le16 bssdescriptsize;
-       uint8_t nr_sets;
-       uint8_t bssdesc_and_tlvbuffer[0];
-} __packed;
-
-struct cmd_ds_802_11_get_log {
-       struct cmd_header hdr;
-
-       __le32 mcasttxframe;
-       __le32 failed;
-       __le32 retry;
-       __le32 multiretry;
-       __le32 framedup;
-       __le32 rtssuccess;
-       __le32 rtsfailure;
-       __le32 ackfailure;
-       __le32 rxfrag;
-       __le32 mcastrxframe;
-       __le32 fcserror;
-       __le32 txframe;
-       __le32 wepundecryptable;
-} __packed;
-
-struct cmd_ds_mac_control {
-       struct cmd_header hdr;
-       __le16 action;
-       u16 reserved;
-} __packed;
-
-struct cmd_ds_mac_multicast_adr {
-       struct cmd_header hdr;
-       __le16 action;
-       __le16 nr_of_adrs;
-       u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE];
-} __packed;
-
-struct cmd_ds_802_11_authenticate {
-       struct cmd_header hdr;
-
-       u8 bssid[ETH_ALEN];
-       u8 authtype;
-       u8 reserved[10];
-} __packed;
-
-struct cmd_ds_802_11_deauthenticate {
-       struct cmd_header hdr;
-
-       u8 macaddr[ETH_ALEN];
-       __le16 reasoncode;
-} __packed;
-
-struct cmd_ds_802_11_associate {
-       struct cmd_header hdr;
-
-       u8 bssid[6];
-       __le16 capability;
-       __le16 listeninterval;
-       __le16 bcnperiod;
-       u8 dtimperiod;
-       u8 iebuf[512];    /* Enough for required and most optional IEs */
-} __packed;
-
-struct cmd_ds_802_11_associate_response {
-       struct cmd_header hdr;
-
-       __le16 capability;
-       __le16 statuscode;
-       __le16 aid;
-       u8 iebuf[512];
-} __packed;
-
-struct cmd_ds_802_11_set_wep {
-       struct cmd_header hdr;
-
-       /* ACT_ADD, ACT_REMOVE or ACT_ENABLE */
-       __le16 action;
-
-       /* key Index selected for Tx */
-       __le16 keyindex;
-
-       /* 40, 128bit or TXWEP */
-       uint8_t keytype[4];
-       uint8_t keymaterial[4][16];
-} __packed;
-
-struct cmd_ds_802_11_snmp_mib {
-       struct cmd_header hdr;
-
-       __le16 action;
-       __le16 oid;
-       __le16 bufsize;
-       u8 value[128];
-} __packed;
-
-struct cmd_ds_reg_access {
-       struct cmd_header hdr;
-
-       __le16 action;
-       __le16 offset;
-       union {
-               u8 bbp_rf;  /* for BBP and RF registers */
-               __le32 mac; /* for MAC registers */
-       } value;
-} __packed;
-
-struct cmd_ds_802_11_radio_control {
-       struct cmd_header hdr;
-
-       __le16 action;
-       __le16 control;
-} __packed;
-
-struct cmd_ds_802_11_beacon_control {
-       struct cmd_header hdr;
-
-       __le16 action;
-       __le16 beacon_enable;
-       __le16 beacon_period;
-} __packed;
-
-struct cmd_ds_802_11_sleep_params {
-       struct cmd_header hdr;
-
-       /* ACT_GET/ACT_SET */
-       __le16 action;
-
-       /* Sleep clock error in ppm */
-       __le16 error;
-
-       /* Wakeup offset in usec */
-       __le16 offset;
-
-       /* Clock stabilization time in usec */
-       __le16 stabletime;
-
-       /* control periodic calibration */
-       uint8_t calcontrol;
-
-       /* control the use of external sleep clock */
-       uint8_t externalsleepclk;
-
-       /* reserved field, should be set to zero */
-       __le16 reserved;
-} __packed;
-
-struct cmd_ds_802_11_rf_channel {
-       struct cmd_header hdr;
-
-       __le16 action;
-       __le16 channel;
-       __le16 rftype;      /* unused */
-       __le16 reserved;    /* unused */
-       u8 channellist[32]; /* unused */
-} __packed;
-
-struct cmd_ds_802_11_rssi {
-       struct cmd_header hdr;
-
-       /*
-        * request:  number of beacons (N) to average the SNR and NF over
-        * response: SNR of most recent beacon
-        */
-       __le16 n_or_snr;
-
-       /*
-        * The following fields are only set in the response.
-        * In the request these are reserved and should be set to 0.
-        */
-       __le16 nf;       /* most recent beacon noise floor */
-       __le16 avg_snr;  /* average SNR weighted by N from request */
-       __le16 avg_nf;   /* average noise floor weighted by N from request */
-} __packed;
-
-struct cmd_ds_802_11_mac_address {
-       struct cmd_header hdr;
-
-       __le16 action;
-       u8 macadd[ETH_ALEN];
-} __packed;
-
-struct cmd_ds_802_11_rf_tx_power {
-       struct cmd_header hdr;
-
-       __le16 action;
-       __le16 curlevel;
-       s8 maxlevel;
-       s8 minlevel;
-} __packed;
-
-/* MONITOR_MODE only exists in OLPC v5 firmware */
-struct cmd_ds_802_11_monitor_mode {
-       struct cmd_header hdr;
-
-       __le16 action;
-       __le16 mode;
-} __packed;
-
-struct cmd_ds_set_boot2_ver {
-       struct cmd_header hdr;
-
-       __le16 action;
-       __le16 version;
-} __packed;
-
-struct cmd_ds_802_11_fw_wake_method {
-       struct cmd_header hdr;
-
-       __le16 action;
-       __le16 method;
-} __packed;
-
-struct cmd_ds_802_11_ps_mode {
-       struct cmd_header hdr;
-
-       __le16 action;
-
-       /*
-        * Interval for keepalive in PS mode:
-        * 0x0000 = don't change
-        * 0x001E = firmware default
-        * 0xFFFF = disable
-        */
-       __le16 nullpktinterval;
-
-       /*
-        * Number of DTIM intervals to wake up for:
-        * 0 = don't change
-        * 1 = firmware default
-        * 5 = max
-        */
-       __le16 multipledtim;
-
-       __le16 reserved;
-       __le16 locallisteninterval;
-
-       /*
-        * AdHoc awake period (FW v9+ only):
-        * 0 = don't change
-        * 1 = always awake (IEEE standard behavior)
-        * 2 - 31 = sleep for (n - 1) periods and awake for 1 period
-        * 32 - 254 = invalid
-        * 255 = sleep at each ATIM
-        */
-       __le16 adhoc_awake_period;
-} __packed;
-
-struct cmd_confirm_sleep {
-       struct cmd_header hdr;
-
-       __le16 action;
-       __le16 nullpktinterval;
-       __le16 multipledtim;
-       __le16 reserved;
-       __le16 locallisteninterval;
-} __packed;
-
-struct cmd_ds_802_11_data_rate {
-       struct cmd_header hdr;
-
-       __le16 action;
-       __le16 reserved;
-       u8 rates[MAX_RATES];
-} __packed;
-
-struct cmd_ds_802_11_rate_adapt_rateset {
-       struct cmd_header hdr;
-       __le16 action;
-       __le16 enablehwauto;
-       __le16 bitmap;
-} __packed;
-
-struct cmd_ds_802_11_ad_hoc_start {
-       struct cmd_header hdr;
-
-       u8 ssid[IEEE80211_MAX_SSID_LEN];
-       u8 bsstype;
-       __le16 beaconperiod;
-       u8 dtimperiod;   /* Reserved on v9 and later */
-       struct ieee_ie_ibss_param_set ibss;
-       u8 reserved1[4];
-       struct ieee_ie_ds_param_set ds;
-       u8 reserved2[4];
-       __le16 probedelay;  /* Reserved on v9 and later */
-       __le16 capability;
-       u8 rates[MAX_RATES];
-       u8 tlv_memory_size_pad[100];
-} __packed;
-
-struct cmd_ds_802_11_ad_hoc_result {
-       struct cmd_header hdr;
-
-       u8 pad[3];
-       u8 bssid[ETH_ALEN];
-} __packed;
-
-struct adhoc_bssdesc {
-       u8 bssid[ETH_ALEN];
-       u8 ssid[IEEE80211_MAX_SSID_LEN];
-       u8 type;
-       __le16 beaconperiod;
-       u8 dtimperiod;
-       __le64 timestamp;
-       __le64 localtime;
-       struct ieee_ie_ds_param_set ds;
-       u8 reserved1[4];
-       struct ieee_ie_ibss_param_set ibss;
-       u8 reserved2[4];
-       __le16 capability;
-       u8 rates[MAX_RATES];
-
-       /*
-        * DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the
-        * Adhoc join command and will cause a binary layout mismatch with
-        * the firmware
-        */
-} __packed;
-
-struct cmd_ds_802_11_ad_hoc_join {
-       struct cmd_header hdr;
-
-       struct adhoc_bssdesc bss;
-       __le16 failtimeout;   /* Reserved on v9 and later */
-       __le16 probedelay;    /* Reserved on v9 and later */
-} __packed;
-
-struct cmd_ds_802_11_ad_hoc_stop {
-       struct cmd_header hdr;
-} __packed;
-
-struct cmd_ds_802_11_enable_rsn {
-       struct cmd_header hdr;
-
-       __le16 action;
-       __le16 enable;
-} __packed;
-
-struct MrvlIEtype_keyParamSet {
-       /* type ID */
-       __le16 type;
-
-       /* length of Payload */
-       __le16 length;
-
-       /* type of key: WEP=0, TKIP=1, AES=2 */
-       __le16 keytypeid;
-
-       /* key control Info specific to a keytypeid */
-       __le16 keyinfo;
-
-       /* length of key */
-       __le16 keylen;
-
-       /* key material of size keylen */
-       u8 key[32];
-} __packed;
-
-#define MAX_WOL_RULES          16
-
-struct host_wol_rule {
-       uint8_t rule_no;
-       uint8_t rule_ops;
-       __le16 sig_offset;
-       __le16 sig_length;
-       __le16 reserve;
-       __be32 sig_mask;
-       __be32 signature;
-} __packed;
-
-struct wol_config {
-       uint8_t action;
-       uint8_t pattern;
-       uint8_t no_rules_in_cmd;
-       uint8_t result;
-       struct host_wol_rule rule[MAX_WOL_RULES];
-} __packed;
-
-struct cmd_ds_host_sleep {
-       struct cmd_header hdr;
-       __le32 criteria;
-       uint8_t gpio;
-       uint16_t gap;
-       struct wol_config wol_conf;
-} __packed;
-
-
-
-struct cmd_ds_802_11_key_material {
-       struct cmd_header hdr;
-
-       __le16 action;
-       struct MrvlIEtype_keyParamSet keyParamSet[2];
-} __packed;
-
-struct cmd_ds_802_11_eeprom_access {
-       struct cmd_header hdr;
-       __le16 action;
-       __le16 offset;
-       __le16 len;
-       /* firmware says it returns a maximum of 20 bytes */
-#define LBS_EEPROM_READ_LEN 20
-       u8 value[LBS_EEPROM_READ_LEN];
-} __packed;
-
-struct cmd_ds_802_11_tpc_cfg {
-       struct cmd_header hdr;
-
-       __le16 action;
-       uint8_t enable;
-       int8_t P0;
-       int8_t P1;
-       int8_t P2;
-       uint8_t usesnr;
-} __packed;
-
-
-struct cmd_ds_802_11_pa_cfg {
-       struct cmd_header hdr;
-
-       __le16 action;
-       uint8_t enable;
-       int8_t P0;
-       int8_t P1;
-       int8_t P2;
-} __packed;
-
-
-struct cmd_ds_802_11_led_ctrl {
-       struct cmd_header hdr;
-
-       __le16 action;
-       __le16 numled;
-       u8 data[256];
-} __packed;
-
-/* Automatic Frequency Control */
-struct cmd_ds_802_11_afc {
-       struct cmd_header hdr;
-
-       __le16 afc_auto;
-       union {
-               struct {
-                       __le16 threshold;
-                       __le16 period;
-               };
-               struct {
-                       __le16 timing_offset; /* signed */
-                       __le16 carrier_offset; /* signed */
-               };
-       };
-} __packed;
-
-struct cmd_tx_rate_query {
-       __le16 txrate;
-} __packed;
-
-struct cmd_ds_get_tsf {
-       __le64 tsfvalue;
-} __packed;
-
-struct cmd_ds_bt_access {
-       struct cmd_header hdr;
-
-       __le16 action;
-       __le32 id;
-       u8 addr1[ETH_ALEN];
-       u8 addr2[ETH_ALEN];
-} __packed;
-
-struct cmd_ds_fwt_access {
-       struct cmd_header hdr;
-
-       __le16 action;
-       __le32 id;
-       u8 valid;
-       u8 da[ETH_ALEN];
-       u8 dir;
-       u8 ra[ETH_ALEN];
-       __le32 ssn;
-       __le32 dsn;
-       __le32 metric;
-       u8 rate;
-       u8 hopcount;
-       u8 ttl;
-       __le32 expiration;
-       u8 sleepmode;
-       __le32 snr;
-       __le32 references;
-       u8 prec[ETH_ALEN];
-} __packed;
-
-struct cmd_ds_mesh_config {
-       struct cmd_header hdr;
-
-       __le16 action;
-       __le16 channel;
-       __le16 type;
-       __le16 length;
-       u8 data[128];   /* last position reserved */
-} __packed;
-
-struct cmd_ds_mesh_access {
-       struct cmd_header hdr;
-
-       __le16 action;
-       __le32 data[32];        /* last position reserved */
-} __packed;
-
-/* Number of stats counters returned by the firmware */
-#define MESH_STATS_NUM 8
-#endif
diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
deleted file mode 100644 (file)
index f499efc..0000000
+++ /dev/null
@@ -1,1006 +0,0 @@
-/*
-
-  Driver for the Marvell 8385 based compact flash WLAN cards.
-
-  (C) 2007 by Holger Schurig <hs4233@mail.mn-solutions.de>
-
-  This program is free software; you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with this program; see the file COPYING.  If not, write to
-  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
-  Boston, MA 02110-1301, USA.
-
-*/
-
-#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)
-{
-       lbs_deb_enter(LBS_DEB_CS);
-       if_cs_write16(card, IF_CS_HOST_INT_MASK, 0);
-}
-
-static inline void if_cs_disable_ints(struct if_cs_card *card)
-{
-       lbs_deb_enter(LBS_DEB_CS);
-       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;
-
-       lbs_deb_enter(LBS_DEB_CS);
-       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);
-       lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
-       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;
-
-       lbs_deb_enter(LBS_DEB_CS);
-       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);
-
-       lbs_deb_leave(LBS_DEB_CS);
-}
-
-/*
- * 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;
-
-       lbs_deb_enter(LBS_DEB_CS);
-
-       /* 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:
-       lbs_deb_leave_args(LBS_DEB_CS, "ret %d, len %d", ret, *len);
-       return ret;
-}
-
-static struct sk_buff *if_cs_receive_data(struct lbs_private *priv)
-{
-       struct sk_buff *skb = NULL;
-       u16 len;
-       u8 *data;
-
-       lbs_deb_enter(LBS_DEB_CS);
-
-       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:
-       lbs_deb_leave_args(LBS_DEB_CS, "ret %p", skb);
-       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;
-
-       lbs_deb_enter(LBS_DEB_CS);
-
-       /* 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);
-
-       lbs_deb_leave(LBS_DEB_CS);
-       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;
-
-       lbs_deb_enter(LBS_DEB_CS);
-
-       /*
-        * 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:
-       lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
-       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_enter(LBS_DEB_CS);
-
-       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:
-       lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
-       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;
-
-       lbs_deb_enter_args(LBS_DEB_CS, "type %d, bytes %d", type, nb);
-
-       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);
-       }
-
-       lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
-       return ret;
-}
-
-
-static void if_cs_release(struct pcmcia_device *p_dev)
-{
-       struct if_cs_card *card = p_dev->priv;
-
-       lbs_deb_enter(LBS_DEB_CS);
-
-       free_irq(p_dev->irq, card);
-       pcmcia_disable_device(p_dev);
-       if (card->iobase)
-               ioport_unmap(card->iobase);
-
-       lbs_deb_leave(LBS_DEB_CS);
-}
-
-
-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;
-
-       lbs_deb_enter(LBS_DEB_CS);
-
-       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 (!priv) {
-               ret = -ENOMEM;
-               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:
-       lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
-       return ret;
-}
-
-
-static void if_cs_detach(struct pcmcia_device *p_dev)
-{
-       struct if_cs_card *card = p_dev->priv;
-
-       lbs_deb_enter(LBS_DEB_CS);
-
-       lbs_stop_card(card->priv);
-       lbs_remove_card(card->priv);
-       if_cs_disable_ints(card);
-       if_cs_release(p_dev);
-       kfree(card);
-
-       lbs_deb_leave(LBS_DEB_CS);
-}
-
-
-
-/********************************************************************/
-/* Module initialization                                            */
-/********************************************************************/
-
-static const struct pcmcia_device_id if_cs_ids[] = {
-       PCMCIA_DEVICE_MANF_CARD(CF8305_MANFID, CF8305_CARDID),
-       PCMCIA_DEVICE_MANF_CARD(CF8381_MANFID, CF8381_CARDID),
-       PCMCIA_DEVICE_MANF_CARD(CF8385_MANFID, CF8385_CARDID),
-       /* NOTE: keep in sync with get_model() */
-       PCMCIA_DEVICE_NULL,
-};
-MODULE_DEVICE_TABLE(pcmcia, if_cs_ids);
-
-static struct pcmcia_driver lbs_driver = {
-       .owner          = THIS_MODULE,
-       .name           = DRV_NAME,
-       .probe          = if_cs_probe,
-       .remove         = if_cs_detach,
-       .id_table       = if_cs_ids,
-};
-module_pcmcia_driver(lbs_driver);
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
deleted file mode 100644 (file)
index 33ceda2..0000000
+++ /dev/null
@@ -1,1453 +0,0 @@
-/*
- *  linux/drivers/net/wireless/libertas/if_sdio.c
- *
- *  Copyright 2007-2008 Pierre Ossman
- *
- * Inspired by if_cs.c, Copyright 2007 Holger Schurig
- *
- * 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 hardware has more or less no CMD53 support, so all registers
- * must be accessed using sdio_readb()/sdio_writeb().
- *
- * Transfers must be in one transaction or the firmware goes bonkers.
- * This means that the transfer must either be small enough to do a
- * byte based transfer or it must be padded to a multiple of the
- * current block size.
- *
- * As SDIO is still new to the kernel, it is unfortunately common with
- * bugs in the host controllers related to that. One such bug is that
- * controllers cannot do transfers that aren't a multiple of 4 bytes.
- * If you don't have time to fix the host controller driver, you can
- * work around the problem by modifying if_sdio_host_to_card() and
- * if_sdio_card_to_host() to pad the data.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/firmware.h>
-#include <linux/netdevice.h>
-#include <linux/delay.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/sdio_func.h>
-#include <linux/mmc/sdio_ids.h>
-#include <linux/mmc/sdio.h>
-#include <linux/mmc/host.h>
-#include <linux/pm_runtime.h>
-
-#include "host.h"
-#include "decl.h"
-#include "defs.h"
-#include "dev.h"
-#include "cmd.h"
-#include "if_sdio.h"
-
-static void if_sdio_interrupt(struct sdio_func *func);
-
-/* The if_sdio_remove() callback function is called when
- * user removes this module from kernel space or ejects
- * the card from the slot. The driver handles these 2 cases
- * differently for SD8688 combo chip.
- * If the user is removing the module, the FUNC_SHUTDOWN
- * command for SD8688 is sent to the firmware.
- * If the card is removed, there is no need to send this command.
- *
- * The variable 'user_rmmod' is used to distinguish these two
- * scenarios. This flag is initialized as FALSE in case the card
- * is removed, and will be set to TRUE for module removal when
- * module_exit function is called.
- */
-static u8 user_rmmod;
-
-static const struct sdio_device_id if_sdio_ids[] = {
-       { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL,
-                       SDIO_DEVICE_ID_MARVELL_LIBERTAS) },
-       { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL,
-                       SDIO_DEVICE_ID_MARVELL_8688WLAN) },
-       { /* end: all zeroes */                         },
-};
-
-MODULE_DEVICE_TABLE(sdio, if_sdio_ids);
-
-#define MODEL_8385     0x04
-#define MODEL_8686     0x0b
-#define MODEL_8688     0x10
-
-static const struct lbs_fw_table fw_table[] = {
-       { MODEL_8385, "libertas/sd8385_helper.bin", "libertas/sd8385.bin" },
-       { MODEL_8385, "sd8385_helper.bin", "sd8385.bin" },
-       { MODEL_8686, "libertas/sd8686_v9_helper.bin", "libertas/sd8686_v9.bin" },
-       { MODEL_8686, "libertas/sd8686_v8_helper.bin", "libertas/sd8686_v8.bin" },
-       { MODEL_8686, "sd8686_helper.bin", "sd8686.bin" },
-       { MODEL_8688, "libertas/sd8688_helper.bin", "libertas/sd8688.bin" },
-       { MODEL_8688, "sd8688_helper.bin", "sd8688.bin" },
-       { 0, NULL, NULL }
-};
-MODULE_FIRMWARE("libertas/sd8385_helper.bin");
-MODULE_FIRMWARE("libertas/sd8385.bin");
-MODULE_FIRMWARE("sd8385_helper.bin");
-MODULE_FIRMWARE("sd8385.bin");
-MODULE_FIRMWARE("libertas/sd8686_v9_helper.bin");
-MODULE_FIRMWARE("libertas/sd8686_v9.bin");
-MODULE_FIRMWARE("libertas/sd8686_v8_helper.bin");
-MODULE_FIRMWARE("libertas/sd8686_v8.bin");
-MODULE_FIRMWARE("sd8686_helper.bin");
-MODULE_FIRMWARE("sd8686.bin");
-MODULE_FIRMWARE("libertas/sd8688_helper.bin");
-MODULE_FIRMWARE("libertas/sd8688.bin");
-MODULE_FIRMWARE("sd8688_helper.bin");
-MODULE_FIRMWARE("sd8688.bin");
-
-struct if_sdio_packet {
-       struct if_sdio_packet   *next;
-       u16                     nb;
-       u8                      buffer[0] __attribute__((aligned(4)));
-};
-
-struct if_sdio_card {
-       struct sdio_func        *func;
-       struct lbs_private      *priv;
-
-       int                     model;
-       unsigned long           ioport;
-       unsigned int            scratch_reg;
-       bool                    started;
-       wait_queue_head_t       pwron_waitq;
-
-       u8                      buffer[65536] __attribute__((aligned(4)));
-
-       spinlock_t              lock;
-       struct if_sdio_packet   *packets;
-
-       struct workqueue_struct *workqueue;
-       struct work_struct      packet_worker;
-
-       u8                      rx_unit;
-};
-
-static void if_sdio_finish_power_on(struct if_sdio_card *card);
-static int if_sdio_power_off(struct if_sdio_card *card);
-
-/********************************************************************/
-/* I/O                                                              */
-/********************************************************************/
-
-/*
- *  For SD8385/SD8686, this function reads firmware status after
- *  the image is downloaded, or reads RX packet length when
- *  interrupt (with IF_SDIO_H_INT_UPLD bit set) is received.
- *  For SD8688, this function reads firmware status only.
- */
-static u16 if_sdio_read_scratch(struct if_sdio_card *card, int *err)
-{
-       int ret;
-       u16 scratch;
-
-       scratch = sdio_readb(card->func, card->scratch_reg, &ret);
-       if (!ret)
-               scratch |= sdio_readb(card->func, card->scratch_reg + 1,
-                                       &ret) << 8;
-
-       if (err)
-               *err = ret;
-
-       if (ret)
-               return 0xffff;
-
-       return scratch;
-}
-
-static u8 if_sdio_read_rx_unit(struct if_sdio_card *card)
-{
-       int ret;
-       u8 rx_unit;
-
-       rx_unit = sdio_readb(card->func, IF_SDIO_RX_UNIT, &ret);
-
-       if (ret)
-               rx_unit = 0;
-
-       return rx_unit;
-}
-
-static u16 if_sdio_read_rx_len(struct if_sdio_card *card, int *err)
-{
-       int ret;
-       u16 rx_len;
-
-       switch (card->model) {
-       case MODEL_8385:
-       case MODEL_8686:
-               rx_len = if_sdio_read_scratch(card, &ret);
-               break;
-       case MODEL_8688:
-       default: /* for newer chipsets */
-               rx_len = sdio_readb(card->func, IF_SDIO_RX_LEN, &ret);
-               if (!ret)
-                       rx_len <<= card->rx_unit;
-               else
-                       rx_len = 0xffff;        /* invalid length */
-
-               break;
-       }
-
-       if (err)
-               *err = ret;
-
-       return rx_len;
-}
-
-static int if_sdio_handle_cmd(struct if_sdio_card *card,
-               u8 *buffer, unsigned size)
-{
-       struct lbs_private *priv = card->priv;
-       int ret;
-       unsigned long flags;
-       u8 i;
-
-       lbs_deb_enter(LBS_DEB_SDIO);
-
-       if (size > LBS_CMD_BUFFER_SIZE) {
-               lbs_deb_sdio("response packet too large (%d bytes)\n",
-                       (int)size);
-               ret = -E2BIG;
-               goto out;
-       }
-
-       spin_lock_irqsave(&priv->driver_lock, flags);
-
-       i = (priv->resp_idx == 0) ? 1 : 0;
-       BUG_ON(priv->resp_len[i]);
-       priv->resp_len[i] = size;
-       memcpy(priv->resp_buf[i], buffer, size);
-       lbs_notify_command_response(priv, i);
-
-       spin_unlock_irqrestore(&card->priv->driver_lock, flags);
-
-       ret = 0;
-
-out:
-       lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
-       return ret;
-}
-
-static int if_sdio_handle_data(struct if_sdio_card *card,
-               u8 *buffer, unsigned size)
-{
-       int ret;
-       struct sk_buff *skb;
-       char *data;
-
-       lbs_deb_enter(LBS_DEB_SDIO);
-
-       if (size > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
-               lbs_deb_sdio("response packet too large (%d bytes)\n",
-                       (int)size);
-               ret = -E2BIG;
-               goto out;
-       }
-
-       skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + NET_IP_ALIGN);
-       if (!skb) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       skb_reserve(skb, NET_IP_ALIGN);
-
-       data = skb_put(skb, size);
-
-       memcpy(data, buffer, size);
-
-       lbs_process_rxed_packet(card->priv, skb);
-
-       ret = 0;
-
-out:
-       lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
-
-       return ret;
-}
-
-static int if_sdio_handle_event(struct if_sdio_card *card,
-               u8 *buffer, unsigned size)
-{
-       int ret;
-       u32 event;
-
-       lbs_deb_enter(LBS_DEB_SDIO);
-
-       if (card->model == MODEL_8385) {
-               event = sdio_readb(card->func, IF_SDIO_EVENT, &ret);
-               if (ret)
-                       goto out;
-
-               /* right shift 3 bits to get the event id */
-               event >>= 3;
-       } else {
-               if (size < 4) {
-                       lbs_deb_sdio("event packet too small (%d bytes)\n",
-                               (int)size);
-                       ret = -EINVAL;
-                       goto out;
-               }
-               event = buffer[3] << 24;
-               event |= buffer[2] << 16;
-               event |= buffer[1] << 8;
-               event |= buffer[0] << 0;
-       }
-
-       lbs_queue_event(card->priv, event & 0xFF);
-       ret = 0;
-
-out:
-       lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
-
-       return ret;
-}
-
-static int if_sdio_wait_status(struct if_sdio_card *card, const u8 condition)
-{
-       u8 status;
-       unsigned long timeout;
-       int ret = 0;
-
-       timeout = jiffies + HZ;
-       while (1) {
-               status = sdio_readb(card->func, IF_SDIO_STATUS, &ret);
-               if (ret)
-                       return ret;
-               if ((status & condition) == condition)
-                       break;
-               if (time_after(jiffies, timeout))
-                       return -ETIMEDOUT;
-               mdelay(1);
-       }
-       return ret;
-}
-
-static int if_sdio_card_to_host(struct if_sdio_card *card)
-{
-       int ret;
-       u16 size, type, chunk;
-
-       lbs_deb_enter(LBS_DEB_SDIO);
-
-       size = if_sdio_read_rx_len(card, &ret);
-       if (ret)
-               goto out;
-
-       if (size < 4) {
-               lbs_deb_sdio("invalid packet size (%d bytes) from firmware\n",
-                       (int)size);
-               ret = -EINVAL;
-               goto out;
-       }
-
-       ret = if_sdio_wait_status(card, IF_SDIO_IO_RDY);
-       if (ret)
-               goto out;
-
-       /*
-        * The transfer must be in one transaction or the firmware
-        * goes suicidal. There's no way to guarantee that for all
-        * controllers, but we can at least try.
-        */
-       chunk = sdio_align_size(card->func, size);
-
-       ret = sdio_readsb(card->func, card->buffer, card->ioport, chunk);
-       if (ret)
-               goto out;
-
-       chunk = card->buffer[0] | (card->buffer[1] << 8);
-       type = card->buffer[2] | (card->buffer[3] << 8);
-
-       lbs_deb_sdio("packet of type %d and size %d bytes\n",
-               (int)type, (int)chunk);
-
-       if (chunk > size) {
-               lbs_deb_sdio("packet fragment (%d > %d)\n",
-                       (int)chunk, (int)size);
-               ret = -EINVAL;
-               goto out;
-       }
-
-       if (chunk < size) {
-               lbs_deb_sdio("packet fragment (%d < %d)\n",
-                       (int)chunk, (int)size);
-       }
-
-       switch (type) {
-       case MVMS_CMD:
-               ret = if_sdio_handle_cmd(card, card->buffer + 4, chunk - 4);
-               if (ret)
-                       goto out;
-               break;
-       case MVMS_DAT:
-               ret = if_sdio_handle_data(card, card->buffer + 4, chunk - 4);
-               if (ret)
-                       goto out;
-               break;
-       case MVMS_EVENT:
-               ret = if_sdio_handle_event(card, card->buffer + 4, chunk - 4);
-               if (ret)
-                       goto out;
-               break;
-       default:
-               lbs_deb_sdio("invalid type (%d) from firmware\n",
-                               (int)type);
-               ret = -EINVAL;
-               goto out;
-       }
-
-out:
-       if (ret)
-               pr_err("problem fetching packet from firmware\n");
-
-       lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
-
-       return ret;
-}
-
-static void if_sdio_host_to_card_worker(struct work_struct *work)
-{
-       struct if_sdio_card *card;
-       struct if_sdio_packet *packet;
-       int ret;
-       unsigned long flags;
-
-       lbs_deb_enter(LBS_DEB_SDIO);
-
-       card = container_of(work, struct if_sdio_card, packet_worker);
-
-       while (1) {
-               spin_lock_irqsave(&card->lock, flags);
-               packet = card->packets;
-               if (packet)
-                       card->packets = packet->next;
-               spin_unlock_irqrestore(&card->lock, flags);
-
-               if (!packet)
-                       break;
-
-               sdio_claim_host(card->func);
-
-               ret = if_sdio_wait_status(card, IF_SDIO_IO_RDY);
-               if (ret == 0) {
-                       ret = sdio_writesb(card->func, card->ioport,
-                                          packet->buffer, packet->nb);
-               }
-
-               if (ret)
-                       pr_err("error %d sending packet to firmware\n", ret);
-
-               sdio_release_host(card->func);
-
-               kfree(packet);
-       }
-
-       lbs_deb_leave(LBS_DEB_SDIO);
-}
-
-/********************************************************************/
-/* Firmware                                                         */
-/********************************************************************/
-
-#define FW_DL_READY_STATUS (IF_SDIO_IO_RDY | IF_SDIO_DL_RDY)
-
-static int if_sdio_prog_helper(struct if_sdio_card *card,
-                               const struct firmware *fw)
-{
-       int ret;
-       unsigned long timeout;
-       u8 *chunk_buffer;
-       u32 chunk_size;
-       const u8 *firmware;
-       size_t size;
-
-       lbs_deb_enter(LBS_DEB_SDIO);
-
-       chunk_buffer = kzalloc(64, GFP_KERNEL);
-       if (!chunk_buffer) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       sdio_claim_host(card->func);
-
-       ret = sdio_set_block_size(card->func, 32);
-       if (ret)
-               goto release;
-
-       firmware = fw->data;
-       size = fw->size;
-
-       while (size) {
-               ret = if_sdio_wait_status(card, FW_DL_READY_STATUS);
-               if (ret)
-                       goto release;
-
-               /* On some platforms (like Davinci) the chip needs more time
-                * between helper blocks.
-                */
-               mdelay(2);
-
-               chunk_size = min_t(size_t, size, 60);
-
-               *((__le32*)chunk_buffer) = cpu_to_le32(chunk_size);
-               memcpy(chunk_buffer + 4, firmware, chunk_size);
-/*
-               lbs_deb_sdio("sending %d bytes chunk\n", chunk_size);
-*/
-               ret = sdio_writesb(card->func, card->ioport,
-                               chunk_buffer, 64);
-               if (ret)
-                       goto release;
-
-               firmware += chunk_size;
-               size -= chunk_size;
-       }
-
-       /* an empty block marks the end of the transfer */
-       memset(chunk_buffer, 0, 4);
-       ret = sdio_writesb(card->func, card->ioport, chunk_buffer, 64);
-       if (ret)
-               goto release;
-
-       lbs_deb_sdio("waiting for helper to boot...\n");
-
-       /* wait for the helper to boot by looking at the size register */
-       timeout = jiffies + HZ;
-       while (1) {
-               u16 req_size;
-
-               req_size = sdio_readb(card->func, IF_SDIO_RD_BASE, &ret);
-               if (ret)
-                       goto release;
-
-               req_size |= sdio_readb(card->func, IF_SDIO_RD_BASE + 1, &ret) << 8;
-               if (ret)
-                       goto release;
-
-               if (req_size != 0)
-                       break;
-
-               if (time_after(jiffies, timeout)) {
-                       ret = -ETIMEDOUT;
-                       goto release;
-               }
-
-               msleep(10);
-       }
-
-       ret = 0;
-
-release:
-       sdio_release_host(card->func);
-       kfree(chunk_buffer);
-
-out:
-       if (ret)
-               pr_err("failed to load helper firmware\n");
-
-       lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
-       return ret;
-}
-
-static int if_sdio_prog_real(struct if_sdio_card *card,
-                               const struct firmware *fw)
-{
-       int ret;
-       unsigned long timeout;
-       u8 *chunk_buffer;
-       u32 chunk_size;
-       const u8 *firmware;
-       size_t size, req_size;
-
-       lbs_deb_enter(LBS_DEB_SDIO);
-
-       chunk_buffer = kzalloc(512, GFP_KERNEL);
-       if (!chunk_buffer) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       sdio_claim_host(card->func);
-
-       ret = sdio_set_block_size(card->func, 32);
-       if (ret)
-               goto release;
-
-       firmware = fw->data;
-       size = fw->size;
-
-       while (size) {
-               timeout = jiffies + HZ;
-               while (1) {
-                       ret = if_sdio_wait_status(card, FW_DL_READY_STATUS);
-                       if (ret)
-                               goto release;
-
-                       req_size = sdio_readb(card->func, IF_SDIO_RD_BASE,
-                                       &ret);
-                       if (ret)
-                               goto release;
-
-                       req_size |= sdio_readb(card->func, IF_SDIO_RD_BASE + 1,
-                                       &ret) << 8;
-                       if (ret)
-                               goto release;
-
-                       /*
-                        * For SD8688 wait until the length is not 0, 1 or 2
-                        * before downloading the first FW block,
-                        * since BOOT code writes the register to indicate the
-                        * helper/FW download winner,
-                        * the value could be 1 or 2 (Func1 or Func2).
-                        */
-                       if ((size != fw->size) || (req_size > 2))
-                               break;
-                       if (time_after(jiffies, timeout)) {
-                               ret = -ETIMEDOUT;
-                               goto release;
-                       }
-                       mdelay(1);
-               }
-
-/*
-               lbs_deb_sdio("firmware wants %d bytes\n", (int)req_size);
-*/
-               if (req_size == 0) {
-                       lbs_deb_sdio("firmware helper gave up early\n");
-                       ret = -EIO;
-                       goto release;
-               }
-
-               if (req_size & 0x01) {
-                       lbs_deb_sdio("firmware helper signalled error\n");
-                       ret = -EIO;
-                       goto release;
-               }
-
-               if (req_size > size)
-                       req_size = size;
-
-               while (req_size) {
-                       chunk_size = min_t(size_t, req_size, 512);
-
-                       memcpy(chunk_buffer, firmware, chunk_size);
-/*
-                       lbs_deb_sdio("sending %d bytes (%d bytes) chunk\n",
-                               chunk_size, (chunk_size + 31) / 32 * 32);
-*/
-                       ret = sdio_writesb(card->func, card->ioport,
-                               chunk_buffer, roundup(chunk_size, 32));
-                       if (ret)
-                               goto release;
-
-                       firmware += chunk_size;
-                       size -= chunk_size;
-                       req_size -= chunk_size;
-               }
-       }
-
-       ret = 0;
-
-       lbs_deb_sdio("waiting for firmware to boot...\n");
-
-       /* wait for the firmware to boot */
-       timeout = jiffies + HZ;
-       while (1) {
-               u16 scratch;
-
-               scratch = if_sdio_read_scratch(card, &ret);
-               if (ret)
-                       goto release;
-
-               if (scratch == IF_SDIO_FIRMWARE_OK)
-                       break;
-
-               if (time_after(jiffies, timeout)) {
-                       ret = -ETIMEDOUT;
-                       goto release;
-               }
-
-               msleep(10);
-       }
-
-       ret = 0;
-
-release:
-       sdio_release_host(card->func);
-       kfree(chunk_buffer);
-
-out:
-       if (ret)
-               pr_err("failed to load firmware\n");
-
-       lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
-       return ret;
-}
-
-static void if_sdio_do_prog_firmware(struct lbs_private *priv, int ret,
-                                    const struct firmware *helper,
-                                    const struct firmware *mainfw)
-{
-       struct if_sdio_card *card = priv->card;
-
-       if (ret) {
-               pr_err("failed to find firmware (%d)\n", ret);
-               return;
-       }
-
-       ret = if_sdio_prog_helper(card, helper);
-       if (ret)
-               return;
-
-       lbs_deb_sdio("Helper firmware loaded\n");
-
-       ret = if_sdio_prog_real(card, mainfw);
-       if (ret)
-               return;
-
-       lbs_deb_sdio("Firmware loaded\n");
-       if_sdio_finish_power_on(card);
-}
-
-static int if_sdio_prog_firmware(struct if_sdio_card *card)
-{
-       int ret;
-       u16 scratch;
-
-       lbs_deb_enter(LBS_DEB_SDIO);
-
-       /*
-        * Disable interrupts
-        */
-       sdio_claim_host(card->func);
-       sdio_writeb(card->func, 0x00, IF_SDIO_H_INT_MASK, &ret);
-       sdio_release_host(card->func);
-
-       sdio_claim_host(card->func);
-       scratch = if_sdio_read_scratch(card, &ret);
-       sdio_release_host(card->func);
-
-       lbs_deb_sdio("firmware status = %#x\n", scratch);
-       lbs_deb_sdio("scratch ret = %d\n", ret);
-
-       if (ret)
-               goto out;
-
-
-       /*
-        * The manual clearly describes that FEDC is the right code to use
-        * to detect firmware presence, but for SD8686 it is not that simple.
-        * Scratch is also used to store the RX packet length, so we lose
-        * the FEDC value early on. So we use a non-zero check in order
-        * to validate firmware presence.
-        * Additionally, the SD8686 in the Gumstix always has the high scratch
-        * bit set, even when the firmware is not loaded. So we have to
-        * exclude that from the test.
-        */
-       if (scratch == IF_SDIO_FIRMWARE_OK) {
-               lbs_deb_sdio("firmware already loaded\n");
-               if_sdio_finish_power_on(card);
-               return 0;
-       } else if ((card->model == MODEL_8686) && (scratch & 0x7fff)) {
-               lbs_deb_sdio("firmware may be running\n");
-               if_sdio_finish_power_on(card);
-               return 0;
-       }
-
-       ret = lbs_get_firmware_async(card->priv, &card->func->dev, card->model,
-                                    fw_table, if_sdio_do_prog_firmware);
-
-out:
-       lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
-       return ret;
-}
-
-/********************************************************************/
-/* Power management                                                 */
-/********************************************************************/
-
-/* Finish power on sequence (after firmware is loaded) */
-static void if_sdio_finish_power_on(struct if_sdio_card *card)
-{
-       struct sdio_func *func = card->func;
-       struct lbs_private *priv = card->priv;
-       int ret;
-
-       sdio_claim_host(func);
-       sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE);
-
-       /*
-        * Get rx_unit if the chip is SD8688 or newer.
-        * SD8385 & SD8686 do not have rx_unit.
-        */
-       if ((card->model != MODEL_8385)
-                       && (card->model != MODEL_8686))
-               card->rx_unit = if_sdio_read_rx_unit(card);
-       else
-               card->rx_unit = 0;
-
-       /*
-        * Set up the interrupt handler late.
-        *
-        * If we set it up earlier, the (buggy) hardware generates a spurious
-        * interrupt, even before the interrupt has been enabled, with
-        * CCCR_INTx = 0.
-        *
-        * We register the interrupt handler late so that we can handle any
-        * spurious interrupts, and also to avoid generation of that known
-        * spurious interrupt in the first place.
-        */
-       ret = sdio_claim_irq(func, if_sdio_interrupt);
-       if (ret)
-               goto release;
-
-       /*
-        * Enable interrupts now that everything is set up
-        */
-       sdio_writeb(func, 0x0f, IF_SDIO_H_INT_MASK, &ret);
-       if (ret)
-               goto release_irq;
-
-       sdio_release_host(func);
-
-       /* Set fw_ready before queuing any commands so that
-        * lbs_thread won't block from sending them to firmware.
-        */
-       priv->fw_ready = 1;
-
-       /*
-        * FUNC_INIT is required for SD8688 WLAN/BT multiple functions
-        */
-       if (card->model == MODEL_8688) {
-               struct cmd_header cmd;
-
-               memset(&cmd, 0, sizeof(cmd));
-
-               lbs_deb_sdio("send function INIT command\n");
-               if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd),
-                               lbs_cmd_copyback, (unsigned long) &cmd))
-                       netdev_alert(priv->dev, "CMD_FUNC_INIT cmd failed\n");
-       }
-
-       wake_up(&card->pwron_waitq);
-
-       if (!card->started) {
-               ret = lbs_start_card(priv);
-               if_sdio_power_off(card);
-               if (ret == 0) {
-                       card->started = true;
-                       /* Tell PM core that we don't need the card to be
-                        * powered now */
-                       pm_runtime_put(&func->dev);
-               }
-       }
-
-       return;
-
-release_irq:
-       sdio_release_irq(func);
-release:
-       sdio_release_host(func);
-}
-
-static int if_sdio_power_on(struct if_sdio_card *card)
-{
-       struct sdio_func *func = card->func;
-       struct mmc_host *host = func->card->host;
-       int ret;
-
-       sdio_claim_host(func);
-
-       ret = sdio_enable_func(func);
-       if (ret)
-               goto release;
-
-       /* For 1-bit transfers to the 8686 model, we need to enable the
-        * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0
-        * bit to allow access to non-vendor registers. */
-       if ((card->model == MODEL_8686) &&
-           (host->caps & MMC_CAP_SDIO_IRQ) &&
-           (host->ios.bus_width == MMC_BUS_WIDTH_1)) {
-               u8 reg;
-
-               func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
-               reg = sdio_f0_readb(func, SDIO_CCCR_IF, &ret);
-               if (ret)
-                       goto disable;
-
-               reg |= SDIO_BUS_ECSI;
-               sdio_f0_writeb(func, reg, SDIO_CCCR_IF, &ret);
-               if (ret)
-                       goto disable;
-       }
-
-       card->ioport = sdio_readb(func, IF_SDIO_IOPORT, &ret);
-       if (ret)
-               goto disable;
-
-       card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 1, &ret) << 8;
-       if (ret)
-               goto disable;
-
-       card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 2, &ret) << 16;
-       if (ret)
-               goto disable;
-
-       sdio_release_host(func);
-       ret = if_sdio_prog_firmware(card);
-       if (ret) {
-               sdio_claim_host(func);
-               goto disable;
-       }
-
-       return 0;
-
-disable:
-       sdio_disable_func(func);
-release:
-       sdio_release_host(func);
-       return ret;
-}
-
-static int if_sdio_power_off(struct if_sdio_card *card)
-{
-       struct sdio_func *func = card->func;
-       struct lbs_private *priv = card->priv;
-
-       priv->fw_ready = 0;
-
-       sdio_claim_host(func);
-       sdio_release_irq(func);
-       sdio_disable_func(func);
-       sdio_release_host(func);
-       return 0;
-}
-
-
-/*******************************************************************/
-/* Libertas callbacks                                              */
-/*******************************************************************/
-
-static int if_sdio_host_to_card(struct lbs_private *priv,
-               u8 type, u8 *buf, u16 nb)
-{
-       int ret;
-       struct if_sdio_card *card;
-       struct if_sdio_packet *packet, *cur;
-       u16 size;
-       unsigned long flags;
-
-       lbs_deb_enter_args(LBS_DEB_SDIO, "type %d, bytes %d", type, nb);
-
-       card = priv->card;
-
-       if (nb > (65536 - sizeof(struct if_sdio_packet) - 4)) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       /*
-        * The transfer must be in one transaction or the firmware
-        * goes suicidal. There's no way to guarantee that for all
-        * controllers, but we can at least try.
-        */
-       size = sdio_align_size(card->func, nb + 4);
-
-       packet = kzalloc(sizeof(struct if_sdio_packet) + size,
-                       GFP_ATOMIC);
-       if (!packet) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       packet->next = NULL;
-       packet->nb = size;
-
-       /*
-        * SDIO specific header.
-        */
-       packet->buffer[0] = (nb + 4) & 0xff;
-       packet->buffer[1] = ((nb + 4) >> 8) & 0xff;
-       packet->buffer[2] = type;
-       packet->buffer[3] = 0;
-
-       memcpy(packet->buffer + 4, buf, nb);
-
-       spin_lock_irqsave(&card->lock, flags);
-
-       if (!card->packets)
-               card->packets = packet;
-       else {
-               cur = card->packets;
-               while (cur->next)
-                       cur = cur->next;
-               cur->next = packet;
-       }
-
-       switch (type) {
-       case MVMS_CMD:
-               priv->dnld_sent = DNLD_CMD_SENT;
-               break;
-       case MVMS_DAT:
-               priv->dnld_sent = DNLD_DATA_SENT;
-               break;
-       default:
-               lbs_deb_sdio("unknown packet type %d\n", (int)type);
-       }
-
-       spin_unlock_irqrestore(&card->lock, flags);
-
-       queue_work(card->workqueue, &card->packet_worker);
-
-       ret = 0;
-
-out:
-       lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
-
-       return ret;
-}
-
-static int if_sdio_enter_deep_sleep(struct lbs_private *priv)
-{
-       int ret = -1;
-       struct cmd_header cmd;
-
-       memset(&cmd, 0, sizeof(cmd));
-
-       lbs_deb_sdio("send DEEP_SLEEP command\n");
-       ret = __lbs_cmd(priv, CMD_802_11_DEEP_SLEEP, &cmd, sizeof(cmd),
-                       lbs_cmd_copyback, (unsigned long) &cmd);
-       if (ret)
-               netdev_err(priv->dev, "DEEP_SLEEP cmd failed\n");
-
-       mdelay(200);
-       return ret;
-}
-
-static int if_sdio_exit_deep_sleep(struct lbs_private *priv)
-{
-       struct if_sdio_card *card = priv->card;
-       int ret = -1;
-
-       lbs_deb_enter(LBS_DEB_SDIO);
-       sdio_claim_host(card->func);
-
-       sdio_writeb(card->func, HOST_POWER_UP, CONFIGURATION_REG, &ret);
-       if (ret)
-               netdev_err(priv->dev, "sdio_writeb failed!\n");
-
-       sdio_release_host(card->func);
-       lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
-       return ret;
-}
-
-static int if_sdio_reset_deep_sleep_wakeup(struct lbs_private *priv)
-{
-       struct if_sdio_card *card = priv->card;
-       int ret = -1;
-
-       lbs_deb_enter(LBS_DEB_SDIO);
-       sdio_claim_host(card->func);
-
-       sdio_writeb(card->func, 0, CONFIGURATION_REG, &ret);
-       if (ret)
-               netdev_err(priv->dev, "sdio_writeb failed!\n");
-
-       sdio_release_host(card->func);
-       lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
-       return ret;
-
-}
-
-static struct mmc_host *reset_host;
-
-static void if_sdio_reset_card_worker(struct work_struct *work)
-{
-       /*
-        * The actual reset operation must be run outside of lbs_thread. This
-        * is because mmc_remove_host() will cause the device to be instantly
-        * destroyed, and the libertas driver then needs to end lbs_thread,
-        * leading to a deadlock.
-        *
-        * We run it in a workqueue totally independent from the if_sdio_card
-        * instance for that reason.
-        */
-
-       pr_info("Resetting card...");
-       mmc_remove_host(reset_host);
-       mmc_add_host(reset_host);
-}
-static DECLARE_WORK(card_reset_work, if_sdio_reset_card_worker);
-
-static void if_sdio_reset_card(struct lbs_private *priv)
-{
-       struct if_sdio_card *card = priv->card;
-
-       if (work_pending(&card_reset_work))
-               return;
-
-       reset_host = card->func->card->host;
-       schedule_work(&card_reset_work);
-}
-
-static int if_sdio_power_save(struct lbs_private *priv)
-{
-       struct if_sdio_card *card = priv->card;
-       int ret;
-
-       flush_workqueue(card->workqueue);
-
-       ret = if_sdio_power_off(card);
-
-       /* Let runtime PM know the card is powered off */
-       pm_runtime_put_sync(&card->func->dev);
-
-       return ret;
-}
-
-static int if_sdio_power_restore(struct lbs_private *priv)
-{
-       struct if_sdio_card *card = priv->card;
-       int r;
-
-       /* Make sure the card will not be powered off by runtime PM */
-       pm_runtime_get_sync(&card->func->dev);
-
-       r = if_sdio_power_on(card);
-       if (r)
-               return r;
-
-       wait_event(card->pwron_waitq, priv->fw_ready);
-       return 0;
-}
-
-
-/*******************************************************************/
-/* SDIO callbacks                                                  */
-/*******************************************************************/
-
-static void if_sdio_interrupt(struct sdio_func *func)
-{
-       int ret;
-       struct if_sdio_card *card;
-       u8 cause;
-
-       lbs_deb_enter(LBS_DEB_SDIO);
-
-       card = sdio_get_drvdata(func);
-
-       cause = sdio_readb(card->func, IF_SDIO_H_INT_STATUS, &ret);
-       if (ret || !cause)
-               goto out;
-
-       lbs_deb_sdio("interrupt: 0x%X\n", (unsigned)cause);
-
-       sdio_writeb(card->func, ~cause, IF_SDIO_H_INT_STATUS, &ret);
-       if (ret)
-               goto out;
-
-       /*
-        * Ignore the define name, this really means the card has
-        * successfully received the command.
-        */
-       card->priv->is_activity_detected = 1;
-       if (cause & IF_SDIO_H_INT_DNLD)
-               lbs_host_to_card_done(card->priv);
-
-
-       if (cause & IF_SDIO_H_INT_UPLD) {
-               ret = if_sdio_card_to_host(card);
-               if (ret)
-                       goto out;
-       }
-
-       ret = 0;
-
-out:
-       lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
-}
-
-static int if_sdio_probe(struct sdio_func *func,
-               const struct sdio_device_id *id)
-{
-       struct if_sdio_card *card;
-       struct lbs_private *priv;
-       int ret, i;
-       unsigned int model;
-       struct if_sdio_packet *packet;
-
-       lbs_deb_enter(LBS_DEB_SDIO);
-
-       for (i = 0;i < func->card->num_info;i++) {
-               if (sscanf(func->card->info[i],
-                               "802.11 SDIO ID: %x", &model) == 1)
-                       break;
-               if (sscanf(func->card->info[i],
-                               "ID: %x", &model) == 1)
-                       break;
-               if (!strcmp(func->card->info[i], "IBIS Wireless SDIO Card")) {
-                       model = MODEL_8385;
-                       break;
-               }
-       }
-
-       if (i == func->card->num_info) {
-               pr_err("unable to identify card model\n");
-               return -ENODEV;
-       }
-
-       card = kzalloc(sizeof(struct if_sdio_card), GFP_KERNEL);
-       if (!card)
-               return -ENOMEM;
-
-       card->func = func;
-       card->model = model;
-
-       switch (card->model) {
-       case MODEL_8385:
-               card->scratch_reg = IF_SDIO_SCRATCH_OLD;
-               break;
-       case MODEL_8686:
-               card->scratch_reg = IF_SDIO_SCRATCH;
-               break;
-       case MODEL_8688:
-       default: /* for newer chipsets */
-               card->scratch_reg = IF_SDIO_FW_STATUS;
-               break;
-       }
-
-       spin_lock_init(&card->lock);
-       card->workqueue = create_workqueue("libertas_sdio");
-       INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker);
-       init_waitqueue_head(&card->pwron_waitq);
-
-       /* Check if we support this card */
-       for (i = 0; i < ARRAY_SIZE(fw_table); i++) {
-               if (card->model == fw_table[i].model)
-                       break;
-       }
-       if (i == ARRAY_SIZE(fw_table)) {
-               pr_err("unknown card model 0x%x\n", card->model);
-               ret = -ENODEV;
-               goto free;
-       }
-
-       sdio_set_drvdata(func, card);
-
-       lbs_deb_sdio("class = 0x%X, vendor = 0x%X, "
-                       "device = 0x%X, model = 0x%X, ioport = 0x%X\n",
-                       func->class, func->vendor, func->device,
-                       model, (unsigned)card->ioport);
-
-
-       priv = lbs_add_card(card, &func->dev);
-       if (!priv) {
-               ret = -ENOMEM;
-               goto free;
-       }
-
-       card->priv = priv;
-
-       priv->card = card;
-       priv->hw_host_to_card = if_sdio_host_to_card;
-       priv->enter_deep_sleep = if_sdio_enter_deep_sleep;
-       priv->exit_deep_sleep = if_sdio_exit_deep_sleep;
-       priv->reset_deep_sleep_wakeup = if_sdio_reset_deep_sleep_wakeup;
-       priv->reset_card = if_sdio_reset_card;
-       priv->power_save = if_sdio_power_save;
-       priv->power_restore = if_sdio_power_restore;
-
-       ret = if_sdio_power_on(card);
-       if (ret)
-               goto err_activate_card;
-
-out:
-       lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
-
-       return ret;
-
-err_activate_card:
-       flush_workqueue(card->workqueue);
-       lbs_remove_card(priv);
-free:
-       destroy_workqueue(card->workqueue);
-       while (card->packets) {
-               packet = card->packets;
-               card->packets = card->packets->next;
-               kfree(packet);
-       }
-
-       kfree(card);
-
-       goto out;
-}
-
-static void if_sdio_remove(struct sdio_func *func)
-{
-       struct if_sdio_card *card;
-       struct if_sdio_packet *packet;
-
-       lbs_deb_enter(LBS_DEB_SDIO);
-
-       card = sdio_get_drvdata(func);
-
-       /* Undo decrement done above in if_sdio_probe */
-       pm_runtime_get_noresume(&func->dev);
-
-       if (user_rmmod && (card->model == MODEL_8688)) {
-               /*
-                * FUNC_SHUTDOWN is required for SD8688 WLAN/BT
-                * multiple functions
-                */
-               struct cmd_header cmd;
-
-               memset(&cmd, 0, sizeof(cmd));
-
-               lbs_deb_sdio("send function SHUTDOWN command\n");
-               if (__lbs_cmd(card->priv, CMD_FUNC_SHUTDOWN,
-                               &cmd, sizeof(cmd), lbs_cmd_copyback,
-                               (unsigned long) &cmd))
-                       pr_alert("CMD_FUNC_SHUTDOWN cmd failed\n");
-       }
-
-
-       lbs_deb_sdio("call remove card\n");
-       lbs_stop_card(card->priv);
-       lbs_remove_card(card->priv);
-
-       flush_workqueue(card->workqueue);
-       destroy_workqueue(card->workqueue);
-
-       while (card->packets) {
-               packet = card->packets;
-               card->packets = card->packets->next;
-               kfree(packet);
-       }
-
-       kfree(card);
-       lbs_deb_leave(LBS_DEB_SDIO);
-}
-
-static int if_sdio_suspend(struct device *dev)
-{
-       struct sdio_func *func = dev_to_sdio_func(dev);
-       int ret;
-       struct if_sdio_card *card = sdio_get_drvdata(func);
-
-       mmc_pm_flag_t flags = sdio_get_host_pm_caps(func);
-
-       /* If we're powered off anyway, just let the mmc layer remove the
-        * card. */
-       if (!lbs_iface_active(card->priv))
-               return -ENOSYS;
-
-       dev_info(dev, "%s: suspend: PM flags = 0x%x\n",
-                sdio_func_id(func), flags);
-
-       /* If we aren't being asked to wake on anything, we should bail out
-        * and let the SD stack power down the card.
-        */
-       if (card->priv->wol_criteria == EHS_REMOVE_WAKEUP) {
-               dev_info(dev, "Suspend without wake params -- powering down card\n");
-               return -ENOSYS;
-       }
-
-       if (!(flags & MMC_PM_KEEP_POWER)) {
-               dev_err(dev, "%s: cannot remain alive while host is suspended\n",
-                       sdio_func_id(func));
-               return -ENOSYS;
-       }
-
-       ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
-       if (ret)
-               return ret;
-
-       ret = lbs_suspend(card->priv);
-       if (ret)
-               return ret;
-
-       return sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ);
-}
-
-static int if_sdio_resume(struct device *dev)
-{
-       struct sdio_func *func = dev_to_sdio_func(dev);
-       struct if_sdio_card *card = sdio_get_drvdata(func);
-       int ret;
-
-       dev_info(dev, "%s: resume: we're back\n", sdio_func_id(func));
-
-       ret = lbs_resume(card->priv);
-
-       return ret;
-}
-
-static const struct dev_pm_ops if_sdio_pm_ops = {
-       .suspend        = if_sdio_suspend,
-       .resume         = if_sdio_resume,
-};
-
-static struct sdio_driver if_sdio_driver = {
-       .name           = "libertas_sdio",
-       .id_table       = if_sdio_ids,
-       .probe          = if_sdio_probe,
-       .remove         = if_sdio_remove,
-       .drv = {
-               .pm = &if_sdio_pm_ops,
-       },
-};
-
-/*******************************************************************/
-/* Module functions                                                */
-/*******************************************************************/
-
-static int __init if_sdio_init_module(void)
-{
-       int ret = 0;
-
-       lbs_deb_enter(LBS_DEB_SDIO);
-
-       printk(KERN_INFO "libertas_sdio: Libertas SDIO driver\n");
-       printk(KERN_INFO "libertas_sdio: Copyright Pierre Ossman\n");
-
-       ret = sdio_register_driver(&if_sdio_driver);
-
-       /* Clear the flag in case user removes the card. */
-       user_rmmod = 0;
-
-       lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
-
-       return ret;
-}
-
-static void __exit if_sdio_exit_module(void)
-{
-       lbs_deb_enter(LBS_DEB_SDIO);
-
-       /* Set the flag as user is removing this module. */
-       user_rmmod = 1;
-
-       cancel_work_sync(&card_reset_work);
-
-       sdio_unregister_driver(&if_sdio_driver);
-
-       lbs_deb_leave(LBS_DEB_SDIO);
-}
-
-module_init(if_sdio_init_module);
-module_exit(if_sdio_exit_module);
-
-MODULE_DESCRIPTION("Libertas SDIO WLAN Driver");
-MODULE_AUTHOR("Pierre Ossman");
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/libertas/if_sdio.h b/drivers/net/wireless/libertas/if_sdio.h
deleted file mode 100644 (file)
index 62fda35..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- *  linux/drivers/net/wireless/libertas/if_sdio.h
- *
- *  Copyright 2007 Pierre Ossman
- *
- * 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.
- */
-
-#ifndef _LBS_IF_SDIO_H
-#define _LBS_IF_SDIO_H
-
-#define IF_SDIO_IOPORT         0x00
-
-#define IF_SDIO_H_INT_MASK     0x04
-#define   IF_SDIO_H_INT_OFLOW  0x08
-#define   IF_SDIO_H_INT_UFLOW  0x04
-#define   IF_SDIO_H_INT_DNLD   0x02
-#define   IF_SDIO_H_INT_UPLD   0x01
-
-#define IF_SDIO_H_INT_STATUS   0x05
-#define IF_SDIO_H_INT_RSR      0x06
-#define IF_SDIO_H_INT_STATUS2  0x07
-
-#define IF_SDIO_RD_BASE                0x10
-
-#define IF_SDIO_STATUS         0x20
-#define   IF_SDIO_IO_RDY       0x08
-#define   IF_SDIO_CIS_RDY      0x04
-#define   IF_SDIO_UL_RDY       0x02
-#define   IF_SDIO_DL_RDY       0x01
-
-#define IF_SDIO_C_INT_MASK     0x24
-#define IF_SDIO_C_INT_STATUS   0x28
-#define IF_SDIO_C_INT_RSR      0x2C
-
-#define IF_SDIO_SCRATCH                0x34
-#define IF_SDIO_SCRATCH_OLD    0x80fe
-#define IF_SDIO_FW_STATUS      0x40
-#define   IF_SDIO_FIRMWARE_OK  0xfedc
-
-#define IF_SDIO_RX_LEN         0x42
-#define IF_SDIO_RX_UNIT                0x43
-
-#define IF_SDIO_EVENT           0x80fc
-
-#define IF_SDIO_BLOCK_SIZE     256
-#define CONFIGURATION_REG               0x03
-#define HOST_POWER_UP                   (0x1U << 1)
-#endif
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c
deleted file mode 100644 (file)
index 82c0796..0000000
+++ /dev/null
@@ -1,1318 +0,0 @@
-/*
- *     linux/drivers/net/wireless/libertas/if_spi.c
- *
- *     Driver for Marvell SPI WLAN cards.
- *
- *     Copyright 2008 Analog Devices Inc.
- *
- *     Authors:
- *     Andrey Yurovsky <andrey@cozybit.com>
- *     Colin McCabe <colin@cozybit.com>
- *
- *     Inspired by if_sdio.c, Copyright 2007-2008 Pierre Ossman
- *
- * 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.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/hardirq.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/firmware.h>
-#include <linux/jiffies.h>
-#include <linux/list.h>
-#include <linux/netdevice.h>
-#include <linux/slab.h>
-#include <linux/spi/libertas_spi.h>
-#include <linux/spi/spi.h>
-
-#include "host.h"
-#include "decl.h"
-#include "defs.h"
-#include "dev.h"
-#include "if_spi.h"
-
-struct if_spi_packet {
-       struct list_head                list;
-       u16                             blen;
-       u8                              buffer[0] __attribute__((aligned(4)));
-};
-
-struct if_spi_card {
-       struct spi_device               *spi;
-       struct lbs_private              *priv;
-       struct libertas_spi_platform_data *pdata;
-
-       /* The card ID and card revision, as reported by the hardware. */
-       u16                             card_id;
-       u8                              card_rev;
-
-       /* The last time that we initiated an SPU operation */
-       unsigned long                   prev_xfer_time;
-
-       int                             use_dummy_writes;
-       unsigned long                   spu_port_delay;
-       unsigned long                   spu_reg_delay;
-
-       /* Handles all SPI communication (except for FW load) */
-       struct workqueue_struct         *workqueue;
-       struct work_struct              packet_work;
-       struct work_struct              resume_work;
-
-       u8                              cmd_buffer[IF_SPI_CMD_BUF_SIZE];
-
-       /* A buffer of incoming packets from libertas core.
-        * Since we can't sleep in hw_host_to_card, we have to buffer
-        * them. */
-       struct list_head                cmd_packet_list;
-       struct list_head                data_packet_list;
-
-       /* Protects cmd_packet_list and data_packet_list */
-       spinlock_t                      buffer_lock;
-
-       /* True is card suspended */
-       u8                              suspended;
-};
-
-static void free_if_spi_card(struct if_spi_card *card)
-{
-       struct list_head *cursor, *next;
-       struct if_spi_packet *packet;
-
-       list_for_each_safe(cursor, next, &card->cmd_packet_list) {
-               packet = container_of(cursor, struct if_spi_packet, list);
-               list_del(&packet->list);
-               kfree(packet);
-       }
-       list_for_each_safe(cursor, next, &card->data_packet_list) {
-               packet = container_of(cursor, struct if_spi_packet, list);
-               list_del(&packet->list);
-               kfree(packet);
-       }
-       kfree(card);
-}
-
-#define MODEL_8385     0x04
-#define MODEL_8686     0x0b
-#define MODEL_8688     0x10
-
-static const struct lbs_fw_table fw_table[] = {
-       { MODEL_8385, "libertas/gspi8385_helper.bin", "libertas/gspi8385.bin" },
-       { MODEL_8385, "libertas/gspi8385_hlp.bin", "libertas/gspi8385.bin" },
-       { MODEL_8686, "libertas/gspi8686_v9_helper.bin", "libertas/gspi8686_v9.bin" },
-       { MODEL_8686, "libertas/gspi8686_hlp.bin", "libertas/gspi8686.bin" },
-       { MODEL_8688, "libertas/gspi8688_helper.bin", "libertas/gspi8688.bin" },
-       { 0, NULL, NULL }
-};
-MODULE_FIRMWARE("libertas/gspi8385_helper.bin");
-MODULE_FIRMWARE("libertas/gspi8385_hlp.bin");
-MODULE_FIRMWARE("libertas/gspi8385.bin");
-MODULE_FIRMWARE("libertas/gspi8686_v9_helper.bin");
-MODULE_FIRMWARE("libertas/gspi8686_v9.bin");
-MODULE_FIRMWARE("libertas/gspi8686_hlp.bin");
-MODULE_FIRMWARE("libertas/gspi8686.bin");
-MODULE_FIRMWARE("libertas/gspi8688_helper.bin");
-MODULE_FIRMWARE("libertas/gspi8688.bin");
-
-
-/*
- * SPI Interface Unit Routines
- *
- * The SPU sits between the host and the WLAN module.
- * All communication with the firmware is through SPU transactions.
- *
- * First we have to put a SPU register name on the bus. Then we can
- * either read from or write to that register.
- *
- */
-
-static void spu_transaction_init(struct if_spi_card *card)
-{
-       if (!time_after(jiffies, card->prev_xfer_time + 1)) {
-               /* Unfortunately, the SPU requires a delay between successive
-                * transactions. If our last transaction was more than a jiffy
-                * ago, we have obviously already delayed enough.
-                * If not, we have to busy-wait to be on the safe side. */
-               ndelay(400);
-       }
-}
-
-static void spu_transaction_finish(struct if_spi_card *card)
-{
-       card->prev_xfer_time = jiffies;
-}
-
-/*
- * Write out a byte buffer to an SPI register,
- * using a series of 16-bit transfers.
- */
-static int spu_write(struct if_spi_card *card, u16 reg, const u8 *buf, int len)
-{
-       int err = 0;
-       __le16 reg_out = cpu_to_le16(reg | IF_SPI_WRITE_OPERATION_MASK);
-       struct spi_message m;
-       struct spi_transfer reg_trans;
-       struct spi_transfer data_trans;
-
-       spi_message_init(&m);
-       memset(&reg_trans, 0, sizeof(reg_trans));
-       memset(&data_trans, 0, sizeof(data_trans));
-
-       /* You must give an even number of bytes to the SPU, even if it
-        * doesn't care about the last one.  */
-       BUG_ON(len & 0x1);
-
-       spu_transaction_init(card);
-
-       /* write SPU register index */
-       reg_trans.tx_buf = &reg_out;
-       reg_trans.len = sizeof(reg_out);
-
-       data_trans.tx_buf = buf;
-       data_trans.len = len;
-
-       spi_message_add_tail(&reg_trans, &m);
-       spi_message_add_tail(&data_trans, &m);
-
-       err = spi_sync(card->spi, &m);
-       spu_transaction_finish(card);
-       return err;
-}
-
-static inline int spu_write_u16(struct if_spi_card *card, u16 reg, u16 val)
-{
-       __le16 buff;
-
-       buff = cpu_to_le16(val);
-       return spu_write(card, reg, (u8 *)&buff, sizeof(u16));
-}
-
-static inline int spu_reg_is_port_reg(u16 reg)
-{
-       switch (reg) {
-       case IF_SPI_IO_RDWRPORT_REG:
-       case IF_SPI_CMD_RDWRPORT_REG:
-       case IF_SPI_DATA_RDWRPORT_REG:
-               return 1;
-       default:
-               return 0;
-       }
-}
-
-static int spu_read(struct if_spi_card *card, u16 reg, u8 *buf, int len)
-{
-       unsigned int delay;
-       int err = 0;
-       __le16 reg_out = cpu_to_le16(reg | IF_SPI_READ_OPERATION_MASK);
-       struct spi_message m;
-       struct spi_transfer reg_trans;
-       struct spi_transfer dummy_trans;
-       struct spi_transfer data_trans;
-
-       /*
-        * You must take an even number of bytes from the SPU, even if you
-        * don't care about the last one.
-        */
-       BUG_ON(len & 0x1);
-
-       spu_transaction_init(card);
-
-       spi_message_init(&m);
-       memset(&reg_trans, 0, sizeof(reg_trans));
-       memset(&dummy_trans, 0, sizeof(dummy_trans));
-       memset(&data_trans, 0, sizeof(data_trans));
-
-       /* write SPU register index */
-       reg_trans.tx_buf = &reg_out;
-       reg_trans.len = sizeof(reg_out);
-       spi_message_add_tail(&reg_trans, &m);
-
-       delay = spu_reg_is_port_reg(reg) ? card->spu_port_delay :
-                                               card->spu_reg_delay;
-       if (card->use_dummy_writes) {
-               /* Clock in dummy cycles while the SPU fills the FIFO */
-               dummy_trans.len = delay / 8;
-               spi_message_add_tail(&dummy_trans, &m);
-       } else {
-               /* Busy-wait while the SPU fills the FIFO */
-               reg_trans.delay_usecs =
-                       DIV_ROUND_UP((100 + (delay * 10)), 1000);
-       }
-
-       /* read in data */
-       data_trans.rx_buf = buf;
-       data_trans.len = len;
-       spi_message_add_tail(&data_trans, &m);
-
-       err = spi_sync(card->spi, &m);
-       spu_transaction_finish(card);
-       return err;
-}
-
-/* Read 16 bits from an SPI register */
-static inline int spu_read_u16(struct if_spi_card *card, u16 reg, u16 *val)
-{
-       __le16 buf;
-       int ret;
-
-       ret = spu_read(card, reg, (u8 *)&buf, sizeof(buf));
-       if (ret == 0)
-               *val = le16_to_cpup(&buf);
-       return ret;
-}
-
-/*
- * Read 32 bits from an SPI register.
- * The low 16 bits are read first.
- */
-static int spu_read_u32(struct if_spi_card *card, u16 reg, u32 *val)
-{
-       __le32 buf;
-       int err;
-
-       err = spu_read(card, reg, (u8 *)&buf, sizeof(buf));
-       if (!err)
-               *val = le32_to_cpup(&buf);
-       return err;
-}
-
-/*
- * Keep reading 16 bits from an SPI register until you get the correct result.
- *
- * If mask = 0, the correct result is any non-zero number.
- * If mask != 0, the correct result is any number where
- * number & target_mask == target
- *
- * Returns -ETIMEDOUT if a second passes without the correct result.
- */
-static int spu_wait_for_u16(struct if_spi_card *card, u16 reg,
-                       u16 target_mask, u16 target)
-{
-       int err;
-       unsigned long timeout = jiffies + 5*HZ;
-       while (1) {
-               u16 val;
-               err = spu_read_u16(card, reg, &val);
-               if (err)
-                       return err;
-               if (target_mask) {
-                       if ((val & target_mask) == target)
-                               return 0;
-               } else {
-                       if (val)
-                               return 0;
-               }
-               udelay(100);
-               if (time_after(jiffies, timeout)) {
-                       pr_err("%s: timeout with val=%02x, target_mask=%02x, target=%02x\n",
-                              __func__, val, target_mask, target);
-                       return -ETIMEDOUT;
-               }
-       }
-}
-
-/*
- * Read 16 bits from an SPI register until you receive a specific value.
- * Returns -ETIMEDOUT if a 4 tries pass without success.
- */
-static int spu_wait_for_u32(struct if_spi_card *card, u32 reg, u32 target)
-{
-       int err, try;
-       for (try = 0; try < 4; ++try) {
-               u32 val = 0;
-               err = spu_read_u32(card, reg, &val);
-               if (err)
-                       return err;
-               if (val == target)
-                       return 0;
-               mdelay(100);
-       }
-       return -ETIMEDOUT;
-}
-
-static int spu_set_interrupt_mode(struct if_spi_card *card,
-                          int suppress_host_int,
-                          int auto_int)
-{
-       int err = 0;
-
-       /*
-        * We can suppress a host interrupt by clearing the appropriate
-        * bit in the "host interrupt status mask" register
-        */
-       if (suppress_host_int) {
-               err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_MASK_REG, 0);
-               if (err)
-                       return err;
-       } else {
-               err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_MASK_REG,
-                             IF_SPI_HISM_TX_DOWNLOAD_RDY |
-                             IF_SPI_HISM_RX_UPLOAD_RDY |
-                             IF_SPI_HISM_CMD_DOWNLOAD_RDY |
-                             IF_SPI_HISM_CARDEVENT |
-                             IF_SPI_HISM_CMD_UPLOAD_RDY);
-               if (err)
-                       return err;
-       }
-
-       /*
-        * If auto-interrupts are on, the completion of certain transactions
-        * will trigger an interrupt automatically. If auto-interrupts
-        * are off, we need to set the "Card Interrupt Cause" register to
-        * trigger a card interrupt.
-        */
-       if (auto_int) {
-               err = spu_write_u16(card, IF_SPI_HOST_INT_CTRL_REG,
-                               IF_SPI_HICT_TX_DOWNLOAD_OVER_AUTO |
-                               IF_SPI_HICT_RX_UPLOAD_OVER_AUTO |
-                               IF_SPI_HICT_CMD_DOWNLOAD_OVER_AUTO |
-                               IF_SPI_HICT_CMD_UPLOAD_OVER_AUTO);
-               if (err)
-                       return err;
-       } else {
-               err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_MASK_REG, 0);
-               if (err)
-                       return err;
-       }
-       return err;
-}
-
-static int spu_get_chip_revision(struct if_spi_card *card,
-                                 u16 *card_id, u8 *card_rev)
-{
-       int err = 0;
-       u32 dev_ctrl;
-       err = spu_read_u32(card, IF_SPI_DEVICEID_CTRL_REG, &dev_ctrl);
-       if (err)
-               return err;
-       *card_id = IF_SPI_DEVICEID_CTRL_REG_TO_CARD_ID(dev_ctrl);
-       *card_rev = IF_SPI_DEVICEID_CTRL_REG_TO_CARD_REV(dev_ctrl);
-       return err;
-}
-
-static int spu_set_bus_mode(struct if_spi_card *card, u16 mode)
-{
-       int err = 0;
-       u16 rval;
-       /* set bus mode */
-       err = spu_write_u16(card, IF_SPI_SPU_BUS_MODE_REG, mode);
-       if (err)
-               return err;
-       /* Check that we were able to read back what we just wrote. */
-       err = spu_read_u16(card, IF_SPI_SPU_BUS_MODE_REG, &rval);
-       if (err)
-               return err;
-       if ((rval & 0xF) != mode) {
-               pr_err("Can't read bus mode register\n");
-               return -EIO;
-       }
-       return 0;
-}
-
-static int spu_init(struct if_spi_card *card, int use_dummy_writes)
-{
-       int err = 0;
-       u32 delay;
-
-       /*
-        * We have to start up in timed delay mode so that we can safely
-        * read the Delay Read Register.
-        */
-       card->use_dummy_writes = 0;
-       err = spu_set_bus_mode(card,
-                               IF_SPI_BUS_MODE_SPI_CLOCK_PHASE_RISING |
-                               IF_SPI_BUS_MODE_DELAY_METHOD_TIMED |
-                               IF_SPI_BUS_MODE_16_BIT_ADDRESS_16_BIT_DATA);
-       if (err)
-               return err;
-       card->spu_port_delay = 1000;
-       card->spu_reg_delay = 1000;
-       err = spu_read_u32(card, IF_SPI_DELAY_READ_REG, &delay);
-       if (err)
-               return err;
-       card->spu_port_delay = delay & 0x0000ffff;
-       card->spu_reg_delay = (delay & 0xffff0000) >> 16;
-
-       /* If dummy clock delay mode has been requested, switch to it now */
-       if (use_dummy_writes) {
-               card->use_dummy_writes = 1;
-               err = spu_set_bus_mode(card,
-                               IF_SPI_BUS_MODE_SPI_CLOCK_PHASE_RISING |
-                               IF_SPI_BUS_MODE_DELAY_METHOD_DUMMY_CLOCK |
-                               IF_SPI_BUS_MODE_16_BIT_ADDRESS_16_BIT_DATA);
-               if (err)
-                       return err;
-       }
-
-       lbs_deb_spi("Initialized SPU unit. "
-                   "spu_port_delay=0x%04lx, spu_reg_delay=0x%04lx\n",
-                   card->spu_port_delay, card->spu_reg_delay);
-       return err;
-}
-
-/*
- * Firmware Loading
- */
-
-static int if_spi_prog_helper_firmware(struct if_spi_card *card,
-                                       const struct firmware *firmware)
-{
-       int err = 0;
-       int bytes_remaining;
-       const u8 *fw;
-       u8 temp[HELPER_FW_LOAD_CHUNK_SZ];
-
-       lbs_deb_enter(LBS_DEB_SPI);
-
-       err = spu_set_interrupt_mode(card, 1, 0);
-       if (err)
-               goto out;
-
-       bytes_remaining = firmware->size;
-       fw = firmware->data;
-
-       /* Load helper firmware image */
-       while (bytes_remaining > 0) {
-               /*
-                * Scratch pad 1 should contain the number of bytes we
-                * want to download to the firmware
-                */
-               err = spu_write_u16(card, IF_SPI_SCRATCH_1_REG,
-                                       HELPER_FW_LOAD_CHUNK_SZ);
-               if (err)
-                       goto out;
-
-               err = spu_wait_for_u16(card, IF_SPI_HOST_INT_STATUS_REG,
-                                       IF_SPI_HIST_CMD_DOWNLOAD_RDY,
-                                       IF_SPI_HIST_CMD_DOWNLOAD_RDY);
-               if (err)
-                       goto out;
-
-               /*
-                * Feed the data into the command read/write port reg
-                * in chunks of 64 bytes
-                */
-               memset(temp, 0, sizeof(temp));
-               memcpy(temp, fw,
-                      min(bytes_remaining, HELPER_FW_LOAD_CHUNK_SZ));
-               mdelay(10);
-               err = spu_write(card, IF_SPI_CMD_RDWRPORT_REG,
-                                       temp, HELPER_FW_LOAD_CHUNK_SZ);
-               if (err)
-                       goto out;
-
-               /* Interrupt the boot code */
-               err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG, 0);
-               if (err)
-                       goto out;
-               err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG,
-                                      IF_SPI_CIC_CMD_DOWNLOAD_OVER);
-               if (err)
-                       goto out;
-               bytes_remaining -= HELPER_FW_LOAD_CHUNK_SZ;
-               fw += HELPER_FW_LOAD_CHUNK_SZ;
-       }
-
-       /*
-        * Once the helper / single stage firmware download is complete,
-        * write 0 to scratch pad 1 and interrupt the
-        * bootloader. This completes the helper download.
-        */
-       err = spu_write_u16(card, IF_SPI_SCRATCH_1_REG, FIRMWARE_DNLD_OK);
-       if (err)
-               goto out;
-       err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG, 0);
-       if (err)
-               goto out;
-       err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG,
-                               IF_SPI_CIC_CMD_DOWNLOAD_OVER);
-out:
-       if (err)
-               pr_err("failed to load helper firmware (err=%d)\n", err);
-       lbs_deb_leave_args(LBS_DEB_SPI, "err %d", err);
-       return err;
-}
-
-/*
- * Returns the length of the next packet the firmware expects us to send.
- * Sets crc_err if the previous transfer had a CRC error.
- */
-static int if_spi_prog_main_firmware_check_len(struct if_spi_card *card,
-                                               int *crc_err)
-{
-       u16 len;
-       int err = 0;
-
-       /*
-        * wait until the host interrupt status register indicates
-        * that we are ready to download
-        */
-       err = spu_wait_for_u16(card, IF_SPI_HOST_INT_STATUS_REG,
-                               IF_SPI_HIST_CMD_DOWNLOAD_RDY,
-                               IF_SPI_HIST_CMD_DOWNLOAD_RDY);
-       if (err) {
-               pr_err("timed out waiting for host_int_status\n");
-               return err;
-       }
-
-       /* Ask the device how many bytes of firmware it wants. */
-       err = spu_read_u16(card, IF_SPI_SCRATCH_1_REG, &len);
-       if (err)
-               return err;
-
-       if (len > IF_SPI_CMD_BUF_SIZE) {
-               pr_err("firmware load device requested a larger transfer than we are prepared to handle (len = %d)\n",
-                      len);
-               return -EIO;
-       }
-       if (len & 0x1) {
-               lbs_deb_spi("%s: crc error\n", __func__);
-               len &= ~0x1;
-               *crc_err = 1;
-       } else
-               *crc_err = 0;
-
-       return len;
-}
-
-static int if_spi_prog_main_firmware(struct if_spi_card *card,
-                                       const struct firmware *firmware)
-{
-       struct lbs_private *priv = card->priv;
-       int len, prev_len;
-       int bytes, crc_err = 0, err = 0;
-       const u8 *fw;
-       u16 num_crc_errs;
-
-       lbs_deb_enter(LBS_DEB_SPI);
-
-       err = spu_set_interrupt_mode(card, 1, 0);
-       if (err)
-               goto out;
-
-       err = spu_wait_for_u16(card, IF_SPI_SCRATCH_1_REG, 0, 0);
-       if (err) {
-               netdev_err(priv->dev,
-                          "%s: timed out waiting for initial scratch reg = 0\n",
-                          __func__);
-               goto out;
-       }
-
-       num_crc_errs = 0;
-       prev_len = 0;
-       bytes = firmware->size;
-       fw = firmware->data;
-       while ((len = if_spi_prog_main_firmware_check_len(card, &crc_err))) {
-               if (len < 0) {
-                       err = len;
-                       goto out;
-               }
-               if (bytes < 0) {
-                       /*
-                        * If there are no more bytes left, we would normally
-                        * expect to have terminated with len = 0
-                        */
-                       netdev_err(priv->dev,
-                                  "Firmware load wants more bytes than we have to offer.\n");
-                       break;
-               }
-               if (crc_err) {
-                       /* Previous transfer failed. */
-                       if (++num_crc_errs > MAX_MAIN_FW_LOAD_CRC_ERR) {
-                               pr_err("Too many CRC errors encountered in firmware load.\n");
-                               err = -EIO;
-                               goto out;
-                       }
-               } else {
-                       /* Previous transfer succeeded. Advance counters. */
-                       bytes -= prev_len;
-                       fw += prev_len;
-               }
-               if (bytes < len) {
-                       memset(card->cmd_buffer, 0, len);
-                       memcpy(card->cmd_buffer, fw, bytes);
-               } else
-                       memcpy(card->cmd_buffer, fw, len);
-
-               err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG, 0);
-               if (err)
-                       goto out;
-               err = spu_write(card, IF_SPI_CMD_RDWRPORT_REG,
-                               card->cmd_buffer, len);
-               if (err)
-                       goto out;
-               err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG ,
-                                       IF_SPI_CIC_CMD_DOWNLOAD_OVER);
-               if (err)
-                       goto out;
-               prev_len = len;
-       }
-       if (bytes > prev_len) {
-               pr_err("firmware load wants fewer bytes than we have to offer\n");
-       }
-
-       /* Confirm firmware download */
-       err = spu_wait_for_u32(card, IF_SPI_SCRATCH_4_REG,
-                                       SUCCESSFUL_FW_DOWNLOAD_MAGIC);
-       if (err) {
-               pr_err("failed to confirm the firmware download\n");
-               goto out;
-       }
-
-out:
-       if (err)
-               pr_err("failed to load firmware (err=%d)\n", err);
-       lbs_deb_leave_args(LBS_DEB_SPI, "err %d", err);
-       return err;
-}
-
-/*
- * SPI Transfer Thread
- *
- * The SPI worker handles all SPI transfers, so there is no need for a lock.
- */
-
-/* Move a command from the card to the host */
-static int if_spi_c2h_cmd(struct if_spi_card *card)
-{
-       struct lbs_private *priv = card->priv;
-       unsigned long flags;
-       int err = 0;
-       u16 len;
-       u8 i;
-
-       /*
-        * We need a buffer big enough to handle whatever people send to
-        * hw_host_to_card
-        */
-       BUILD_BUG_ON(IF_SPI_CMD_BUF_SIZE < LBS_CMD_BUFFER_SIZE);
-       BUILD_BUG_ON(IF_SPI_CMD_BUF_SIZE < LBS_UPLD_SIZE);
-
-       /*
-        * It's just annoying if the buffer size isn't a multiple of 4, because
-        * then we might have len < IF_SPI_CMD_BUF_SIZE but
-        * ALIGN(len, 4) > IF_SPI_CMD_BUF_SIZE
-        */
-       BUILD_BUG_ON(IF_SPI_CMD_BUF_SIZE % 4 != 0);
-
-       lbs_deb_enter(LBS_DEB_SPI);
-
-       /* How many bytes are there to read? */
-       err = spu_read_u16(card, IF_SPI_SCRATCH_2_REG, &len);
-       if (err)
-               goto out;
-       if (!len) {
-               netdev_err(priv->dev, "%s: error: card has no data for host\n",
-                          __func__);
-               err = -EINVAL;
-               goto out;
-       } else if (len > IF_SPI_CMD_BUF_SIZE) {
-               netdev_err(priv->dev,
-                          "%s: error: response packet too large: %d bytes, but maximum is %d\n",
-                          __func__, len, IF_SPI_CMD_BUF_SIZE);
-               err = -EINVAL;
-               goto out;
-       }
-
-       /* Read the data from the WLAN module into our command buffer */
-       err = spu_read(card, IF_SPI_CMD_RDWRPORT_REG,
-                               card->cmd_buffer, ALIGN(len, 4));
-       if (err)
-               goto out;
-
-       spin_lock_irqsave(&priv->driver_lock, flags);
-       i = (priv->resp_idx == 0) ? 1 : 0;
-       BUG_ON(priv->resp_len[i]);
-       priv->resp_len[i] = len;
-       memcpy(priv->resp_buf[i], card->cmd_buffer, len);
-       lbs_notify_command_response(priv, i);
-       spin_unlock_irqrestore(&priv->driver_lock, flags);
-
-out:
-       if (err)
-               netdev_err(priv->dev, "%s: err=%d\n", __func__, err);
-       lbs_deb_leave(LBS_DEB_SPI);
-       return err;
-}
-
-/* Move data from the card to the host */
-static int if_spi_c2h_data(struct if_spi_card *card)
-{
-       struct lbs_private *priv = card->priv;
-       struct sk_buff *skb;
-       char *data;
-       u16 len;
-       int err = 0;
-
-       lbs_deb_enter(LBS_DEB_SPI);
-
-       /* How many bytes are there to read? */
-       err = spu_read_u16(card, IF_SPI_SCRATCH_1_REG, &len);
-       if (err)
-               goto out;
-       if (!len) {
-               netdev_err(priv->dev, "%s: error: card has no data for host\n",
-                          __func__);
-               err = -EINVAL;
-               goto out;
-       } else if (len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
-               netdev_err(priv->dev,
-                          "%s: error: card has %d bytes of data, but our maximum skb size is %zu\n",
-                          __func__, len, MRVDRV_ETH_RX_PACKET_BUFFER_SIZE);
-               err = -EINVAL;
-               goto out;
-       }
-
-       /* TODO: should we allocate a smaller skb if we have less data? */
-       skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE);
-       if (!skb) {
-               err = -ENOBUFS;
-               goto out;
-       }
-       skb_reserve(skb, IPFIELD_ALIGN_OFFSET);
-       data = skb_put(skb, len);
-
-       /* Read the data from the WLAN module into our skb... */
-       err = spu_read(card, IF_SPI_DATA_RDWRPORT_REG, data, ALIGN(len, 4));
-       if (err)
-               goto free_skb;
-
-       /* pass the SKB to libertas */
-       err = lbs_process_rxed_packet(card->priv, skb);
-       if (err)
-               goto free_skb;
-
-       /* success */
-       goto out;
-
-free_skb:
-       dev_kfree_skb(skb);
-out:
-       if (err)
-               netdev_err(priv->dev, "%s: err=%d\n", __func__, err);
-       lbs_deb_leave(LBS_DEB_SPI);
-       return err;
-}
-
-/* Move data or a command from the host to the card. */
-static void if_spi_h2c(struct if_spi_card *card,
-                       struct if_spi_packet *packet, int type)
-{
-       struct lbs_private *priv = card->priv;
-       int err = 0;
-       u16 int_type, port_reg;
-
-       switch (type) {
-       case MVMS_DAT:
-               int_type = IF_SPI_CIC_TX_DOWNLOAD_OVER;
-               port_reg = IF_SPI_DATA_RDWRPORT_REG;
-               break;
-       case MVMS_CMD:
-               int_type = IF_SPI_CIC_CMD_DOWNLOAD_OVER;
-               port_reg = IF_SPI_CMD_RDWRPORT_REG;
-               break;
-       default:
-               netdev_err(priv->dev, "can't transfer buffer of type %d\n",
-                          type);
-               err = -EINVAL;
-               goto out;
-       }
-
-       /* Write the data to the card */
-       err = spu_write(card, port_reg, packet->buffer, packet->blen);
-       if (err)
-               goto out;
-
-out:
-       kfree(packet);
-
-       if (err)
-               netdev_err(priv->dev, "%s: error %d\n", __func__, err);
-}
-
-/* Inform the host about a card event */
-static void if_spi_e2h(struct if_spi_card *card)
-{
-       int err = 0;
-       u32 cause;
-       struct lbs_private *priv = card->priv;
-
-       err = spu_read_u32(card, IF_SPI_SCRATCH_3_REG, &cause);
-       if (err)
-               goto out;
-
-       /* re-enable the card event interrupt */
-       spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG,
-                       ~IF_SPI_HICU_CARD_EVENT);
-
-       /* generate a card interrupt */
-       spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG, IF_SPI_CIC_HOST_EVENT);
-
-       lbs_queue_event(priv, cause & 0xff);
-out:
-       if (err)
-               netdev_err(priv->dev, "%s: error %d\n", __func__, err);
-}
-
-static void if_spi_host_to_card_worker(struct work_struct *work)
-{
-       int err;
-       struct if_spi_card *card;
-       u16 hiStatus;
-       unsigned long flags;
-       struct if_spi_packet *packet;
-       struct lbs_private *priv;
-
-       card = container_of(work, struct if_spi_card, packet_work);
-       priv = card->priv;
-
-       lbs_deb_enter(LBS_DEB_SPI);
-
-       /*
-        * Read the host interrupt status register to see what we
-        * can do.
-        */
-       err = spu_read_u16(card, IF_SPI_HOST_INT_STATUS_REG,
-                               &hiStatus);
-       if (err) {
-               netdev_err(priv->dev, "I/O error\n");
-               goto err;
-       }
-
-       if (hiStatus & IF_SPI_HIST_CMD_UPLOAD_RDY) {
-               err = if_spi_c2h_cmd(card);
-               if (err)
-                       goto err;
-       }
-       if (hiStatus & IF_SPI_HIST_RX_UPLOAD_RDY) {
-               err = if_spi_c2h_data(card);
-               if (err)
-                       goto err;
-       }
-
-       /*
-        * workaround: in PS mode, the card does not set the Command
-        * Download Ready bit, but it sets TX Download Ready.
-        */
-       if (hiStatus & IF_SPI_HIST_CMD_DOWNLOAD_RDY ||
-          (card->priv->psstate != PS_STATE_FULL_POWER &&
-           (hiStatus & IF_SPI_HIST_TX_DOWNLOAD_RDY))) {
-               /*
-                * This means two things. First of all,
-                * if there was a previous command sent, the card has
-                * successfully received it.
-                * Secondly, it is now ready to download another
-                * command.
-                */
-               lbs_host_to_card_done(card->priv);
-
-               /* Do we have any command packets from the host to send? */
-               packet = NULL;
-               spin_lock_irqsave(&card->buffer_lock, flags);
-               if (!list_empty(&card->cmd_packet_list)) {
-                       packet = (struct if_spi_packet *)(card->
-                                       cmd_packet_list.next);
-                       list_del(&packet->list);
-               }
-               spin_unlock_irqrestore(&card->buffer_lock, flags);
-
-               if (packet)
-                       if_spi_h2c(card, packet, MVMS_CMD);
-       }
-       if (hiStatus & IF_SPI_HIST_TX_DOWNLOAD_RDY) {
-               /* Do we have any data packets from the host to send? */
-               packet = NULL;
-               spin_lock_irqsave(&card->buffer_lock, flags);
-               if (!list_empty(&card->data_packet_list)) {
-                       packet = (struct if_spi_packet *)(card->
-                                       data_packet_list.next);
-                       list_del(&packet->list);
-               }
-               spin_unlock_irqrestore(&card->buffer_lock, flags);
-
-               if (packet)
-                       if_spi_h2c(card, packet, MVMS_DAT);
-       }
-       if (hiStatus & IF_SPI_HIST_CARD_EVENT)
-               if_spi_e2h(card);
-
-err:
-       if (err)
-               netdev_err(priv->dev, "%s: got error %d\n", __func__, err);
-
-       lbs_deb_leave(LBS_DEB_SPI);
-}
-
-/*
- * Host to Card
- *
- * Called from Libertas to transfer some data to the WLAN device
- * We can't sleep here.
- */
-static int if_spi_host_to_card(struct lbs_private *priv,
-                               u8 type, u8 *buf, u16 nb)
-{
-       int err = 0;
-       unsigned long flags;
-       struct if_spi_card *card = priv->card;
-       struct if_spi_packet *packet;
-       u16 blen;
-
-       lbs_deb_enter_args(LBS_DEB_SPI, "type %d, bytes %d", type, nb);
-
-       if (nb == 0) {
-               netdev_err(priv->dev, "%s: invalid size requested: %d\n",
-                          __func__, nb);
-               err = -EINVAL;
-               goto out;
-       }
-       blen = ALIGN(nb, 4);
-       packet = kzalloc(sizeof(struct if_spi_packet) + blen, GFP_ATOMIC);
-       if (!packet) {
-               err = -ENOMEM;
-               goto out;
-       }
-       packet->blen = blen;
-       memcpy(packet->buffer, buf, nb);
-       memset(packet->buffer + nb, 0, blen - nb);
-
-       switch (type) {
-       case MVMS_CMD:
-               priv->dnld_sent = DNLD_CMD_SENT;
-               spin_lock_irqsave(&card->buffer_lock, flags);
-               list_add_tail(&packet->list, &card->cmd_packet_list);
-               spin_unlock_irqrestore(&card->buffer_lock, flags);
-               break;
-       case MVMS_DAT:
-               priv->dnld_sent = DNLD_DATA_SENT;
-               spin_lock_irqsave(&card->buffer_lock, flags);
-               list_add_tail(&packet->list, &card->data_packet_list);
-               spin_unlock_irqrestore(&card->buffer_lock, flags);
-               break;
-       default:
-               kfree(packet);
-               netdev_err(priv->dev, "can't transfer buffer of type %d\n",
-                          type);
-               err = -EINVAL;
-               break;
-       }
-
-       /* Queue spi xfer work */
-       queue_work(card->workqueue, &card->packet_work);
-out:
-       lbs_deb_leave_args(LBS_DEB_SPI, "err=%d", err);
-       return err;
-}
-
-/*
- * Host Interrupts
- *
- * Service incoming interrupts from the WLAN device. We can't sleep here, so
- * don't try to talk on the SPI bus, just queue the SPI xfer work.
- */
-static irqreturn_t if_spi_host_interrupt(int irq, void *dev_id)
-{
-       struct if_spi_card *card = dev_id;
-
-       queue_work(card->workqueue, &card->packet_work);
-
-       return IRQ_HANDLED;
-}
-
-/*
- * SPI callbacks
- */
-
-static int if_spi_init_card(struct if_spi_card *card)
-{
-       struct lbs_private *priv = card->priv;
-       int err, i;
-       u32 scratch;
-       const struct firmware *helper = NULL;
-       const struct firmware *mainfw = NULL;
-
-       lbs_deb_enter(LBS_DEB_SPI);
-
-       err = spu_init(card, card->pdata->use_dummy_writes);
-       if (err)
-               goto out;
-       err = spu_get_chip_revision(card, &card->card_id, &card->card_rev);
-       if (err)
-               goto out;
-
-       err = spu_read_u32(card, IF_SPI_SCRATCH_4_REG, &scratch);
-       if (err)
-               goto out;
-       if (scratch == SUCCESSFUL_FW_DOWNLOAD_MAGIC)
-               lbs_deb_spi("Firmware is already loaded for "
-                           "Marvell WLAN 802.11 adapter\n");
-       else {
-               /* Check if we support this card */
-               for (i = 0; i < ARRAY_SIZE(fw_table); i++) {
-                       if (card->card_id == fw_table[i].model)
-                               break;
-               }
-               if (i == ARRAY_SIZE(fw_table)) {
-                       netdev_err(priv->dev, "Unsupported chip_id: 0x%02x\n",
-                                  card->card_id);
-                       err = -ENODEV;
-                       goto out;
-               }
-
-               err = lbs_get_firmware(&card->spi->dev, card->card_id,
-                                       &fw_table[0], &helper, &mainfw);
-               if (err) {
-                       netdev_err(priv->dev, "failed to find firmware (%d)\n",
-                                  err);
-                       goto out;
-               }
-
-               lbs_deb_spi("Initializing FW for Marvell WLAN 802.11 adapter "
-                               "(chip_id = 0x%04x, chip_rev = 0x%02x) "
-                               "attached to SPI bus_num %d, chip_select %d. "
-                               "spi->max_speed_hz=%d\n",
-                               card->card_id, card->card_rev,
-                               card->spi->master->bus_num,
-                               card->spi->chip_select,
-                               card->spi->max_speed_hz);
-               err = if_spi_prog_helper_firmware(card, helper);
-               if (err)
-                       goto out;
-               err = if_spi_prog_main_firmware(card, mainfw);
-               if (err)
-                       goto out;
-               lbs_deb_spi("loaded FW for Marvell WLAN 802.11 adapter\n");
-       }
-
-       err = spu_set_interrupt_mode(card, 0, 1);
-       if (err)
-               goto out;
-
-out:
-       lbs_deb_leave_args(LBS_DEB_SPI, "err %d\n", err);
-       return err;
-}
-
-static void if_spi_resume_worker(struct work_struct *work)
-{
-       struct if_spi_card *card;
-
-       card = container_of(work, struct if_spi_card, resume_work);
-
-       if (card->suspended) {
-               if (card->pdata->setup)
-                       card->pdata->setup(card->spi);
-
-               /* Init card ... */
-               if_spi_init_card(card);
-
-               enable_irq(card->spi->irq);
-
-               /* And resume it ... */
-               lbs_resume(card->priv);
-
-               card->suspended = 0;
-       }
-}
-
-static int if_spi_probe(struct spi_device *spi)
-{
-       struct if_spi_card *card;
-       struct lbs_private *priv = NULL;
-       struct libertas_spi_platform_data *pdata = dev_get_platdata(&spi->dev);
-       int err = 0;
-
-       lbs_deb_enter(LBS_DEB_SPI);
-
-       if (!pdata) {
-               err = -EINVAL;
-               goto out;
-       }
-
-       if (pdata->setup) {
-               err = pdata->setup(spi);
-               if (err)
-                       goto out;
-       }
-
-       /* Allocate card structure to represent this specific device */
-       card = kzalloc(sizeof(struct if_spi_card), GFP_KERNEL);
-       if (!card) {
-               err = -ENOMEM;
-               goto teardown;
-       }
-       spi_set_drvdata(spi, card);
-       card->pdata = pdata;
-       card->spi = spi;
-       card->prev_xfer_time = jiffies;
-
-       INIT_LIST_HEAD(&card->cmd_packet_list);
-       INIT_LIST_HEAD(&card->data_packet_list);
-       spin_lock_init(&card->buffer_lock);
-
-       /* Initialize the SPI Interface Unit */
-
-       /* Firmware load */
-       err = if_spi_init_card(card);
-       if (err)
-               goto free_card;
-
-       /*
-        * Register our card with libertas.
-        * This will call alloc_etherdev.
-        */
-       priv = lbs_add_card(card, &spi->dev);
-       if (!priv) {
-               err = -ENOMEM;
-               goto free_card;
-       }
-       card->priv = priv;
-       priv->setup_fw_on_resume = 1;
-       priv->card = card;
-       priv->hw_host_to_card = if_spi_host_to_card;
-       priv->enter_deep_sleep = NULL;
-       priv->exit_deep_sleep = NULL;
-       priv->reset_deep_sleep_wakeup = NULL;
-       priv->fw_ready = 1;
-
-       /* Initialize interrupt handling stuff. */
-       card->workqueue = create_workqueue("libertas_spi");
-       INIT_WORK(&card->packet_work, if_spi_host_to_card_worker);
-       INIT_WORK(&card->resume_work, if_spi_resume_worker);
-
-       err = request_irq(spi->irq, if_spi_host_interrupt,
-                       IRQF_TRIGGER_FALLING, "libertas_spi", card);
-       if (err) {
-               pr_err("can't get host irq line-- request_irq failed\n");
-               goto terminate_workqueue;
-       }
-
-       /*
-        * Start the card.
-        * This will call register_netdev, and we'll start
-        * getting interrupts...
-        */
-       err = lbs_start_card(priv);
-       if (err)
-               goto release_irq;
-
-       lbs_deb_spi("Finished initializing WLAN module.\n");
-
-       /* successful exit */
-       goto out;
-
-release_irq:
-       free_irq(spi->irq, card);
-terminate_workqueue:
-       flush_workqueue(card->workqueue);
-       destroy_workqueue(card->workqueue);
-       lbs_remove_card(priv); /* will call free_netdev */
-free_card:
-       free_if_spi_card(card);
-teardown:
-       if (pdata->teardown)
-               pdata->teardown(spi);
-out:
-       lbs_deb_leave_args(LBS_DEB_SPI, "err %d\n", err);
-       return err;
-}
-
-static int libertas_spi_remove(struct spi_device *spi)
-{
-       struct if_spi_card *card = spi_get_drvdata(spi);
-       struct lbs_private *priv = card->priv;
-
-       lbs_deb_spi("libertas_spi_remove\n");
-       lbs_deb_enter(LBS_DEB_SPI);
-
-       cancel_work_sync(&card->resume_work);
-
-       lbs_stop_card(priv);
-       lbs_remove_card(priv); /* will call free_netdev */
-
-       free_irq(spi->irq, card);
-       flush_workqueue(card->workqueue);
-       destroy_workqueue(card->workqueue);
-       if (card->pdata->teardown)
-               card->pdata->teardown(spi);
-       free_if_spi_card(card);
-       lbs_deb_leave(LBS_DEB_SPI);
-       return 0;
-}
-
-static int if_spi_suspend(struct device *dev)
-{
-       struct spi_device *spi = to_spi_device(dev);
-       struct if_spi_card *card = spi_get_drvdata(spi);
-
-       if (!card->suspended) {
-               lbs_suspend(card->priv);
-               flush_workqueue(card->workqueue);
-               disable_irq(spi->irq);
-
-               if (card->pdata->teardown)
-                       card->pdata->teardown(spi);
-               card->suspended = 1;
-       }
-
-       return 0;
-}
-
-static int if_spi_resume(struct device *dev)
-{
-       struct spi_device *spi = to_spi_device(dev);
-       struct if_spi_card *card = spi_get_drvdata(spi);
-
-       /* Schedule delayed work */
-       schedule_work(&card->resume_work);
-
-       return 0;
-}
-
-static const struct dev_pm_ops if_spi_pm_ops = {
-       .suspend        = if_spi_suspend,
-       .resume         = if_spi_resume,
-};
-
-static struct spi_driver libertas_spi_driver = {
-       .probe  = if_spi_probe,
-       .remove = libertas_spi_remove,
-       .driver = {
-               .name   = "libertas_spi",
-               .pm     = &if_spi_pm_ops,
-       },
-};
-
-/*
- * Module functions
- */
-
-static int __init if_spi_init_module(void)
-{
-       int ret = 0;
-       lbs_deb_enter(LBS_DEB_SPI);
-       printk(KERN_INFO "libertas_spi: Libertas SPI driver\n");
-       ret = spi_register_driver(&libertas_spi_driver);
-       lbs_deb_leave(LBS_DEB_SPI);
-       return ret;
-}
-
-static void __exit if_spi_exit_module(void)
-{
-       lbs_deb_enter(LBS_DEB_SPI);
-       spi_unregister_driver(&libertas_spi_driver);
-       lbs_deb_leave(LBS_DEB_SPI);
-}
-
-module_init(if_spi_init_module);
-module_exit(if_spi_exit_module);
-
-MODULE_DESCRIPTION("Libertas SPI WLAN Driver");
-MODULE_AUTHOR("Andrey Yurovsky <andrey@cozybit.com>, "
-             "Colin McCabe <colin@cozybit.com>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("spi:libertas_spi");
diff --git a/drivers/net/wireless/libertas/if_spi.h b/drivers/net/wireless/libertas/if_spi.h
deleted file mode 100644 (file)
index e450e31..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- *     linux/drivers/net/wireless/libertas/if_spi.c
- *
- *     Driver for Marvell SPI WLAN cards.
- *
- *     Copyright 2008 Analog Devices Inc.
- *
- *     Authors:
- *     Andrey Yurovsky <andrey@cozybit.com>
- *     Colin McCabe <colin@cozybit.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- */
-
-#ifndef _LBS_IF_SPI_H_
-#define _LBS_IF_SPI_H_
-
-#define IPFIELD_ALIGN_OFFSET 2
-#define IF_SPI_CMD_BUF_SIZE 2400
-
-/***************** Firmware *****************/
-
-#define IF_SPI_FW_NAME_MAX 30
-
-#define MAX_MAIN_FW_LOAD_CRC_ERR 10
-
-/* Chunk size when loading the helper firmware */
-#define HELPER_FW_LOAD_CHUNK_SZ 64
-
-/* Value to write to indicate end of helper firmware dnld */
-#define FIRMWARE_DNLD_OK 0x0000
-
-/* Value to check once the main firmware is downloaded */
-#define SUCCESSFUL_FW_DOWNLOAD_MAGIC 0x88888888
-
-/***************** SPI Interface Unit *****************/
-/* Masks used in SPI register read/write operations */
-#define IF_SPI_READ_OPERATION_MASK 0x0
-#define IF_SPI_WRITE_OPERATION_MASK 0x8000
-
-/* SPI register offsets. 4-byte aligned. */
-#define IF_SPI_DEVICEID_CTRL_REG 0x00  /* DeviceID controller reg */
-#define IF_SPI_IO_READBASE_REG 0x04    /* Read I/O base reg */
-#define IF_SPI_IO_WRITEBASE_REG 0x08   /* Write I/O base reg */
-#define IF_SPI_IO_RDWRPORT_REG 0x0C    /* Read/Write I/O port reg */
-
-#define IF_SPI_CMD_READBASE_REG 0x10   /* Read command base reg */
-#define IF_SPI_CMD_WRITEBASE_REG 0x14  /* Write command base reg */
-#define IF_SPI_CMD_RDWRPORT_REG 0x18   /* Read/Write command port reg */
-
-#define IF_SPI_DATA_READBASE_REG 0x1C  /* Read data base reg */
-#define IF_SPI_DATA_WRITEBASE_REG 0x20 /* Write data base reg */
-#define IF_SPI_DATA_RDWRPORT_REG 0x24  /* Read/Write data port reg */
-
-#define IF_SPI_SCRATCH_1_REG 0x28      /* Scratch reg 1 */
-#define IF_SPI_SCRATCH_2_REG 0x2C      /* Scratch reg 2 */
-#define IF_SPI_SCRATCH_3_REG 0x30      /* Scratch reg 3 */
-#define IF_SPI_SCRATCH_4_REG 0x34      /* Scratch reg 4 */
-
-#define IF_SPI_TX_FRAME_SEQ_NUM_REG 0x38 /* Tx frame sequence number reg */
-#define IF_SPI_TX_FRAME_STATUS_REG 0x3C        /* Tx frame status reg */
-
-#define IF_SPI_HOST_INT_CTRL_REG 0x40  /* Host interrupt controller reg */
-
-#define IF_SPI_CARD_INT_CAUSE_REG 0x44 /* Card interrupt cause reg */
-#define IF_SPI_CARD_INT_STATUS_REG 0x48 /* Card interrupt status reg */
-#define IF_SPI_CARD_INT_EVENT_MASK_REG 0x4C /* Card interrupt event mask */
-#define IF_SPI_CARD_INT_STATUS_MASK_REG        0x50 /* Card interrupt status mask */
-
-#define IF_SPI_CARD_INT_RESET_SELECT_REG 0x54 /* Card interrupt reset select */
-
-#define IF_SPI_HOST_INT_CAUSE_REG 0x58 /* Host interrupt cause reg */
-#define IF_SPI_HOST_INT_STATUS_REG 0x5C        /* Host interrupt status reg */
-#define IF_SPI_HOST_INT_EVENT_MASK_REG 0x60 /* Host interrupt event mask */
-#define IF_SPI_HOST_INT_STATUS_MASK_REG        0x64 /* Host interrupt status mask */
-#define IF_SPI_HOST_INT_RESET_SELECT_REG 0x68 /* Host interrupt reset select */
-
-#define IF_SPI_DELAY_READ_REG 0x6C     /* Delay read reg */
-#define IF_SPI_SPU_BUS_MODE_REG 0x70   /* SPU BUS mode reg */
-
-/***************** IF_SPI_DEVICEID_CTRL_REG *****************/
-#define IF_SPI_DEVICEID_CTRL_REG_TO_CARD_ID(dc) ((dc & 0xffff0000)>>16)
-#define IF_SPI_DEVICEID_CTRL_REG_TO_CARD_REV(dc) (dc & 0x000000ff)
-
-/***************** IF_SPI_HOST_INT_CTRL_REG *****************/
-/* Host Interrupt Control bit : Wake up */
-#define IF_SPI_HICT_WAKE_UP                            (1<<0)
-/* Host Interrupt Control bit : WLAN ready */
-#define IF_SPI_HICT_WLAN_READY                         (1<<1)
-/*#define IF_SPI_HICT_FIFO_FIRST_HALF_EMPTY            (1<<2) */
-/*#define IF_SPI_HICT_FIFO_SECOND_HALF_EMPTY           (1<<3) */
-/*#define IF_SPI_HICT_IRQSRC_WLAN                      (1<<4) */
-/* Host Interrupt Control bit : Tx auto download */
-#define IF_SPI_HICT_TX_DOWNLOAD_OVER_AUTO              (1<<5)
-/* Host Interrupt Control bit : Rx auto upload */
-#define IF_SPI_HICT_RX_UPLOAD_OVER_AUTO                        (1<<6)
-/* Host Interrupt Control bit : Command auto download */
-#define IF_SPI_HICT_CMD_DOWNLOAD_OVER_AUTO             (1<<7)
-/* Host Interrupt Control bit : Command auto upload */
-#define IF_SPI_HICT_CMD_UPLOAD_OVER_AUTO               (1<<8)
-
-/***************** IF_SPI_CARD_INT_CAUSE_REG *****************/
-/* Card Interrupt Case bit : Tx download over */
-#define IF_SPI_CIC_TX_DOWNLOAD_OVER                    (1<<0)
-/* Card Interrupt Case bit : Rx upload over */
-#define IF_SPI_CIC_RX_UPLOAD_OVER                      (1<<1)
-/* Card Interrupt Case bit : Command download over */
-#define IF_SPI_CIC_CMD_DOWNLOAD_OVER                   (1<<2)
-/* Card Interrupt Case bit : Host event */
-#define IF_SPI_CIC_HOST_EVENT                          (1<<3)
-/* Card Interrupt Case bit : Command upload over */
-#define IF_SPI_CIC_CMD_UPLOAD_OVER                     (1<<4)
-/* Card Interrupt Case bit : Power down */
-#define IF_SPI_CIC_POWER_DOWN                          (1<<5)
-
-/***************** IF_SPI_CARD_INT_STATUS_REG *****************/
-#define IF_SPI_CIS_TX_DOWNLOAD_OVER                    (1<<0)
-#define IF_SPI_CIS_RX_UPLOAD_OVER                      (1<<1)
-#define IF_SPI_CIS_CMD_DOWNLOAD_OVER                   (1<<2)
-#define IF_SPI_CIS_HOST_EVENT                          (1<<3)
-#define IF_SPI_CIS_CMD_UPLOAD_OVER                     (1<<4)
-#define IF_SPI_CIS_POWER_DOWN                          (1<<5)
-
-/***************** IF_SPI_HOST_INT_CAUSE_REG *****************/
-#define IF_SPI_HICU_TX_DOWNLOAD_RDY                    (1<<0)
-#define IF_SPI_HICU_RX_UPLOAD_RDY                      (1<<1)
-#define IF_SPI_HICU_CMD_DOWNLOAD_RDY                   (1<<2)
-#define IF_SPI_HICU_CARD_EVENT                         (1<<3)
-#define IF_SPI_HICU_CMD_UPLOAD_RDY                     (1<<4)
-#define IF_SPI_HICU_IO_WR_FIFO_OVERFLOW                        (1<<5)
-#define IF_SPI_HICU_IO_RD_FIFO_UNDERFLOW               (1<<6)
-#define IF_SPI_HICU_DATA_WR_FIFO_OVERFLOW              (1<<7)
-#define IF_SPI_HICU_DATA_RD_FIFO_UNDERFLOW             (1<<8)
-#define IF_SPI_HICU_CMD_WR_FIFO_OVERFLOW               (1<<9)
-#define IF_SPI_HICU_CMD_RD_FIFO_UNDERFLOW              (1<<10)
-
-/***************** IF_SPI_HOST_INT_STATUS_REG *****************/
-/* Host Interrupt Status bit : Tx download ready */
-#define IF_SPI_HIST_TX_DOWNLOAD_RDY                    (1<<0)
-/* Host Interrupt Status bit : Rx upload ready */
-#define IF_SPI_HIST_RX_UPLOAD_RDY                      (1<<1)
-/* Host Interrupt Status bit : Command download ready */
-#define IF_SPI_HIST_CMD_DOWNLOAD_RDY                   (1<<2)
-/* Host Interrupt Status bit : Card event */
-#define IF_SPI_HIST_CARD_EVENT                         (1<<3)
-/* Host Interrupt Status bit : Command upload ready */
-#define IF_SPI_HIST_CMD_UPLOAD_RDY                     (1<<4)
-/* Host Interrupt Status bit : I/O write FIFO overflow */
-#define IF_SPI_HIST_IO_WR_FIFO_OVERFLOW                        (1<<5)
-/* Host Interrupt Status bit : I/O read FIFO underflow */
-#define IF_SPI_HIST_IO_RD_FIFO_UNDRFLOW                        (1<<6)
-/* Host Interrupt Status bit : Data write FIFO overflow */
-#define IF_SPI_HIST_DATA_WR_FIFO_OVERFLOW              (1<<7)
-/* Host Interrupt Status bit : Data read FIFO underflow */
-#define IF_SPI_HIST_DATA_RD_FIFO_UNDERFLOW             (1<<8)
-/* Host Interrupt Status bit : Command write FIFO overflow */
-#define IF_SPI_HIST_CMD_WR_FIFO_OVERFLOW               (1<<9)
-/* Host Interrupt Status bit : Command read FIFO underflow */
-#define IF_SPI_HIST_CMD_RD_FIFO_UNDERFLOW              (1<<10)
-
-/***************** IF_SPI_HOST_INT_STATUS_MASK_REG *****************/
-/* Host Interrupt Status Mask bit : Tx download ready */
-#define IF_SPI_HISM_TX_DOWNLOAD_RDY                    (1<<0)
-/* Host Interrupt Status Mask bit : Rx upload ready */
-#define IF_SPI_HISM_RX_UPLOAD_RDY                      (1<<1)
-/* Host Interrupt Status Mask bit : Command download ready */
-#define IF_SPI_HISM_CMD_DOWNLOAD_RDY                   (1<<2)
-/* Host Interrupt Status Mask bit : Card event */
-#define IF_SPI_HISM_CARDEVENT                          (1<<3)
-/* Host Interrupt Status Mask bit : Command upload ready */
-#define IF_SPI_HISM_CMD_UPLOAD_RDY                     (1<<4)
-/* Host Interrupt Status Mask bit : I/O write FIFO overflow */
-#define IF_SPI_HISM_IO_WR_FIFO_OVERFLOW                        (1<<5)
-/* Host Interrupt Status Mask bit : I/O read FIFO underflow */
-#define IF_SPI_HISM_IO_RD_FIFO_UNDERFLOW               (1<<6)
-/* Host Interrupt Status Mask bit : Data write FIFO overflow */
-#define IF_SPI_HISM_DATA_WR_FIFO_OVERFLOW              (1<<7)
-/* Host Interrupt Status Mask bit : Data write FIFO underflow */
-#define IF_SPI_HISM_DATA_RD_FIFO_UNDERFLOW             (1<<8)
-/* Host Interrupt Status Mask bit : Command write FIFO overflow */
-#define IF_SPI_HISM_CMD_WR_FIFO_OVERFLOW               (1<<9)
-/* Host Interrupt Status Mask bit : Command write FIFO underflow */
-#define IF_SPI_HISM_CMD_RD_FIFO_UNDERFLOW              (1<<10)
-
-/***************** IF_SPI_SPU_BUS_MODE_REG *****************/
-/* SCK edge on which the WLAN module outputs data on MISO */
-#define IF_SPI_BUS_MODE_SPI_CLOCK_PHASE_FALLING 0x8
-#define IF_SPI_BUS_MODE_SPI_CLOCK_PHASE_RISING 0x0
-
-/* In a SPU read operation, there is a delay between writing the SPU
- * register name and getting back data from the WLAN module.
- * This can be specified in terms of nanoseconds or in terms of dummy
- * clock cycles which the master must output before receiving a response. */
-#define IF_SPI_BUS_MODE_DELAY_METHOD_DUMMY_CLOCK 0x4
-#define IF_SPI_BUS_MODE_DELAY_METHOD_TIMED 0x0
-
-/* Some different modes of SPI operation */
-#define IF_SPI_BUS_MODE_8_BIT_ADDRESS_16_BIT_DATA 0x00
-#define IF_SPI_BUS_MODE_8_BIT_ADDRESS_32_BIT_DATA 0x01
-#define IF_SPI_BUS_MODE_16_BIT_ADDRESS_16_BIT_DATA 0x02
-#define IF_SPI_BUS_MODE_16_BIT_ADDRESS_32_BIT_DATA 0x03
-
-#endif
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
deleted file mode 100644 (file)
index dff08a2..0000000
+++ /dev/null
@@ -1,1018 +0,0 @@
-/*
- * This file contains functions used in USB interface module.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/firmware.h>
-#include <linux/netdevice.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <linux/olpc-ec.h>
-
-#ifdef CONFIG_OLPC
-#include <asm/olpc.h>
-#endif
-
-#define DRV_NAME "usb8xxx"
-
-#include "host.h"
-#include "decl.h"
-#include "defs.h"
-#include "dev.h"
-#include "cmd.h"
-#include "if_usb.h"
-
-#define INSANEDEBUG    0
-#define lbs_deb_usb2(...) do { if (INSANEDEBUG) lbs_deb_usbd(__VA_ARGS__); } while (0)
-
-#define MESSAGE_HEADER_LEN     4
-
-MODULE_FIRMWARE("libertas/usb8388_v9.bin");
-MODULE_FIRMWARE("libertas/usb8388_v5.bin");
-MODULE_FIRMWARE("libertas/usb8388.bin");
-MODULE_FIRMWARE("libertas/usb8682.bin");
-MODULE_FIRMWARE("usb8388.bin");
-
-enum {
-       MODEL_UNKNOWN = 0x0,
-       MODEL_8388 = 0x1,
-       MODEL_8682 = 0x2
-};
-
-/* table of firmware file names */
-static const struct lbs_fw_table fw_table[] = {
-       { MODEL_8388, "libertas/usb8388_olpc.bin", NULL },
-       { MODEL_8388, "libertas/usb8388_v9.bin", NULL },
-       { MODEL_8388, "libertas/usb8388_v5.bin", NULL },
-       { MODEL_8388, "libertas/usb8388.bin", NULL },
-       { MODEL_8388, "usb8388.bin", NULL },
-       { MODEL_8682, "libertas/usb8682.bin", NULL }
-};
-
-static struct usb_device_id if_usb_table[] = {
-       /* Enter the device signature inside */
-       { USB_DEVICE(0x1286, 0x2001), .driver_info = MODEL_8388 },
-       { USB_DEVICE(0x05a3, 0x8388), .driver_info = MODEL_8388 },
-       {}      /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, if_usb_table);
-
-static void if_usb_receive(struct urb *urb);
-static void if_usb_receive_fwload(struct urb *urb);
-static void if_usb_prog_firmware(struct lbs_private *priv, int ret,
-                                const struct firmware *fw,
-                                const struct firmware *unused);
-static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
-                              uint8_t *payload, uint16_t nb);
-static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload,
-                       uint16_t nb);
-static void if_usb_free(struct if_usb_card *cardp);
-static int if_usb_submit_rx_urb(struct if_usb_card *cardp);
-static int if_usb_reset_device(struct if_usb_card *cardp);
-
-/**
- * if_usb_write_bulk_callback - callback function to handle the status
- * of the URB
- * @urb:       pointer to &urb structure
- * returns:    N/A
- */
-static void if_usb_write_bulk_callback(struct urb *urb)
-{
-       struct if_usb_card *cardp = (struct if_usb_card *) urb->context;
-
-       /* handle the transmission complete validations */
-
-       if (urb->status == 0) {
-               struct lbs_private *priv = cardp->priv;
-
-               lbs_deb_usb2(&urb->dev->dev, "URB status is successful\n");
-               lbs_deb_usb2(&urb->dev->dev, "Actual length transmitted %d\n",
-                            urb->actual_length);
-
-               /* Boot commands such as UPDATE_FW and UPDATE_BOOT2 are not
-                * passed up to the lbs level.
-                */
-               if (priv && priv->dnld_sent != DNLD_BOOTCMD_SENT)
-                       lbs_host_to_card_done(priv);
-       } else {
-               /* print the failure status number for debug */
-               pr_info("URB in failure status: %d\n", urb->status);
-       }
-}
-
-/**
- * if_usb_free - free tx/rx urb, skb and rx buffer
- * @cardp:     pointer to &if_usb_card
- * returns:    N/A
- */
-static void if_usb_free(struct if_usb_card *cardp)
-{
-       lbs_deb_enter(LBS_DEB_USB);
-
-       /* Unlink tx & rx urb */
-       usb_kill_urb(cardp->tx_urb);
-       usb_kill_urb(cardp->rx_urb);
-
-       usb_free_urb(cardp->tx_urb);
-       cardp->tx_urb = NULL;
-
-       usb_free_urb(cardp->rx_urb);
-       cardp->rx_urb = NULL;
-
-       kfree(cardp->ep_out_buf);
-       cardp->ep_out_buf = NULL;
-
-       lbs_deb_leave(LBS_DEB_USB);
-}
-
-static void if_usb_setup_firmware(struct lbs_private *priv)
-{
-       struct if_usb_card *cardp = priv->card;
-       struct cmd_ds_set_boot2_ver b2_cmd;
-       struct cmd_ds_802_11_fw_wake_method wake_method;
-
-       b2_cmd.hdr.size = cpu_to_le16(sizeof(b2_cmd));
-       b2_cmd.action = 0;
-       b2_cmd.version = cardp->boot2_version;
-
-       if (lbs_cmd_with_response(priv, CMD_SET_BOOT2_VER, &b2_cmd))
-               lbs_deb_usb("Setting boot2 version failed\n");
-
-       priv->wol_gpio = 2; /* Wake via GPIO2... */
-       priv->wol_gap = 20; /* ... after 20ms    */
-       lbs_host_sleep_cfg(priv, EHS_WAKE_ON_UNICAST_DATA,
-                       (struct wol_config *) NULL);
-
-       wake_method.hdr.size = cpu_to_le16(sizeof(wake_method));
-       wake_method.action = cpu_to_le16(CMD_ACT_GET);
-       if (lbs_cmd_with_response(priv, CMD_802_11_FW_WAKE_METHOD, &wake_method)) {
-               netdev_info(priv->dev, "Firmware does not seem to support PS mode\n");
-               priv->fwcapinfo &= ~FW_CAPINFO_PS;
-       } else {
-               if (le16_to_cpu(wake_method.method) == CMD_WAKE_METHOD_COMMAND_INT) {
-                       lbs_deb_usb("Firmware seems to support PS with wake-via-command\n");
-               } else {
-                       /* The versions which boot up this way don't seem to
-                          work even if we set it to the command interrupt */
-                       priv->fwcapinfo &= ~FW_CAPINFO_PS;
-                       netdev_info(priv->dev,
-                                   "Firmware doesn't wake via command interrupt; disabling PS mode\n");
-               }
-       }
-}
-
-static void if_usb_fw_timeo(unsigned long priv)
-{
-       struct if_usb_card *cardp = (void *)priv;
-
-       if (cardp->fwdnldover) {
-               lbs_deb_usb("Download complete, no event. Assuming success\n");
-       } else {
-               pr_err("Download timed out\n");
-               cardp->surprise_removed = 1;
-       }
-       wake_up(&cardp->fw_wq);
-}
-
-#ifdef CONFIG_OLPC
-static void if_usb_reset_olpc_card(struct lbs_private *priv)
-{
-       printk(KERN_CRIT "Resetting OLPC wireless via EC...\n");
-       olpc_ec_cmd(0x25, NULL, 0, NULL, 0);
-}
-#endif
-
-/**
- * if_usb_probe - sets the configuration values
- * @intf:      &usb_interface pointer
- * @id:        pointer to usb_device_id
- * returns:    0 on success, error code on failure
- */
-static int if_usb_probe(struct usb_interface *intf,
-                       const struct usb_device_id *id)
-{
-       struct usb_device *udev;
-       struct usb_host_interface *iface_desc;
-       struct usb_endpoint_descriptor *endpoint;
-       struct lbs_private *priv;
-       struct if_usb_card *cardp;
-       int r = -ENOMEM;
-       int i;
-
-       udev = interface_to_usbdev(intf);
-
-       cardp = kzalloc(sizeof(struct if_usb_card), GFP_KERNEL);
-       if (!cardp)
-               goto error;
-
-       setup_timer(&cardp->fw_timeout, if_usb_fw_timeo, (unsigned long)cardp);
-       init_waitqueue_head(&cardp->fw_wq);
-
-       cardp->udev = udev;
-       cardp->model = (uint32_t) id->driver_info;
-       iface_desc = intf->cur_altsetting;
-
-       lbs_deb_usbd(&udev->dev, "bcdUSB = 0x%X bDeviceClass = 0x%X"
-                    " bDeviceSubClass = 0x%X, bDeviceProtocol = 0x%X\n",
-                    le16_to_cpu(udev->descriptor.bcdUSB),
-                    udev->descriptor.bDeviceClass,
-                    udev->descriptor.bDeviceSubClass,
-                    udev->descriptor.bDeviceProtocol);
-
-       for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
-               endpoint = &iface_desc->endpoint[i].desc;
-               if (usb_endpoint_is_bulk_in(endpoint)) {
-                       cardp->ep_in_size = le16_to_cpu(endpoint->wMaxPacketSize);
-                       cardp->ep_in = usb_endpoint_num(endpoint);
-
-                       lbs_deb_usbd(&udev->dev, "in_endpoint = %d\n", cardp->ep_in);
-                       lbs_deb_usbd(&udev->dev, "Bulk in size is %d\n", cardp->ep_in_size);
-
-               } else if (usb_endpoint_is_bulk_out(endpoint)) {
-                       cardp->ep_out_size = le16_to_cpu(endpoint->wMaxPacketSize);
-                       cardp->ep_out = usb_endpoint_num(endpoint);
-
-                       lbs_deb_usbd(&udev->dev, "out_endpoint = %d\n", cardp->ep_out);
-                       lbs_deb_usbd(&udev->dev, "Bulk out size is %d\n", cardp->ep_out_size);
-               }
-       }
-       if (!cardp->ep_out_size || !cardp->ep_in_size) {
-               lbs_deb_usbd(&udev->dev, "Endpoints not found\n");
-               goto dealloc;
-       }
-       if (!(cardp->rx_urb = usb_alloc_urb(0, GFP_KERNEL))) {
-               lbs_deb_usbd(&udev->dev, "Rx URB allocation failed\n");
-               goto dealloc;
-       }
-       if (!(cardp->tx_urb = usb_alloc_urb(0, GFP_KERNEL))) {
-               lbs_deb_usbd(&udev->dev, "Tx URB allocation failed\n");
-               goto dealloc;
-       }
-       cardp->ep_out_buf = kmalloc(MRVDRV_ETH_TX_PACKET_BUFFER_SIZE, GFP_KERNEL);
-       if (!cardp->ep_out_buf) {
-               lbs_deb_usbd(&udev->dev, "Could not allocate buffer\n");
-               goto dealloc;
-       }
-
-       if (!(priv = lbs_add_card(cardp, &intf->dev)))
-               goto err_add_card;
-
-       cardp->priv = priv;
-
-       priv->hw_host_to_card = if_usb_host_to_card;
-       priv->enter_deep_sleep = NULL;
-       priv->exit_deep_sleep = NULL;
-       priv->reset_deep_sleep_wakeup = NULL;
-#ifdef CONFIG_OLPC
-       if (machine_is_olpc())
-               priv->reset_card = if_usb_reset_olpc_card;
-#endif
-
-       cardp->boot2_version = udev->descriptor.bcdDevice;
-
-       usb_get_dev(udev);
-       usb_set_intfdata(intf, cardp);
-
-       r = lbs_get_firmware_async(priv, &udev->dev, cardp->model,
-                                  fw_table, if_usb_prog_firmware);
-       if (r)
-               goto err_get_fw;
-
-       return 0;
-
-err_get_fw:
-       lbs_remove_card(priv);
-err_add_card:
-       if_usb_reset_device(cardp);
-dealloc:
-       if_usb_free(cardp);
-
-error:
-       return r;
-}
-
-/**
- * if_usb_disconnect - free resource and cleanup
- * @intf:      USB interface structure
- * returns:    N/A
- */
-static void if_usb_disconnect(struct usb_interface *intf)
-{
-       struct if_usb_card *cardp = usb_get_intfdata(intf);
-       struct lbs_private *priv = cardp->priv;
-
-       lbs_deb_enter(LBS_DEB_MAIN);
-
-       cardp->surprise_removed = 1;
-
-       if (priv) {
-               lbs_stop_card(priv);
-               lbs_remove_card(priv);
-       }
-
-       /* Unlink and free urb */
-       if_usb_free(cardp);
-
-       usb_set_intfdata(intf, NULL);
-       usb_put_dev(interface_to_usbdev(intf));
-
-       lbs_deb_leave(LBS_DEB_MAIN);
-}
-
-/**
- * if_usb_send_fw_pkt - download FW
- * @cardp:     pointer to &struct if_usb_card
- * returns:    0
- */
-static int if_usb_send_fw_pkt(struct if_usb_card *cardp)
-{
-       struct fwdata *fwdata = cardp->ep_out_buf;
-       const uint8_t *firmware = cardp->fw->data;
-
-       /* If we got a CRC failure on the last block, back
-          up and retry it */
-       if (!cardp->CRC_OK) {
-               cardp->totalbytes = cardp->fwlastblksent;
-               cardp->fwseqnum--;
-       }
-
-       lbs_deb_usb2(&cardp->udev->dev, "totalbytes = %d\n",
-                    cardp->totalbytes);
-
-       /* struct fwdata (which we sent to the card) has an
-          extra __le32 field in between the header and the data,
-          which is not in the struct fwheader in the actual
-          firmware binary. Insert the seqnum in the middle... */
-       memcpy(&fwdata->hdr, &firmware[cardp->totalbytes],
-              sizeof(struct fwheader));
-
-       cardp->fwlastblksent = cardp->totalbytes;
-       cardp->totalbytes += sizeof(struct fwheader);
-
-       memcpy(fwdata->data, &firmware[cardp->totalbytes],
-              le32_to_cpu(fwdata->hdr.datalength));
-
-       lbs_deb_usb2(&cardp->udev->dev, "Data length = %d\n",
-                    le32_to_cpu(fwdata->hdr.datalength));
-
-       fwdata->seqnum = cpu_to_le32(++cardp->fwseqnum);
-       cardp->totalbytes += le32_to_cpu(fwdata->hdr.datalength);
-
-       usb_tx_block(cardp, cardp->ep_out_buf, sizeof(struct fwdata) +
-                    le32_to_cpu(fwdata->hdr.datalength));
-
-       if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_DATA_TO_RECV)) {
-               lbs_deb_usb2(&cardp->udev->dev, "There are data to follow\n");
-               lbs_deb_usb2(&cardp->udev->dev, "seqnum = %d totalbytes = %d\n",
-                            cardp->fwseqnum, cardp->totalbytes);
-       } else if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK)) {
-               lbs_deb_usb2(&cardp->udev->dev, "Host has finished FW downloading\n");
-               lbs_deb_usb2(&cardp->udev->dev, "Donwloading FW JUMP BLOCK\n");
-
-               cardp->fwfinalblk = 1;
-       }
-
-       lbs_deb_usb2(&cardp->udev->dev, "Firmware download done; size %d\n",
-                    cardp->totalbytes);
-
-       return 0;
-}
-
-static int if_usb_reset_device(struct if_usb_card *cardp)
-{
-       struct cmd_header *cmd = cardp->ep_out_buf + 4;
-       int ret;
-
-       lbs_deb_enter(LBS_DEB_USB);
-
-       *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST);
-
-       cmd->command = cpu_to_le16(CMD_802_11_RESET);
-       cmd->size = cpu_to_le16(sizeof(cmd));
-       cmd->result = cpu_to_le16(0);
-       cmd->seqnum = cpu_to_le16(0x5a5a);
-       usb_tx_block(cardp, cardp->ep_out_buf, 4 + sizeof(struct cmd_header));
-
-       msleep(100);
-       ret = usb_reset_device(cardp->udev);
-       msleep(100);
-
-#ifdef CONFIG_OLPC
-       if (ret && machine_is_olpc())
-               if_usb_reset_olpc_card(NULL);
-#endif
-
-       lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret);
-
-       return ret;
-}
-
-/**
- *  usb_tx_block - transfer the data to the device
- *  @cardp:    pointer to &struct if_usb_card
- *  @payload:  pointer to payload data
- *  @nb:       data length
- *  returns:   0 for success or negative error code
- */
-static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, uint16_t nb)
-{
-       int ret;
-
-       /* check if device is removed */
-       if (cardp->surprise_removed) {
-               lbs_deb_usbd(&cardp->udev->dev, "Device removed\n");
-               ret = -ENODEV;
-               goto tx_ret;
-       }
-
-       usb_fill_bulk_urb(cardp->tx_urb, cardp->udev,
-                         usb_sndbulkpipe(cardp->udev,
-                                         cardp->ep_out),
-                         payload, nb, if_usb_write_bulk_callback, cardp);
-
-       cardp->tx_urb->transfer_flags |= URB_ZERO_PACKET;
-
-       if ((ret = usb_submit_urb(cardp->tx_urb, GFP_ATOMIC))) {
-               lbs_deb_usbd(&cardp->udev->dev, "usb_submit_urb failed: %d\n", ret);
-       } else {
-               lbs_deb_usb2(&cardp->udev->dev, "usb_submit_urb success\n");
-               ret = 0;
-       }
-
-tx_ret:
-       return ret;
-}
-
-static int __if_usb_submit_rx_urb(struct if_usb_card *cardp,
-                                 void (*callbackfn)(struct urb *urb))
-{
-       struct sk_buff *skb;
-       int ret = -1;
-
-       if (!(skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE))) {
-               pr_err("No free skb\n");
-               goto rx_ret;
-       }
-
-       cardp->rx_skb = skb;
-
-       /* Fill the receive configuration URB and initialise the Rx call back */
-       usb_fill_bulk_urb(cardp->rx_urb, cardp->udev,
-                         usb_rcvbulkpipe(cardp->udev, cardp->ep_in),
-                         skb->data + IPFIELD_ALIGN_OFFSET,
-                         MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn,
-                         cardp);
-
-       cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET;
-
-       lbs_deb_usb2(&cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb);
-       if ((ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC))) {
-               lbs_deb_usbd(&cardp->udev->dev, "Submit Rx URB failed: %d\n", ret);
-               kfree_skb(skb);
-               cardp->rx_skb = NULL;
-               ret = -1;
-       } else {
-               lbs_deb_usb2(&cardp->udev->dev, "Submit Rx URB success\n");
-               ret = 0;
-       }
-
-rx_ret:
-       return ret;
-}
-
-static int if_usb_submit_rx_urb_fwload(struct if_usb_card *cardp)
-{
-       return __if_usb_submit_rx_urb(cardp, &if_usb_receive_fwload);
-}
-
-static int if_usb_submit_rx_urb(struct if_usb_card *cardp)
-{
-       return __if_usb_submit_rx_urb(cardp, &if_usb_receive);
-}
-
-static void if_usb_receive_fwload(struct urb *urb)
-{
-       struct if_usb_card *cardp = urb->context;
-       struct sk_buff *skb = cardp->rx_skb;
-       struct fwsyncheader *syncfwheader;
-       struct bootcmdresp bootcmdresp;
-
-       if (urb->status) {
-               lbs_deb_usbd(&cardp->udev->dev,
-                            "URB status is failed during fw load\n");
-               kfree_skb(skb);
-               return;
-       }
-
-       if (cardp->fwdnldover) {
-               __le32 *tmp = (__le32 *)(skb->data + IPFIELD_ALIGN_OFFSET);
-
-               if (tmp[0] == cpu_to_le32(CMD_TYPE_INDICATION) &&
-                   tmp[1] == cpu_to_le32(MACREG_INT_CODE_FIRMWARE_READY)) {
-                       pr_info("Firmware ready event received\n");
-                       wake_up(&cardp->fw_wq);
-               } else {
-                       lbs_deb_usb("Waiting for confirmation; got %x %x\n",
-                                   le32_to_cpu(tmp[0]), le32_to_cpu(tmp[1]));
-                       if_usb_submit_rx_urb_fwload(cardp);
-               }
-               kfree_skb(skb);
-               return;
-       }
-       if (cardp->bootcmdresp <= 0) {
-               memcpy (&bootcmdresp, skb->data + IPFIELD_ALIGN_OFFSET,
-                       sizeof(bootcmdresp));
-
-               if (le16_to_cpu(cardp->udev->descriptor.bcdDevice) < 0x3106) {
-                       kfree_skb(skb);
-                       if_usb_submit_rx_urb_fwload(cardp);
-                       cardp->bootcmdresp = BOOT_CMD_RESP_OK;
-                       lbs_deb_usbd(&cardp->udev->dev,
-                                    "Received valid boot command response\n");
-                       return;
-               }
-               if (bootcmdresp.magic != cpu_to_le32(BOOT_CMD_MAGIC_NUMBER)) {
-                       if (bootcmdresp.magic == cpu_to_le32(CMD_TYPE_REQUEST) ||
-                           bootcmdresp.magic == cpu_to_le32(CMD_TYPE_DATA) ||
-                           bootcmdresp.magic == cpu_to_le32(CMD_TYPE_INDICATION)) {
-                               if (!cardp->bootcmdresp)
-                                       pr_info("Firmware already seems alive; resetting\n");
-                               cardp->bootcmdresp = -1;
-                       } else {
-                               pr_info("boot cmd response wrong magic number (0x%x)\n",
-                                           le32_to_cpu(bootcmdresp.magic));
-                       }
-               } else if ((bootcmdresp.cmd != BOOT_CMD_FW_BY_USB) &&
-                          (bootcmdresp.cmd != BOOT_CMD_UPDATE_FW) &&
-                          (bootcmdresp.cmd != BOOT_CMD_UPDATE_BOOT2)) {
-                       pr_info("boot cmd response cmd_tag error (%d)\n",
-                               bootcmdresp.cmd);
-               } else if (bootcmdresp.result != BOOT_CMD_RESP_OK) {
-                       pr_info("boot cmd response result error (%d)\n",
-                               bootcmdresp.result);
-               } else {
-                       cardp->bootcmdresp = 1;
-                       lbs_deb_usbd(&cardp->udev->dev,
-                                    "Received valid boot command response\n");
-               }
-               kfree_skb(skb);
-               if_usb_submit_rx_urb_fwload(cardp);
-               return;
-       }
-
-       syncfwheader = kmemdup(skb->data + IPFIELD_ALIGN_OFFSET,
-                              sizeof(struct fwsyncheader), GFP_ATOMIC);
-       if (!syncfwheader) {
-               lbs_deb_usbd(&cardp->udev->dev, "Failure to allocate syncfwheader\n");
-               kfree_skb(skb);
-               return;
-       }
-
-       if (!syncfwheader->cmd) {
-               lbs_deb_usb2(&cardp->udev->dev, "FW received Blk with correct CRC\n");
-               lbs_deb_usb2(&cardp->udev->dev, "FW received Blk seqnum = %d\n",
-                            le32_to_cpu(syncfwheader->seqnum));
-               cardp->CRC_OK = 1;
-       } else {
-               lbs_deb_usbd(&cardp->udev->dev, "FW received Blk with CRC error\n");
-               cardp->CRC_OK = 0;
-       }
-
-       kfree_skb(skb);
-
-       /* Give device 5s to either write firmware to its RAM or eeprom */
-       mod_timer(&cardp->fw_timeout, jiffies + (HZ*5));
-
-       if (cardp->fwfinalblk) {
-               cardp->fwdnldover = 1;
-               goto exit;
-       }
-
-       if_usb_send_fw_pkt(cardp);
-
- exit:
-       if_usb_submit_rx_urb_fwload(cardp);
-
-       kfree(syncfwheader);
-}
-
-#define MRVDRV_MIN_PKT_LEN     30
-
-static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb,
-                                      struct if_usb_card *cardp,
-                                      struct lbs_private *priv)
-{
-       if (recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + MESSAGE_HEADER_LEN
-           || recvlength < MRVDRV_MIN_PKT_LEN) {
-               lbs_deb_usbd(&cardp->udev->dev, "Packet length is Invalid\n");
-               kfree_skb(skb);
-               return;
-       }
-
-       skb_reserve(skb, IPFIELD_ALIGN_OFFSET);
-       skb_put(skb, recvlength);
-       skb_pull(skb, MESSAGE_HEADER_LEN);
-
-       lbs_process_rxed_packet(priv, skb);
-}
-
-static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff,
-                                     struct sk_buff *skb,
-                                     struct if_usb_card *cardp,
-                                     struct lbs_private *priv)
-{
-       u8 i;
-
-       if (recvlength > LBS_CMD_BUFFER_SIZE) {
-               lbs_deb_usbd(&cardp->udev->dev,
-                            "The receive buffer is too large\n");
-               kfree_skb(skb);
-               return;
-       }
-
-       BUG_ON(!in_interrupt());
-
-       spin_lock(&priv->driver_lock);
-
-       i = (priv->resp_idx == 0) ? 1 : 0;
-       BUG_ON(priv->resp_len[i]);
-       priv->resp_len[i] = (recvlength - MESSAGE_HEADER_LEN);
-       memcpy(priv->resp_buf[i], recvbuff + MESSAGE_HEADER_LEN,
-               priv->resp_len[i]);
-       kfree_skb(skb);
-       lbs_notify_command_response(priv, i);
-
-       spin_unlock(&priv->driver_lock);
-
-       lbs_deb_usbd(&cardp->udev->dev,
-                   "Wake up main thread to handle cmd response\n");
-}
-
-/**
- *  if_usb_receive - read the packet into the upload buffer,
- *  wake up the main thread and initialise the Rx callack
- *
- *  @urb:      pointer to &struct urb
- *  returns:   N/A
- */
-static void if_usb_receive(struct urb *urb)
-{
-       struct if_usb_card *cardp = urb->context;
-       struct sk_buff *skb = cardp->rx_skb;
-       struct lbs_private *priv = cardp->priv;
-       int recvlength = urb->actual_length;
-       uint8_t *recvbuff = NULL;
-       uint32_t recvtype = 0;
-       __le32 *pkt = (__le32 *)(skb->data + IPFIELD_ALIGN_OFFSET);
-       uint32_t event;
-
-       lbs_deb_enter(LBS_DEB_USB);
-
-       if (recvlength) {
-               if (urb->status) {
-                       lbs_deb_usbd(&cardp->udev->dev, "RX URB failed: %d\n",
-                                    urb->status);
-                       kfree_skb(skb);
-                       goto setup_for_next;
-               }
-
-               recvbuff = skb->data + IPFIELD_ALIGN_OFFSET;
-               recvtype = le32_to_cpu(pkt[0]);
-               lbs_deb_usbd(&cardp->udev->dev,
-                           "Recv length = 0x%x, Recv type = 0x%X\n",
-                           recvlength, recvtype);
-       } else if (urb->status) {
-               kfree_skb(skb);
-               goto rx_exit;
-       }
-
-       switch (recvtype) {
-       case CMD_TYPE_DATA:
-               process_cmdtypedata(recvlength, skb, cardp, priv);
-               break;
-
-       case CMD_TYPE_REQUEST:
-               process_cmdrequest(recvlength, recvbuff, skb, cardp, priv);
-               break;
-
-       case CMD_TYPE_INDICATION:
-               /* Event handling */
-               event = le32_to_cpu(pkt[1]);
-               lbs_deb_usbd(&cardp->udev->dev, "**EVENT** 0x%X\n", event);
-               kfree_skb(skb);
-
-               /* Icky undocumented magic special case */
-               if (event & 0xffff0000) {
-                       u32 trycount = (event & 0xffff0000) >> 16;
-
-                       lbs_send_tx_feedback(priv, trycount);
-               } else
-                       lbs_queue_event(priv, event & 0xFF);
-               break;
-
-       default:
-               lbs_deb_usbd(&cardp->udev->dev, "Unknown command type 0x%X\n",
-                            recvtype);
-               kfree_skb(skb);
-               break;
-       }
-
-setup_for_next:
-       if_usb_submit_rx_urb(cardp);
-rx_exit:
-       lbs_deb_leave(LBS_DEB_USB);
-}
-
-/**
- *  if_usb_host_to_card - downloads data to FW
- *  @priv:     pointer to &struct lbs_private structure
- *  @type:     type of data
- *  @payload:  pointer to data buffer
- *  @nb:       number of bytes
- *  returns:   0 for success or negative error code
- */
-static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
-                              uint8_t *payload, uint16_t nb)
-{
-       struct if_usb_card *cardp = priv->card;
-
-       lbs_deb_usbd(&cardp->udev->dev,"*** type = %u\n", type);
-       lbs_deb_usbd(&cardp->udev->dev,"size after = %d\n", nb);
-
-       if (type == MVMS_CMD) {
-               *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST);
-               priv->dnld_sent = DNLD_CMD_SENT;
-       } else {
-               *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_DATA);
-               priv->dnld_sent = DNLD_DATA_SENT;
-       }
-
-       memcpy((cardp->ep_out_buf + MESSAGE_HEADER_LEN), payload, nb);
-
-       return usb_tx_block(cardp, cardp->ep_out_buf, nb + MESSAGE_HEADER_LEN);
-}
-
-/**
- *  if_usb_issue_boot_command - issues Boot command to the Boot2 code
- *  @cardp:    pointer to &if_usb_card
- *  @ivalue:   1:Boot from FW by USB-Download
- *             2:Boot from FW in EEPROM
- *  returns:   0 for success or negative error code
- */
-static int if_usb_issue_boot_command(struct if_usb_card *cardp, int ivalue)
-{
-       struct bootcmd *bootcmd = cardp->ep_out_buf;
-
-       /* Prepare command */
-       bootcmd->magic = cpu_to_le32(BOOT_CMD_MAGIC_NUMBER);
-       bootcmd->cmd = ivalue;
-       memset(bootcmd->pad, 0, sizeof(bootcmd->pad));
-
-       /* Issue command */
-       usb_tx_block(cardp, cardp->ep_out_buf, sizeof(*bootcmd));
-
-       return 0;
-}
-
-
-/**
- *  check_fwfile_format - check the validity of Boot2/FW image
- *
- *  @data:     pointer to image
- *  @totlen:   image length
- *  returns:     0 (good) or 1 (failure)
- */
-static int check_fwfile_format(const uint8_t *data, uint32_t totlen)
-{
-       uint32_t bincmd, exit;
-       uint32_t blksize, offset, len;
-       int ret;
-
-       ret = 1;
-       exit = len = 0;
-
-       do {
-               struct fwheader *fwh = (void *)data;
-
-               bincmd = le32_to_cpu(fwh->dnldcmd);
-               blksize = le32_to_cpu(fwh->datalength);
-               switch (bincmd) {
-               case FW_HAS_DATA_TO_RECV:
-                       offset = sizeof(struct fwheader) + blksize;
-                       data += offset;
-                       len += offset;
-                       if (len >= totlen)
-                               exit = 1;
-                       break;
-               case FW_HAS_LAST_BLOCK:
-                       exit = 1;
-                       ret = 0;
-                       break;
-               default:
-                       exit = 1;
-                       break;
-               }
-       } while (!exit);
-
-       if (ret)
-               pr_err("firmware file format check FAIL\n");
-       else
-               lbs_deb_fw("firmware file format check PASS\n");
-
-       return ret;
-}
-
-static void if_usb_prog_firmware(struct lbs_private *priv, int ret,
-                                const struct firmware *fw,
-                                const struct firmware *unused)
-{
-       struct if_usb_card *cardp = priv->card;
-       int i = 0;
-       static int reset_count = 10;
-
-       lbs_deb_enter(LBS_DEB_USB);
-
-       if (ret) {
-               pr_err("failed to find firmware (%d)\n", ret);
-               goto done;
-       }
-
-       cardp->fw = fw;
-       if (check_fwfile_format(cardp->fw->data, cardp->fw->size)) {
-               ret = -EINVAL;
-               goto done;
-       }
-
-       /* Cancel any pending usb business */
-       usb_kill_urb(cardp->rx_urb);
-       usb_kill_urb(cardp->tx_urb);
-
-       cardp->fwlastblksent = 0;
-       cardp->fwdnldover = 0;
-       cardp->totalbytes = 0;
-       cardp->fwfinalblk = 0;
-       cardp->bootcmdresp = 0;
-
-restart:
-       if (if_usb_submit_rx_urb_fwload(cardp) < 0) {
-               lbs_deb_usbd(&cardp->udev->dev, "URB submission is failed\n");
-               ret = -EIO;
-               goto done;
-       }
-
-       cardp->bootcmdresp = 0;
-       do {
-               int j = 0;
-               i++;
-               if_usb_issue_boot_command(cardp, BOOT_CMD_FW_BY_USB);
-               /* wait for command response */
-               do {
-                       j++;
-                       msleep_interruptible(100);
-               } while (cardp->bootcmdresp == 0 && j < 10);
-       } while (cardp->bootcmdresp == 0 && i < 5);
-
-       if (cardp->bootcmdresp == BOOT_CMD_RESP_NOT_SUPPORTED) {
-               /* Return to normal operation */
-               ret = -EOPNOTSUPP;
-               usb_kill_urb(cardp->rx_urb);
-               usb_kill_urb(cardp->tx_urb);
-               if (if_usb_submit_rx_urb(cardp) < 0)
-                       ret = -EIO;
-               goto done;
-       } else if (cardp->bootcmdresp <= 0) {
-               if (--reset_count >= 0) {
-                       if_usb_reset_device(cardp);
-                       goto restart;
-               }
-               ret = -EIO;
-               goto done;
-       }
-
-       i = 0;
-
-       cardp->totalbytes = 0;
-       cardp->fwlastblksent = 0;
-       cardp->CRC_OK = 1;
-       cardp->fwdnldover = 0;
-       cardp->fwseqnum = -1;
-       cardp->totalbytes = 0;
-       cardp->fwfinalblk = 0;
-
-       /* Send the first firmware packet... */
-       if_usb_send_fw_pkt(cardp);
-
-       /* ... and wait for the process to complete */
-       wait_event_interruptible(cardp->fw_wq, cardp->surprise_removed || cardp->fwdnldover);
-
-       del_timer_sync(&cardp->fw_timeout);
-       usb_kill_urb(cardp->rx_urb);
-
-       if (!cardp->fwdnldover) {
-               pr_info("failed to load fw, resetting device!\n");
-               if (--reset_count >= 0) {
-                       if_usb_reset_device(cardp);
-                       goto restart;
-               }
-
-               pr_info("FW download failure, time = %d ms\n", i * 100);
-               ret = -EIO;
-               goto done;
-       }
-
-       cardp->priv->fw_ready = 1;
-       if_usb_submit_rx_urb(cardp);
-
-       if (lbs_start_card(priv))
-               goto done;
-
-       if_usb_setup_firmware(priv);
-
-       /*
-        * EHS_REMOVE_WAKEUP is not supported on all versions of the firmware.
-        */
-       priv->wol_criteria = EHS_REMOVE_WAKEUP;
-       if (lbs_host_sleep_cfg(priv, priv->wol_criteria, NULL))
-               priv->ehs_remove_supported = false;
-
- done:
-       cardp->fw = NULL;
-       lbs_deb_leave(LBS_DEB_USB);
-}
-
-
-#ifdef CONFIG_PM
-static int if_usb_suspend(struct usb_interface *intf, pm_message_t message)
-{
-       struct if_usb_card *cardp = usb_get_intfdata(intf);
-       struct lbs_private *priv = cardp->priv;
-       int ret;
-
-       lbs_deb_enter(LBS_DEB_USB);
-
-       if (priv->psstate != PS_STATE_FULL_POWER) {
-               ret = -1;
-               goto out;
-       }
-
-#ifdef CONFIG_OLPC
-       if (machine_is_olpc()) {
-               if (priv->wol_criteria == EHS_REMOVE_WAKEUP)
-                       olpc_ec_wakeup_clear(EC_SCI_SRC_WLAN);
-               else
-                       olpc_ec_wakeup_set(EC_SCI_SRC_WLAN);
-       }
-#endif
-
-       ret = lbs_suspend(priv);
-       if (ret)
-               goto out;
-
-       /* Unlink tx & rx urb */
-       usb_kill_urb(cardp->tx_urb);
-       usb_kill_urb(cardp->rx_urb);
-
- out:
-       lbs_deb_leave(LBS_DEB_USB);
-       return ret;
-}
-
-static int if_usb_resume(struct usb_interface *intf)
-{
-       struct if_usb_card *cardp = usb_get_intfdata(intf);
-       struct lbs_private *priv = cardp->priv;
-
-       lbs_deb_enter(LBS_DEB_USB);
-
-       if_usb_submit_rx_urb(cardp);
-
-       lbs_resume(priv);
-
-       lbs_deb_leave(LBS_DEB_USB);
-       return 0;
-}
-#else
-#define if_usb_suspend NULL
-#define if_usb_resume NULL
-#endif
-
-static struct usb_driver if_usb_driver = {
-       .name = DRV_NAME,
-       .probe = if_usb_probe,
-       .disconnect = if_usb_disconnect,
-       .id_table = if_usb_table,
-       .suspend = if_usb_suspend,
-       .resume = if_usb_resume,
-       .reset_resume = if_usb_resume,
-       .disable_hub_initiated_lpm = 1,
-};
-
-module_usb_driver(if_usb_driver);
-
-MODULE_DESCRIPTION("8388 USB WLAN Driver");
-MODULE_AUTHOR("Marvell International Ltd. and Red Hat, Inc.");
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/libertas/if_usb.h b/drivers/net/wireless/libertas/if_usb.h
deleted file mode 100644 (file)
index 6e42eac..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-#ifndef _LBS_IF_USB_H
-#define _LBS_IF_USB_H
-
-#include <linux/wait.h>
-#include <linux/timer.h>
-
-struct lbs_private;
-
-/*
- * This file contains definition for USB interface.
- */
-#define CMD_TYPE_REQUEST               0xF00DFACE
-#define CMD_TYPE_DATA                  0xBEADC0DE
-#define CMD_TYPE_INDICATION            0xBEEFFACE
-
-#define IPFIELD_ALIGN_OFFSET           2
-
-#define BOOT_CMD_FW_BY_USB             0x01
-#define BOOT_CMD_FW_IN_EEPROM          0x02
-#define BOOT_CMD_UPDATE_BOOT2          0x03
-#define BOOT_CMD_UPDATE_FW             0x04
-#define BOOT_CMD_MAGIC_NUMBER          0x4C56524D   /* LVRM */
-
-struct bootcmd
-{
-       __le32  magic;
-       uint8_t cmd;
-       uint8_t pad[11];
-};
-
-#define BOOT_CMD_RESP_OK               0x0001
-#define BOOT_CMD_RESP_FAIL             0x0000
-#define BOOT_CMD_RESP_NOT_SUPPORTED    0x0002
-
-struct bootcmdresp
-{
-       __le32  magic;
-       uint8_t cmd;
-       uint8_t result;
-       uint8_t pad[2];
-};
-
-/* USB card description structure*/
-struct if_usb_card {
-       struct usb_device *udev;
-       uint32_t model;  /* MODEL_* */
-       struct urb *rx_urb, *tx_urb;
-       struct lbs_private *priv;
-
-       struct sk_buff *rx_skb;
-
-       uint8_t ep_in;
-       uint8_t ep_out;
-
-       /* bootcmdresp == 0 means command is pending
-        * bootcmdresp < 0 means error
-        * bootcmdresp > 0 is a BOOT_CMD_RESP_* from firmware
-        */
-       int8_t bootcmdresp;
-
-       int ep_in_size;
-
-       void *ep_out_buf;
-       int ep_out_size;
-
-       const struct firmware *fw;
-       struct timer_list fw_timeout;
-       wait_queue_head_t fw_wq;
-       uint32_t fwseqnum;
-       uint32_t totalbytes;
-       uint32_t fwlastblksent;
-       uint8_t CRC_OK;
-       uint8_t fwdnldover;
-       uint8_t fwfinalblk;
-       uint8_t surprise_removed;
-
-       __le16 boot2_version;
-};
-
-/* fwheader */
-struct fwheader {
-       __le32 dnldcmd;
-       __le32 baseaddr;
-       __le32 datalength;
-       __le32 CRC;
-};
-
-#define FW_MAX_DATA_BLK_SIZE   600
-/* FWData */
-struct fwdata {
-       struct fwheader hdr;
-       __le32 seqnum;
-       uint8_t data[0];
-};
-
-/* fwsyncheader */
-struct fwsyncheader {
-       __le32 cmd;
-       __le32 seqnum;
-};
-
-#define FW_HAS_DATA_TO_RECV            0x00000001
-#define FW_HAS_LAST_BLOCK              0x00000004
-
-
-#endif
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
deleted file mode 100644 (file)
index 8079560..0000000
+++ /dev/null
@@ -1,1225 +0,0 @@
-/*
- * This file contains the major functions in WLAN
- * driver. It includes init, exit, open, close and main
- * thread etc..
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/etherdevice.h>
-#include <linux/hardirq.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/kthread.h>
-#include <linux/kfifo.h>
-#include <linux/slab.h>
-#include <net/cfg80211.h>
-
-#include "host.h"
-#include "decl.h"
-#include "dev.h"
-#include "cfg.h"
-#include "debugfs.h"
-#include "cmd.h"
-#include "mesh.h"
-
-#define DRIVER_RELEASE_VERSION "323.p0"
-const char lbs_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION
-#ifdef  DEBUG
-    "-dbg"
-#endif
-    "";
-
-
-/* Module parameters */
-unsigned int lbs_debug;
-EXPORT_SYMBOL_GPL(lbs_debug);
-module_param_named(libertas_debug, lbs_debug, int, 0644);
-
-unsigned int lbs_disablemesh;
-EXPORT_SYMBOL_GPL(lbs_disablemesh);
-module_param_named(libertas_disablemesh, lbs_disablemesh, int, 0644);
-
-
-/*
- * This global structure is used to send the confirm_sleep command as
- * fast as possible down to the firmware.
- */
-struct cmd_confirm_sleep confirm_sleep;
-
-
-/*
- * the table to keep region code
- */
-u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE] =
-    { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 };
-
-/*
- * FW rate table.  FW refers to rates by their index in this table, not by the
- * rate value itself.  Values of 0x00 are
- * reserved positions.
- */
-static u8 fw_data_rates[MAX_RATES] =
-    { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12,
-      0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00
-};
-
-/**
- *  lbs_fw_index_to_data_rate - use index to get the data rate
- *
- *  @idx:      The index of data rate
- *  returns:   data rate or 0
- */
-u32 lbs_fw_index_to_data_rate(u8 idx)
-{
-       if (idx >= sizeof(fw_data_rates))
-               idx = 0;
-       return fw_data_rates[idx];
-}
-
-/**
- *  lbs_data_rate_to_fw_index - use rate to get the index
- *
- *  @rate:     data rate
- *  returns:   index or 0
- */
-u8 lbs_data_rate_to_fw_index(u32 rate)
-{
-       u8 i;
-
-       if (!rate)
-               return 0;
-
-       for (i = 0; i < sizeof(fw_data_rates); i++) {
-               if (rate == fw_data_rates[i])
-                       return i;
-       }
-       return 0;
-}
-
-int lbs_set_iface_type(struct lbs_private *priv, enum nl80211_iftype type)
-{
-       int ret = 0;
-
-       switch (type) {
-       case NL80211_IFTYPE_MONITOR:
-               ret = lbs_set_monitor_mode(priv, 1);
-               break;
-       case NL80211_IFTYPE_STATION:
-               if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR)
-                       ret = lbs_set_monitor_mode(priv, 0);
-               if (!ret)
-                       ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, 1);
-               break;
-       case NL80211_IFTYPE_ADHOC:
-               if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR)
-                       ret = lbs_set_monitor_mode(priv, 0);
-               if (!ret)
-                       ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, 2);
-               break;
-       default:
-               ret = -ENOTSUPP;
-       }
-       return ret;
-}
-
-int lbs_start_iface(struct lbs_private *priv)
-{
-       struct cmd_ds_802_11_mac_address cmd;
-       int ret;
-
-       if (priv->power_restore) {
-               ret = priv->power_restore(priv);
-               if (ret)
-                       return ret;
-       }
-
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-       cmd.action = cpu_to_le16(CMD_ACT_SET);
-       memcpy(cmd.macadd, priv->current_addr, ETH_ALEN);
-
-       ret = lbs_cmd_with_response(priv, CMD_802_11_MAC_ADDRESS, &cmd);
-       if (ret) {
-               lbs_deb_net("set MAC address failed\n");
-               goto err;
-       }
-
-       ret = lbs_set_iface_type(priv, priv->wdev->iftype);
-       if (ret) {
-               lbs_deb_net("set iface type failed\n");
-               goto err;
-       }
-
-       ret = lbs_set_11d_domain_info(priv);
-       if (ret) {
-               lbs_deb_net("set 11d domain info failed\n");
-               goto err;
-       }
-
-       lbs_update_channel(priv);
-
-       priv->iface_running = true;
-       return 0;
-
-err:
-       if (priv->power_save)
-               priv->power_save(priv);
-       return ret;
-}
-
-/**
- *  lbs_dev_open - open the ethX interface
- *
- *  @dev:      A pointer to &net_device structure
- *  returns:   0 or -EBUSY if monitor mode active
- */
-static int lbs_dev_open(struct net_device *dev)
-{
-       struct lbs_private *priv = dev->ml_priv;
-       int ret = 0;
-
-       lbs_deb_enter(LBS_DEB_NET);
-       if (!priv->iface_running) {
-               ret = lbs_start_iface(priv);
-               if (ret)
-                       goto out;
-       }
-
-       spin_lock_irq(&priv->driver_lock);
-
-       netif_carrier_off(dev);
-
-       if (!priv->tx_pending_len)
-               netif_wake_queue(dev);
-
-       spin_unlock_irq(&priv->driver_lock);
-
-out:
-       lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
-       return ret;
-}
-
-static bool lbs_command_queue_empty(struct lbs_private *priv)
-{
-       unsigned long flags;
-       bool ret;
-       spin_lock_irqsave(&priv->driver_lock, flags);
-       ret = priv->cur_cmd == NULL && list_empty(&priv->cmdpendingq);
-       spin_unlock_irqrestore(&priv->driver_lock, flags);
-       return ret;
-}
-
-int lbs_stop_iface(struct lbs_private *priv)
-{
-       unsigned long flags;
-       int ret = 0;
-
-       lbs_deb_enter(LBS_DEB_MAIN);
-
-       spin_lock_irqsave(&priv->driver_lock, flags);
-       priv->iface_running = false;
-       kfree_skb(priv->currenttxskb);
-       priv->currenttxskb = NULL;
-       priv->tx_pending_len = 0;
-       spin_unlock_irqrestore(&priv->driver_lock, flags);
-
-       cancel_work_sync(&priv->mcast_work);
-       del_timer_sync(&priv->tx_lockup_timer);
-
-       /* Disable command processing, and wait for all commands to complete */
-       lbs_deb_main("waiting for commands to complete\n");
-       wait_event(priv->waitq, lbs_command_queue_empty(priv));
-       lbs_deb_main("all commands completed\n");
-
-       if (priv->power_save)
-               ret = priv->power_save(priv);
-
-       lbs_deb_leave(LBS_DEB_MAIN);
-       return ret;
-}
-
-/**
- *  lbs_eth_stop - close the ethX interface
- *
- *  @dev:      A pointer to &net_device structure
- *  returns:   0
- */
-static int lbs_eth_stop(struct net_device *dev)
-{
-       struct lbs_private *priv = dev->ml_priv;
-
-       lbs_deb_enter(LBS_DEB_NET);
-
-       if (priv->connect_status == LBS_CONNECTED)
-               lbs_disconnect(priv, WLAN_REASON_DEAUTH_LEAVING);
-
-       spin_lock_irq(&priv->driver_lock);
-       netif_stop_queue(dev);
-       spin_unlock_irq(&priv->driver_lock);
-
-       lbs_update_mcast(priv);
-       cancel_delayed_work_sync(&priv->scan_work);
-       if (priv->scan_req)
-               lbs_scan_done(priv);
-
-       netif_carrier_off(priv->dev);
-
-       if (!lbs_iface_active(priv))
-               lbs_stop_iface(priv);
-
-       lbs_deb_leave(LBS_DEB_NET);
-       return 0;
-}
-
-void lbs_host_to_card_done(struct lbs_private *priv)
-{
-       unsigned long flags;
-
-       lbs_deb_enter(LBS_DEB_THREAD);
-
-       spin_lock_irqsave(&priv->driver_lock, flags);
-       del_timer(&priv->tx_lockup_timer);
-
-       priv->dnld_sent = DNLD_RES_RECEIVED;
-
-       /* Wake main thread if commands are pending */
-       if (!priv->cur_cmd || priv->tx_pending_len > 0) {
-               if (!priv->wakeup_dev_required)
-                       wake_up(&priv->waitq);
-       }
-
-       spin_unlock_irqrestore(&priv->driver_lock, flags);
-       lbs_deb_leave(LBS_DEB_THREAD);
-}
-EXPORT_SYMBOL_GPL(lbs_host_to_card_done);
-
-int lbs_set_mac_address(struct net_device *dev, void *addr)
-{
-       int ret = 0;
-       struct lbs_private *priv = dev->ml_priv;
-       struct sockaddr *phwaddr = addr;
-
-       lbs_deb_enter(LBS_DEB_NET);
-
-       /*
-        * Can only set MAC address when all interfaces are down, to be written
-        * to the hardware when one of them is brought up.
-        */
-       if (lbs_iface_active(priv))
-               return -EBUSY;
-
-       /* In case it was called from the mesh device */
-       dev = priv->dev;
-
-       memcpy(priv->current_addr, phwaddr->sa_data, ETH_ALEN);
-       memcpy(dev->dev_addr, phwaddr->sa_data, ETH_ALEN);
-       if (priv->mesh_dev)
-               memcpy(priv->mesh_dev->dev_addr, phwaddr->sa_data, ETH_ALEN);
-
-       lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
-       return ret;
-}
-
-
-static inline int mac_in_list(unsigned char *list, int list_len,
-                             unsigned char *mac)
-{
-       while (list_len) {
-               if (!memcmp(list, mac, ETH_ALEN))
-                       return 1;
-               list += ETH_ALEN;
-               list_len--;
-       }
-       return 0;
-}
-
-
-static int lbs_add_mcast_addrs(struct cmd_ds_mac_multicast_adr *cmd,
-                              struct net_device *dev, int nr_addrs)
-{
-       int i = nr_addrs;
-       struct netdev_hw_addr *ha;
-       int cnt;
-
-       if ((dev->flags & (IFF_UP|IFF_MULTICAST)) != (IFF_UP|IFF_MULTICAST))
-               return nr_addrs;
-
-       netif_addr_lock_bh(dev);
-       cnt = netdev_mc_count(dev);
-       netdev_for_each_mc_addr(ha, dev) {
-               if (mac_in_list(cmd->maclist, nr_addrs, ha->addr)) {
-                       lbs_deb_net("mcast address %s:%pM skipped\n", dev->name,
-                                   ha->addr);
-                       cnt--;
-                       continue;
-               }
-
-               if (i == MRVDRV_MAX_MULTICAST_LIST_SIZE)
-                       break;
-               memcpy(&cmd->maclist[6*i], ha->addr, ETH_ALEN);
-               lbs_deb_net("mcast address %s:%pM added to filter\n", dev->name,
-                           ha->addr);
-               i++;
-               cnt--;
-       }
-       netif_addr_unlock_bh(dev);
-       if (cnt)
-               return -EOVERFLOW;
-
-       return i;
-}
-
-void lbs_update_mcast(struct lbs_private *priv)
-{
-       struct cmd_ds_mac_multicast_adr mcast_cmd;
-       int dev_flags = 0;
-       int nr_addrs;
-       int old_mac_control = priv->mac_control;
-
-       lbs_deb_enter(LBS_DEB_NET);
-
-       if (netif_running(priv->dev))
-               dev_flags |= priv->dev->flags;
-       if (priv->mesh_dev && netif_running(priv->mesh_dev))
-               dev_flags |= priv->mesh_dev->flags;
-
-       if (dev_flags & IFF_PROMISC) {
-               priv->mac_control |= CMD_ACT_MAC_PROMISCUOUS_ENABLE;
-               priv->mac_control &= ~(CMD_ACT_MAC_ALL_MULTICAST_ENABLE |
-                                      CMD_ACT_MAC_MULTICAST_ENABLE);
-               goto out_set_mac_control;
-       } else if (dev_flags & IFF_ALLMULTI) {
-       do_allmulti:
-               priv->mac_control |= CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
-               priv->mac_control &= ~(CMD_ACT_MAC_PROMISCUOUS_ENABLE |
-                                      CMD_ACT_MAC_MULTICAST_ENABLE);
-               goto out_set_mac_control;
-       }
-
-       /* Once for priv->dev, again for priv->mesh_dev if it exists */
-       nr_addrs = lbs_add_mcast_addrs(&mcast_cmd, priv->dev, 0);
-       if (nr_addrs >= 0 && priv->mesh_dev)
-               nr_addrs = lbs_add_mcast_addrs(&mcast_cmd, priv->mesh_dev, nr_addrs);
-       if (nr_addrs < 0)
-               goto do_allmulti;
-
-       if (nr_addrs) {
-               int size = offsetof(struct cmd_ds_mac_multicast_adr,
-                                   maclist[6*nr_addrs]);
-
-               mcast_cmd.action = cpu_to_le16(CMD_ACT_SET);
-               mcast_cmd.hdr.size = cpu_to_le16(size);
-               mcast_cmd.nr_of_adrs = cpu_to_le16(nr_addrs);
-
-               lbs_cmd_async(priv, CMD_MAC_MULTICAST_ADR, &mcast_cmd.hdr, size);
-
-               priv->mac_control |= CMD_ACT_MAC_MULTICAST_ENABLE;
-       } else
-               priv->mac_control &= ~CMD_ACT_MAC_MULTICAST_ENABLE;
-
-       priv->mac_control &= ~(CMD_ACT_MAC_PROMISCUOUS_ENABLE |
-                              CMD_ACT_MAC_ALL_MULTICAST_ENABLE);
- out_set_mac_control:
-       if (priv->mac_control != old_mac_control)
-               lbs_set_mac_control(priv);
-
-       lbs_deb_leave(LBS_DEB_NET);
-}
-
-static void lbs_set_mcast_worker(struct work_struct *work)
-{
-       struct lbs_private *priv = container_of(work, struct lbs_private, mcast_work);
-       lbs_update_mcast(priv);
-}
-
-void lbs_set_multicast_list(struct net_device *dev)
-{
-       struct lbs_private *priv = dev->ml_priv;
-
-       schedule_work(&priv->mcast_work);
-}
-
-/**
- *  lbs_thread - handles the major jobs in the LBS driver.
- *  It handles all events generated by firmware, RX data received
- *  from firmware and TX data sent from kernel.
- *
- *  @data:     A pointer to &lbs_thread structure
- *  returns:   0
- */
-static int lbs_thread(void *data)
-{
-       struct net_device *dev = data;
-       struct lbs_private *priv = dev->ml_priv;
-       wait_queue_t wait;
-
-       lbs_deb_enter(LBS_DEB_THREAD);
-
-       init_waitqueue_entry(&wait, current);
-
-       for (;;) {
-               int shouldsleep;
-               u8 resp_idx;
-
-               lbs_deb_thread("1: currenttxskb %p, dnld_sent %d\n",
-                               priv->currenttxskb, priv->dnld_sent);
-
-               add_wait_queue(&priv->waitq, &wait);
-               set_current_state(TASK_INTERRUPTIBLE);
-               spin_lock_irq(&priv->driver_lock);
-
-               if (kthread_should_stop())
-                       shouldsleep = 0;        /* Bye */
-               else if (priv->surpriseremoved)
-                       shouldsleep = 1;        /* We need to wait until we're _told_ to die */
-               else if (priv->psstate == PS_STATE_SLEEP)
-                       shouldsleep = 1;        /* Sleep mode. Nothing we can do till it wakes */
-               else if (priv->cmd_timed_out)
-                       shouldsleep = 0;        /* Command timed out. Recover */
-               else if (!priv->fw_ready)
-                       shouldsleep = 1;        /* Firmware not ready. We're waiting for it */
-               else if (priv->dnld_sent)
-                       shouldsleep = 1;        /* Something is en route to the device already */
-               else if (priv->tx_pending_len > 0)
-                       shouldsleep = 0;        /* We've a packet to send */
-               else if (priv->resp_len[priv->resp_idx])
-                       shouldsleep = 0;        /* We have a command response */
-               else if (priv->cur_cmd)
-                       shouldsleep = 1;        /* Can't send a command; one already running */
-               else if (!list_empty(&priv->cmdpendingq) &&
-                                       !(priv->wakeup_dev_required))
-                       shouldsleep = 0;        /* We have a command to send */
-               else if (kfifo_len(&priv->event_fifo))
-                       shouldsleep = 0;        /* We have an event to process */
-               else
-                       shouldsleep = 1;        /* No command */
-
-               if (shouldsleep) {
-                       lbs_deb_thread("sleeping, connect_status %d, "
-                               "psmode %d, psstate %d\n",
-                               priv->connect_status,
-                               priv->psmode, priv->psstate);
-                       spin_unlock_irq(&priv->driver_lock);
-                       schedule();
-               } else
-                       spin_unlock_irq(&priv->driver_lock);
-
-               lbs_deb_thread("2: currenttxskb %p, dnld_send %d\n",
-                              priv->currenttxskb, priv->dnld_sent);
-
-               set_current_state(TASK_RUNNING);
-               remove_wait_queue(&priv->waitq, &wait);
-
-               lbs_deb_thread("3: currenttxskb %p, dnld_sent %d\n",
-                              priv->currenttxskb, priv->dnld_sent);
-
-               if (kthread_should_stop()) {
-                       lbs_deb_thread("break from main thread\n");
-                       break;
-               }
-
-               if (priv->surpriseremoved) {
-                       lbs_deb_thread("adapter removed; waiting to die...\n");
-                       continue;
-               }
-
-               lbs_deb_thread("4: currenttxskb %p, dnld_sent %d\n",
-                      priv->currenttxskb, priv->dnld_sent);
-
-               /* Process any pending command response */
-               spin_lock_irq(&priv->driver_lock);
-               resp_idx = priv->resp_idx;
-               if (priv->resp_len[resp_idx]) {
-                       spin_unlock_irq(&priv->driver_lock);
-                       lbs_process_command_response(priv,
-                               priv->resp_buf[resp_idx],
-                               priv->resp_len[resp_idx]);
-                       spin_lock_irq(&priv->driver_lock);
-                       priv->resp_len[resp_idx] = 0;
-               }
-               spin_unlock_irq(&priv->driver_lock);
-
-               /* Process hardware events, e.g. card removed, link lost */
-               spin_lock_irq(&priv->driver_lock);
-               while (kfifo_len(&priv->event_fifo)) {
-                       u32 event;
-
-                       if (kfifo_out(&priv->event_fifo,
-                               (unsigned char *) &event, sizeof(event)) !=
-                               sizeof(event))
-                                       break;
-                       spin_unlock_irq(&priv->driver_lock);
-                       lbs_process_event(priv, event);
-                       spin_lock_irq(&priv->driver_lock);
-               }
-               spin_unlock_irq(&priv->driver_lock);
-
-               if (priv->wakeup_dev_required) {
-                       lbs_deb_thread("Waking up device...\n");
-                       /* Wake up device */
-                       if (priv->exit_deep_sleep(priv))
-                               lbs_deb_thread("Wakeup device failed\n");
-                       continue;
-               }
-
-               /* command timeout stuff */
-               if (priv->cmd_timed_out && priv->cur_cmd) {
-                       struct cmd_ctrl_node *cmdnode = priv->cur_cmd;
-
-                       netdev_info(dev, "Timeout submitting command 0x%04x\n",
-                                   le16_to_cpu(cmdnode->cmdbuf->command));
-                       lbs_complete_command(priv, cmdnode, -ETIMEDOUT);
-
-                       /* Reset card, but only when it isn't in the process
-                        * of being shutdown anyway. */
-                       if (!dev->dismantle && priv->reset_card)
-                               priv->reset_card(priv);
-               }
-               priv->cmd_timed_out = 0;
-
-               if (!priv->fw_ready)
-                       continue;
-
-               /* Check if we need to confirm Sleep Request received previously */
-               if (priv->psstate == PS_STATE_PRE_SLEEP &&
-                   !priv->dnld_sent && !priv->cur_cmd) {
-                       if (priv->connect_status == LBS_CONNECTED) {
-                               lbs_deb_thread("pre-sleep, currenttxskb %p, "
-                                       "dnld_sent %d, cur_cmd %p\n",
-                                       priv->currenttxskb, priv->dnld_sent,
-                                       priv->cur_cmd);
-
-                               lbs_ps_confirm_sleep(priv);
-                       } else {
-                               /* workaround for firmware sending
-                                * deauth/linkloss event immediately
-                                * after sleep request; remove this
-                                * after firmware fixes it
-                                */
-                               priv->psstate = PS_STATE_AWAKE;
-                               netdev_alert(dev,
-                                            "ignore PS_SleepConfirm in non-connected state\n");
-                       }
-               }
-
-               /* The PS state is changed during processing of Sleep Request
-                * event above
-                */
-               if ((priv->psstate == PS_STATE_SLEEP) ||
-                   (priv->psstate == PS_STATE_PRE_SLEEP))
-                       continue;
-
-               if (priv->is_deep_sleep)
-                       continue;
-
-               /* Execute the next command */
-               if (!priv->dnld_sent && !priv->cur_cmd)
-                       lbs_execute_next_command(priv);
-
-               spin_lock_irq(&priv->driver_lock);
-               if (!priv->dnld_sent && priv->tx_pending_len > 0) {
-                       int ret = priv->hw_host_to_card(priv, MVMS_DAT,
-                                                       priv->tx_pending_buf,
-                                                       priv->tx_pending_len);
-                       if (ret) {
-                               lbs_deb_tx("host_to_card failed %d\n", ret);
-                               priv->dnld_sent = DNLD_RES_RECEIVED;
-                       } else {
-                               mod_timer(&priv->tx_lockup_timer,
-                                         jiffies + (HZ * 5));
-                       }
-                       priv->tx_pending_len = 0;
-                       if (!priv->currenttxskb) {
-                               /* We can wake the queues immediately if we aren't
-                                  waiting for TX feedback */
-                               if (priv->connect_status == LBS_CONNECTED)
-                                       netif_wake_queue(priv->dev);
-                               if (priv->mesh_dev &&
-                                   netif_running(priv->mesh_dev))
-                                       netif_wake_queue(priv->mesh_dev);
-                       }
-               }
-               spin_unlock_irq(&priv->driver_lock);
-       }
-
-       del_timer(&priv->command_timer);
-       del_timer(&priv->tx_lockup_timer);
-       del_timer(&priv->auto_deepsleep_timer);
-
-       lbs_deb_leave(LBS_DEB_THREAD);
-       return 0;
-}
-
-/**
- * lbs_setup_firmware - gets the HW spec from the firmware and sets
- *        some basic parameters
- *
- *  @priv:     A pointer to &struct lbs_private structure
- *  returns:   0 or -1
- */
-static int lbs_setup_firmware(struct lbs_private *priv)
-{
-       int ret = -1;
-       s16 curlevel = 0, minlevel = 0, maxlevel = 0;
-
-       lbs_deb_enter(LBS_DEB_FW);
-
-       /* Read MAC address from firmware */
-       eth_broadcast_addr(priv->current_addr);
-       ret = lbs_update_hw_spec(priv);
-       if (ret)
-               goto done;
-
-       /* Read power levels if available */
-       ret = lbs_get_tx_power(priv, &curlevel, &minlevel, &maxlevel);
-       if (ret == 0) {
-               priv->txpower_cur = curlevel;
-               priv->txpower_min = minlevel;
-               priv->txpower_max = maxlevel;
-       }
-
-       /* Send cmd to FW to enable 11D function */
-       ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_11D_ENABLE, 1);
-       if (ret)
-               goto done;
-
-       ret = lbs_set_mac_control_sync(priv);
-done:
-       lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
-       return ret;
-}
-
-int lbs_suspend(struct lbs_private *priv)
-{
-       int ret;
-
-       lbs_deb_enter(LBS_DEB_FW);
-
-       if (priv->is_deep_sleep) {
-               ret = lbs_set_deep_sleep(priv, 0);
-               if (ret) {
-                       netdev_err(priv->dev,
-                                  "deep sleep cancellation failed: %d\n", ret);
-                       return ret;
-               }
-               priv->deep_sleep_required = 1;
-       }
-
-       ret = lbs_set_host_sleep(priv, 1);
-
-       netif_device_detach(priv->dev);
-       if (priv->mesh_dev)
-               netif_device_detach(priv->mesh_dev);
-
-       lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(lbs_suspend);
-
-int lbs_resume(struct lbs_private *priv)
-{
-       int ret;
-
-       lbs_deb_enter(LBS_DEB_FW);
-
-       ret = lbs_set_host_sleep(priv, 0);
-
-       netif_device_attach(priv->dev);
-       if (priv->mesh_dev)
-               netif_device_attach(priv->mesh_dev);
-
-       if (priv->deep_sleep_required) {
-               priv->deep_sleep_required = 0;
-               ret = lbs_set_deep_sleep(priv, 1);
-               if (ret)
-                       netdev_err(priv->dev,
-                                  "deep sleep activation failed: %d\n", ret);
-       }
-
-       if (priv->setup_fw_on_resume)
-               ret = lbs_setup_firmware(priv);
-
-       lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(lbs_resume);
-
-/**
- * lbs_cmd_timeout_handler - handles the timeout of command sending.
- * It will re-send the same command again.
- *
- * @data: &struct lbs_private pointer
- */
-static void lbs_cmd_timeout_handler(unsigned long data)
-{
-       struct lbs_private *priv = (struct lbs_private *)data;
-       unsigned long flags;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-       spin_lock_irqsave(&priv->driver_lock, flags);
-
-       if (!priv->cur_cmd)
-               goto out;
-
-       netdev_info(priv->dev, "command 0x%04x timed out\n",
-                   le16_to_cpu(priv->cur_cmd->cmdbuf->command));
-
-       priv->cmd_timed_out = 1;
-
-       /*
-        * If the device didn't even acknowledge the command, reset the state
-        * so that we don't block all future commands due to this one timeout.
-        */
-       if (priv->dnld_sent == DNLD_CMD_SENT)
-               priv->dnld_sent = DNLD_RES_RECEIVED;
-
-       wake_up(&priv->waitq);
-out:
-       spin_unlock_irqrestore(&priv->driver_lock, flags);
-       lbs_deb_leave(LBS_DEB_CMD);
-}
-
-/**
- * lbs_tx_lockup_handler - handles the timeout of the passing of TX frames
- * to the hardware. This is known to frequently happen with SD8686 when
- * waking up after a Wake-on-WLAN-triggered resume.
- *
- * @data: &struct lbs_private pointer
- */
-static void lbs_tx_lockup_handler(unsigned long data)
-{
-       struct lbs_private *priv = (struct lbs_private *)data;
-       unsigned long flags;
-
-       lbs_deb_enter(LBS_DEB_TX);
-       spin_lock_irqsave(&priv->driver_lock, flags);
-
-       netdev_info(priv->dev, "TX lockup detected\n");
-       if (priv->reset_card)
-               priv->reset_card(priv);
-
-       priv->dnld_sent = DNLD_RES_RECEIVED;
-       wake_up_interruptible(&priv->waitq);
-
-       spin_unlock_irqrestore(&priv->driver_lock, flags);
-       lbs_deb_leave(LBS_DEB_TX);
-}
-
-/**
- * auto_deepsleep_timer_fn - put the device back to deep sleep mode when
- * timer expires and no activity (command, event, data etc.) is detected.
- * @data:      &struct lbs_private pointer
- * returns:    N/A
- */
-static void auto_deepsleep_timer_fn(unsigned long data)
-{
-       struct lbs_private *priv = (struct lbs_private *)data;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       if (priv->is_activity_detected) {
-               priv->is_activity_detected = 0;
-       } else {
-               if (priv->is_auto_deep_sleep_enabled &&
-                   (!priv->wakeup_dev_required) &&
-                   (priv->connect_status != LBS_CONNECTED)) {
-                       struct cmd_header cmd;
-
-                       lbs_deb_main("Entering auto deep sleep mode...\n");
-                       memset(&cmd, 0, sizeof(cmd));
-                       cmd.size = cpu_to_le16(sizeof(cmd));
-                       lbs_cmd_async(priv, CMD_802_11_DEEP_SLEEP, &cmd,
-                                       sizeof(cmd));
-               }
-       }
-       mod_timer(&priv->auto_deepsleep_timer , jiffies +
-                               (priv->auto_deep_sleep_timeout * HZ)/1000);
-       lbs_deb_leave(LBS_DEB_CMD);
-}
-
-int lbs_enter_auto_deep_sleep(struct lbs_private *priv)
-{
-       lbs_deb_enter(LBS_DEB_SDIO);
-
-       priv->is_auto_deep_sleep_enabled = 1;
-       if (priv->is_deep_sleep)
-               priv->wakeup_dev_required = 1;
-       mod_timer(&priv->auto_deepsleep_timer ,
-                       jiffies + (priv->auto_deep_sleep_timeout * HZ)/1000);
-
-       lbs_deb_leave(LBS_DEB_SDIO);
-       return 0;
-}
-
-int lbs_exit_auto_deep_sleep(struct lbs_private *priv)
-{
-       lbs_deb_enter(LBS_DEB_SDIO);
-
-       priv->is_auto_deep_sleep_enabled = 0;
-       priv->auto_deep_sleep_timeout = 0;
-       del_timer(&priv->auto_deepsleep_timer);
-
-       lbs_deb_leave(LBS_DEB_SDIO);
-       return 0;
-}
-
-static int lbs_init_adapter(struct lbs_private *priv)
-{
-       int ret;
-
-       lbs_deb_enter(LBS_DEB_MAIN);
-
-       eth_broadcast_addr(priv->current_addr);
-
-       priv->connect_status = LBS_DISCONNECTED;
-       priv->channel = DEFAULT_AD_HOC_CHANNEL;
-       priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
-       priv->radio_on = 1;
-       priv->psmode = LBS802_11POWERMODECAM;
-       priv->psstate = PS_STATE_FULL_POWER;
-       priv->is_deep_sleep = 0;
-       priv->is_auto_deep_sleep_enabled = 0;
-       priv->deep_sleep_required = 0;
-       priv->wakeup_dev_required = 0;
-       init_waitqueue_head(&priv->ds_awake_q);
-       init_waitqueue_head(&priv->scan_q);
-       priv->authtype_auto = 1;
-       priv->is_host_sleep_configured = 0;
-       priv->is_host_sleep_activated = 0;
-       init_waitqueue_head(&priv->host_sleep_q);
-       init_waitqueue_head(&priv->fw_waitq);
-       mutex_init(&priv->lock);
-
-       setup_timer(&priv->command_timer, lbs_cmd_timeout_handler,
-               (unsigned long)priv);
-       setup_timer(&priv->tx_lockup_timer, lbs_tx_lockup_handler,
-               (unsigned long)priv);
-       setup_timer(&priv->auto_deepsleep_timer, auto_deepsleep_timer_fn,
-                       (unsigned long)priv);
-
-       INIT_LIST_HEAD(&priv->cmdfreeq);
-       INIT_LIST_HEAD(&priv->cmdpendingq);
-
-       spin_lock_init(&priv->driver_lock);
-
-       /* Allocate the command buffers */
-       if (lbs_allocate_cmd_buffer(priv)) {
-               pr_err("Out of memory allocating command buffers\n");
-               ret = -ENOMEM;
-               goto out;
-       }
-       priv->resp_idx = 0;
-       priv->resp_len[0] = priv->resp_len[1] = 0;
-
-       /* Create the event FIFO */
-       ret = kfifo_alloc(&priv->event_fifo, sizeof(u32) * 16, GFP_KERNEL);
-       if (ret) {
-               pr_err("Out of memory allocating event FIFO buffer\n");
-               goto out;
-       }
-
-out:
-       lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
-
-       return ret;
-}
-
-static void lbs_free_adapter(struct lbs_private *priv)
-{
-       lbs_deb_enter(LBS_DEB_MAIN);
-
-       lbs_free_cmd_buffer(priv);
-       kfifo_free(&priv->event_fifo);
-       del_timer(&priv->command_timer);
-       del_timer(&priv->tx_lockup_timer);
-       del_timer(&priv->auto_deepsleep_timer);
-
-       lbs_deb_leave(LBS_DEB_MAIN);
-}
-
-static const struct net_device_ops lbs_netdev_ops = {
-       .ndo_open               = lbs_dev_open,
-       .ndo_stop               = lbs_eth_stop,
-       .ndo_start_xmit         = lbs_hard_start_xmit,
-       .ndo_set_mac_address    = lbs_set_mac_address,
-       .ndo_set_rx_mode        = lbs_set_multicast_list,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-/**
- * lbs_add_card - adds the card. It will probe the
- * card, allocate the lbs_priv and initialize the device.
- *
- * @card:      A pointer to card
- * @dmdev:     A pointer to &struct device
- * returns:    A pointer to &struct lbs_private structure
- */
-struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
-{
-       struct net_device *dev;
-       struct wireless_dev *wdev;
-       struct lbs_private *priv = NULL;
-
-       lbs_deb_enter(LBS_DEB_MAIN);
-
-       /* Allocate an Ethernet device and register it */
-       wdev = lbs_cfg_alloc(dmdev);
-       if (IS_ERR(wdev)) {
-               pr_err("cfg80211 init failed\n");
-               goto done;
-       }
-
-       wdev->iftype = NL80211_IFTYPE_STATION;
-       priv = wdev_priv(wdev);
-       priv->wdev = wdev;
-
-       if (lbs_init_adapter(priv)) {
-               pr_err("failed to initialize adapter structure\n");
-               goto err_wdev;
-       }
-
-       dev = alloc_netdev(0, "wlan%d", NET_NAME_UNKNOWN, ether_setup);
-       if (!dev) {
-               dev_err(dmdev, "no memory for network device instance\n");
-               goto err_adapter;
-       }
-
-       dev->ieee80211_ptr = wdev;
-       dev->ml_priv = priv;
-       SET_NETDEV_DEV(dev, dmdev);
-       wdev->netdev = dev;
-       priv->dev = dev;
-
-       dev->netdev_ops = &lbs_netdev_ops;
-       dev->watchdog_timeo = 5 * HZ;
-       dev->ethtool_ops = &lbs_ethtool_ops;
-       dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
-
-       priv->card = card;
-
-       strcpy(dev->name, "wlan%d");
-
-       lbs_deb_thread("Starting main thread...\n");
-       init_waitqueue_head(&priv->waitq);
-       priv->main_thread = kthread_run(lbs_thread, dev, "lbs_main");
-       if (IS_ERR(priv->main_thread)) {
-               lbs_deb_thread("Error creating main thread.\n");
-               goto err_ndev;
-       }
-
-       priv->work_thread = create_singlethread_workqueue("lbs_worker");
-       INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker);
-
-       priv->wol_criteria = EHS_REMOVE_WAKEUP;
-       priv->wol_gpio = 0xff;
-       priv->wol_gap = 20;
-       priv->ehs_remove_supported = true;
-
-       goto done;
-
- err_ndev:
-       free_netdev(dev);
-
- err_adapter:
-       lbs_free_adapter(priv);
-
- err_wdev:
-       lbs_cfg_free(priv);
-
-       priv = NULL;
-
-done:
-       lbs_deb_leave_args(LBS_DEB_MAIN, "priv %p", priv);
-       return priv;
-}
-EXPORT_SYMBOL_GPL(lbs_add_card);
-
-
-void lbs_remove_card(struct lbs_private *priv)
-{
-       struct net_device *dev = priv->dev;
-
-       lbs_deb_enter(LBS_DEB_MAIN);
-
-       lbs_remove_mesh(priv);
-
-       if (priv->wiphy_registered)
-               lbs_scan_deinit(priv);
-
-       lbs_wait_for_firmware_load(priv);
-
-       /* worker thread destruction blocks on the in-flight command which
-        * should have been cleared already in lbs_stop_card().
-        */
-       lbs_deb_main("destroying worker thread\n");
-       destroy_workqueue(priv->work_thread);
-       lbs_deb_main("done destroying worker thread\n");
-
-       if (priv->psmode == LBS802_11POWERMODEMAX_PSP) {
-               priv->psmode = LBS802_11POWERMODECAM;
-               lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS, true);
-       }
-
-       if (priv->is_deep_sleep) {
-               priv->is_deep_sleep = 0;
-               wake_up_interruptible(&priv->ds_awake_q);
-       }
-
-       priv->is_host_sleep_configured = 0;
-       priv->is_host_sleep_activated = 0;
-       wake_up_interruptible(&priv->host_sleep_q);
-
-       /* Stop the thread servicing the interrupts */
-       priv->surpriseremoved = 1;
-       kthread_stop(priv->main_thread);
-
-       lbs_free_adapter(priv);
-       lbs_cfg_free(priv);
-       free_netdev(dev);
-
-       lbs_deb_leave(LBS_DEB_MAIN);
-}
-EXPORT_SYMBOL_GPL(lbs_remove_card);
-
-
-int lbs_rtap_supported(struct lbs_private *priv)
-{
-       if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5)
-               return 1;
-
-       /* newer firmware use a capability mask */
-       return ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
-               (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK));
-}
-
-
-int lbs_start_card(struct lbs_private *priv)
-{
-       struct net_device *dev = priv->dev;
-       int ret = -1;
-
-       lbs_deb_enter(LBS_DEB_MAIN);
-
-       /* poke the firmware */
-       ret = lbs_setup_firmware(priv);
-       if (ret)
-               goto done;
-
-       if (!lbs_disablemesh)
-               lbs_init_mesh(priv);
-       else
-               pr_info("%s: mesh disabled\n", dev->name);
-
-       if (lbs_cfg_register(priv)) {
-               pr_err("cannot register device\n");
-               goto done;
-       }
-
-       if (lbs_mesh_activated(priv))
-               lbs_start_mesh(priv);
-
-       lbs_debugfs_init_one(priv, dev);
-
-       netdev_info(dev, "Marvell WLAN 802.11 adapter\n");
-
-       ret = 0;
-
-done:
-       lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(lbs_start_card);
-
-
-void lbs_stop_card(struct lbs_private *priv)
-{
-       struct net_device *dev;
-
-       lbs_deb_enter(LBS_DEB_MAIN);
-
-       if (!priv)
-               goto out;
-       dev = priv->dev;
-
-       /* If the netdev isn't registered, it means that lbs_start_card() was
-        * never called so we have nothing to do here. */
-       if (dev->reg_state != NETREG_REGISTERED)
-               goto out;
-
-       netif_stop_queue(dev);
-       netif_carrier_off(dev);
-
-       lbs_debugfs_remove_one(priv);
-       lbs_deinit_mesh(priv);
-       unregister_netdev(dev);
-
-out:
-       lbs_deb_leave(LBS_DEB_MAIN);
-}
-EXPORT_SYMBOL_GPL(lbs_stop_card);
-
-
-void lbs_queue_event(struct lbs_private *priv, u32 event)
-{
-       unsigned long flags;
-
-       lbs_deb_enter(LBS_DEB_THREAD);
-       spin_lock_irqsave(&priv->driver_lock, flags);
-
-       if (priv->psstate == PS_STATE_SLEEP)
-               priv->psstate = PS_STATE_AWAKE;
-
-       kfifo_in(&priv->event_fifo, (unsigned char *) &event, sizeof(u32));
-
-       wake_up(&priv->waitq);
-
-       spin_unlock_irqrestore(&priv->driver_lock, flags);
-       lbs_deb_leave(LBS_DEB_THREAD);
-}
-EXPORT_SYMBOL_GPL(lbs_queue_event);
-
-void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx)
-{
-       lbs_deb_enter(LBS_DEB_THREAD);
-
-       if (priv->psstate == PS_STATE_SLEEP)
-               priv->psstate = PS_STATE_AWAKE;
-
-       /* Swap buffers by flipping the response index */
-       BUG_ON(resp_idx > 1);
-       priv->resp_idx = resp_idx;
-
-       wake_up(&priv->waitq);
-
-       lbs_deb_leave(LBS_DEB_THREAD);
-}
-EXPORT_SYMBOL_GPL(lbs_notify_command_response);
-
-static int __init lbs_init_module(void)
-{
-       lbs_deb_enter(LBS_DEB_MAIN);
-       memset(&confirm_sleep, 0, sizeof(confirm_sleep));
-       confirm_sleep.hdr.command = cpu_to_le16(CMD_802_11_PS_MODE);
-       confirm_sleep.hdr.size = cpu_to_le16(sizeof(confirm_sleep));
-       confirm_sleep.action = cpu_to_le16(PS_MODE_ACTION_SLEEP_CONFIRMED);
-       lbs_debugfs_init();
-       lbs_deb_leave(LBS_DEB_MAIN);
-       return 0;
-}
-
-static void __exit lbs_exit_module(void)
-{
-       lbs_deb_enter(LBS_DEB_MAIN);
-       lbs_debugfs_remove();
-       lbs_deb_leave(LBS_DEB_MAIN);
-}
-
-module_init(lbs_init_module);
-module_exit(lbs_exit_module);
-
-MODULE_DESCRIPTION("Libertas WLAN Driver Library");
-MODULE_AUTHOR("Marvell International Ltd.");
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c
deleted file mode 100644 (file)
index d0c881d..0000000
+++ /dev/null
@@ -1,1187 +0,0 @@
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/delay.h>
-#include <linux/etherdevice.h>
-#include <linux/hardirq.h>
-#include <linux/netdevice.h>
-#include <linux/if_ether.h>
-#include <linux/if_arp.h>
-#include <linux/kthread.h>
-#include <linux/kfifo.h>
-#include <net/cfg80211.h>
-
-#include "mesh.h"
-#include "decl.h"
-#include "cmd.h"
-
-
-static int lbs_add_mesh(struct lbs_private *priv);
-
-/***************************************************************************
- * Mesh command handling
- */
-
-static int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
-                   struct cmd_ds_mesh_access *cmd)
-{
-       int ret;
-
-       lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
-
-       cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS);
-       cmd->hdr.size = cpu_to_le16(sizeof(*cmd));
-       cmd->hdr.result = 0;
-
-       cmd->action = cpu_to_le16(cmd_action);
-
-       ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd);
-
-       lbs_deb_leave(LBS_DEB_CMD);
-       return ret;
-}
-
-static int __lbs_mesh_config_send(struct lbs_private *priv,
-                                 struct cmd_ds_mesh_config *cmd,
-                                 uint16_t action, uint16_t type)
-{
-       int ret;
-       u16 command = CMD_MESH_CONFIG_OLD;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       /*
-        * Command id is 0xac for v10 FW along with mesh interface
-        * id in bits 14-13-12.
-        */
-       if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
-               command = CMD_MESH_CONFIG |
-                         (MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET);
-
-       cmd->hdr.command = cpu_to_le16(command);
-       cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config));
-       cmd->hdr.result = 0;
-
-       cmd->type = cpu_to_le16(type);
-       cmd->action = cpu_to_le16(action);
-
-       ret = lbs_cmd_with_response(priv, command, cmd);
-
-       lbs_deb_leave(LBS_DEB_CMD);
-       return ret;
-}
-
-static int lbs_mesh_config_send(struct lbs_private *priv,
-                        struct cmd_ds_mesh_config *cmd,
-                        uint16_t action, uint16_t type)
-{
-       int ret;
-
-       if (!(priv->fwcapinfo & FW_CAPINFO_PERSISTENT_CONFIG))
-               return -EOPNOTSUPP;
-
-       ret = __lbs_mesh_config_send(priv, cmd, action, type);
-       return ret;
-}
-
-/* This function is the CMD_MESH_CONFIG legacy function.  It only handles the
- * START and STOP actions.  The extended actions supported by CMD_MESH_CONFIG
- * are all handled by preparing a struct cmd_ds_mesh_config and passing it to
- * lbs_mesh_config_send.
- */
-static int lbs_mesh_config(struct lbs_private *priv, uint16_t action,
-               uint16_t chan)
-{
-       struct cmd_ds_mesh_config cmd;
-       struct mrvl_meshie *ie;
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.channel = cpu_to_le16(chan);
-       ie = (struct mrvl_meshie *)cmd.data;
-
-       switch (action) {
-       case CMD_ACT_MESH_CONFIG_START:
-               ie->id = WLAN_EID_VENDOR_SPECIFIC;
-               ie->val.oui[0] = 0x00;
-               ie->val.oui[1] = 0x50;
-               ie->val.oui[2] = 0x43;
-               ie->val.type = MARVELL_MESH_IE_TYPE;
-               ie->val.subtype = MARVELL_MESH_IE_SUBTYPE;
-               ie->val.version = MARVELL_MESH_IE_VERSION;
-               ie->val.active_protocol_id = MARVELL_MESH_PROTO_ID_HWMP;
-               ie->val.active_metric_id = MARVELL_MESH_METRIC_ID;
-               ie->val.mesh_capability = MARVELL_MESH_CAPABILITY;
-               ie->val.mesh_id_len = priv->mesh_ssid_len;
-               memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len);
-               ie->len = sizeof(struct mrvl_meshie_val) -
-                       IEEE80211_MAX_SSID_LEN + priv->mesh_ssid_len;
-               cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val));
-               break;
-       case CMD_ACT_MESH_CONFIG_STOP:
-               break;
-       default:
-               return -1;
-       }
-       lbs_deb_cmd("mesh config action %d type %x channel %d SSID %*pE\n",
-                   action, priv->mesh_tlv, chan, priv->mesh_ssid_len,
-                   priv->mesh_ssid);
-
-       return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
-}
-
-int lbs_mesh_set_channel(struct lbs_private *priv, u8 channel)
-{
-       priv->mesh_channel = channel;
-       return lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, channel);
-}
-
-static uint16_t lbs_mesh_get_channel(struct lbs_private *priv)
-{
-       return priv->mesh_channel ?: 1;
-}
-
-/***************************************************************************
- * Mesh sysfs support
- */
-
-/*
- * Attributes exported through sysfs
- */
-
-/**
- * lbs_anycast_get - Get function for sysfs attribute anycast_mask
- * @dev: the &struct device
- * @attr: device attributes
- * @buf: buffer where data will be returned
- */
-static ssize_t lbs_anycast_get(struct device *dev,
-               struct device_attribute *attr, char * buf)
-{
-       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
-       struct cmd_ds_mesh_access mesh_access;
-       int ret;
-
-       memset(&mesh_access, 0, sizeof(mesh_access));
-
-       ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_ANYCAST, &mesh_access);
-       if (ret)
-               return ret;
-
-       return snprintf(buf, 12, "0x%X\n", le32_to_cpu(mesh_access.data[0]));
-}
-
-/**
- * lbs_anycast_set - Set function for sysfs attribute anycast_mask
- * @dev: the &struct device
- * @attr: device attributes
- * @buf: buffer that contains new attribute value
- * @count: size of buffer
- */
-static ssize_t lbs_anycast_set(struct device *dev,
-               struct device_attribute *attr, const char * buf, size_t count)
-{
-       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
-       struct cmd_ds_mesh_access mesh_access;
-       uint32_t datum;
-       int ret;
-
-       memset(&mesh_access, 0, sizeof(mesh_access));
-       sscanf(buf, "%x", &datum);
-       mesh_access.data[0] = cpu_to_le32(datum);
-
-       ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_ANYCAST, &mesh_access);
-       if (ret)
-               return ret;
-
-       return strlen(buf);
-}
-
-/**
- * lbs_prb_rsp_limit_get - Get function for sysfs attribute prb_rsp_limit
- * @dev: the &struct device
- * @attr: device attributes
- * @buf: buffer where data will be returned
- */
-static ssize_t lbs_prb_rsp_limit_get(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
-       struct cmd_ds_mesh_access mesh_access;
-       int ret;
-       u32 retry_limit;
-
-       memset(&mesh_access, 0, sizeof(mesh_access));
-       mesh_access.data[0] = cpu_to_le32(CMD_ACT_GET);
-
-       ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
-                       &mesh_access);
-       if (ret)
-               return ret;
-
-       retry_limit = le32_to_cpu(mesh_access.data[1]);
-       return snprintf(buf, 10, "%d\n", retry_limit);
-}
-
-/**
- * lbs_prb_rsp_limit_set - Set function for sysfs attribute prb_rsp_limit
- * @dev: the &struct device
- * @attr: device attributes
- * @buf: buffer that contains new attribute value
- * @count: size of buffer
- */
-static ssize_t lbs_prb_rsp_limit_set(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t count)
-{
-       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
-       struct cmd_ds_mesh_access mesh_access;
-       int ret;
-       unsigned long retry_limit;
-
-       memset(&mesh_access, 0, sizeof(mesh_access));
-       mesh_access.data[0] = cpu_to_le32(CMD_ACT_SET);
-
-       if (!kstrtoul(buf, 10, &retry_limit))
-               return -ENOTSUPP;
-       if (retry_limit > 15)
-               return -ENOTSUPP;
-
-       mesh_access.data[1] = cpu_to_le32(retry_limit);
-
-       ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
-                       &mesh_access);
-       if (ret)
-               return ret;
-
-       return strlen(buf);
-}
-
-/**
- * lbs_mesh_get - Get function for sysfs attribute mesh
- * @dev: the &struct device
- * @attr: device attributes
- * @buf: buffer where data will be returned
- */
-static ssize_t lbs_mesh_get(struct device *dev,
-               struct device_attribute *attr, char * buf)
-{
-       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
-       return snprintf(buf, 5, "0x%X\n", !!priv->mesh_dev);
-}
-
-/**
- * lbs_mesh_set - Set function for sysfs attribute mesh
- * @dev: the &struct device
- * @attr: device attributes
- * @buf: buffer that contains new attribute value
- * @count: size of buffer
- */
-static ssize_t lbs_mesh_set(struct device *dev,
-               struct device_attribute *attr, const char * buf, size_t count)
-{
-       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
-       int enable;
-
-       sscanf(buf, "%x", &enable);
-       enable = !!enable;
-       if (enable == !!priv->mesh_dev)
-               return count;
-
-       if (enable)
-               lbs_add_mesh(priv);
-       else
-               lbs_remove_mesh(priv);
-
-       return count;
-}
-
-/*
- * lbs_mesh attribute to be exported per ethX interface
- * through sysfs (/sys/class/net/ethX/lbs_mesh)
- */
-static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set);
-
-/*
- * anycast_mask attribute to be exported per mshX interface
- * through sysfs (/sys/class/net/mshX/anycast_mask)
- */
-static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set);
-
-/*
- * prb_rsp_limit attribute to be exported per mshX interface
- * through sysfs (/sys/class/net/mshX/prb_rsp_limit)
- */
-static DEVICE_ATTR(prb_rsp_limit, 0644, lbs_prb_rsp_limit_get,
-               lbs_prb_rsp_limit_set);
-
-static struct attribute *lbs_mesh_sysfs_entries[] = {
-       &dev_attr_anycast_mask.attr,
-       &dev_attr_prb_rsp_limit.attr,
-       NULL,
-};
-
-static const struct attribute_group lbs_mesh_attr_group = {
-       .attrs = lbs_mesh_sysfs_entries,
-};
-
-
-/***************************************************************************
- * Persistent configuration support
- */
-
-static int mesh_get_default_parameters(struct device *dev,
-                                      struct mrvl_mesh_defaults *defs)
-{
-       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
-       struct cmd_ds_mesh_config cmd;
-       int ret;
-
-       memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
-       ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_GET,
-                                  CMD_TYPE_MESH_GET_DEFAULTS);
-
-       if (ret)
-               return -EOPNOTSUPP;
-
-       memcpy(defs, &cmd.data[0], sizeof(struct mrvl_mesh_defaults));
-
-       return 0;
-}
-
-/**
- * bootflag_get - Get function for sysfs attribute bootflag
- * @dev: the &struct device
- * @attr: device attributes
- * @buf: buffer where data will be returned
- */
-static ssize_t bootflag_get(struct device *dev,
-                           struct device_attribute *attr, char *buf)
-{
-       struct mrvl_mesh_defaults defs;
-       int ret;
-
-       ret = mesh_get_default_parameters(dev, &defs);
-
-       if (ret)
-               return ret;
-
-       return snprintf(buf, 12, "%d\n", le32_to_cpu(defs.bootflag));
-}
-
-/**
- * bootflag_set - Set function for sysfs attribute bootflag
- * @dev: the &struct device
- * @attr: device attributes
- * @buf: buffer that contains new attribute value
- * @count: size of buffer
- */
-static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
-                           const char *buf, size_t count)
-{
-       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
-       struct cmd_ds_mesh_config cmd;
-       uint32_t datum;
-       int ret;
-
-       memset(&cmd, 0, sizeof(cmd));
-       ret = sscanf(buf, "%d", &datum);
-       if ((ret != 1) || (datum > 1))
-               return -EINVAL;
-
-       *((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum);
-       cmd.length = cpu_to_le16(sizeof(uint32_t));
-       ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
-                                  CMD_TYPE_MESH_SET_BOOTFLAG);
-       if (ret)
-               return ret;
-
-       return strlen(buf);
-}
-
-/**
- * boottime_get - Get function for sysfs attribute boottime
- * @dev: the &struct device
- * @attr: device attributes
- * @buf: buffer where data will be returned
- */
-static ssize_t boottime_get(struct device *dev,
-                           struct device_attribute *attr, char *buf)
-{
-       struct mrvl_mesh_defaults defs;
-       int ret;
-
-       ret = mesh_get_default_parameters(dev, &defs);
-
-       if (ret)
-               return ret;
-
-       return snprintf(buf, 12, "%d\n", defs.boottime);
-}
-
-/**
- * boottime_set - Set function for sysfs attribute boottime
- * @dev: the &struct device
- * @attr: device attributes
- * @buf: buffer that contains new attribute value
- * @count: size of buffer
- */
-static ssize_t boottime_set(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t count)
-{
-       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
-       struct cmd_ds_mesh_config cmd;
-       uint32_t datum;
-       int ret;
-
-       memset(&cmd, 0, sizeof(cmd));
-       ret = sscanf(buf, "%d", &datum);
-       if ((ret != 1) || (datum > 255))
-               return -EINVAL;
-
-       /* A too small boot time will result in the device booting into
-        * standalone (no-host) mode before the host can take control of it,
-        * so the change will be hard to revert.  This may be a desired
-        * feature (e.g to configure a very fast boot time for devices that
-        * will not be attached to a host), but dangerous.  So I'm enforcing a
-        * lower limit of 20 seconds:  remove and recompile the driver if this
-        * does not work for you.
-        */
-       datum = (datum < 20) ? 20 : datum;
-       cmd.data[0] = datum;
-       cmd.length = cpu_to_le16(sizeof(uint8_t));
-       ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
-                                  CMD_TYPE_MESH_SET_BOOTTIME);
-       if (ret)
-               return ret;
-
-       return strlen(buf);
-}
-
-/**
- * channel_get - Get function for sysfs attribute channel
- * @dev: the &struct device
- * @attr: device attributes
- * @buf: buffer where data will be returned
- */
-static ssize_t channel_get(struct device *dev,
-                          struct device_attribute *attr, char *buf)
-{
-       struct mrvl_mesh_defaults defs;
-       int ret;
-
-       ret = mesh_get_default_parameters(dev, &defs);
-
-       if (ret)
-               return ret;
-
-       return snprintf(buf, 12, "%d\n", le16_to_cpu(defs.channel));
-}
-
-/**
- * channel_set - Set function for sysfs attribute channel
- * @dev: the &struct device
- * @attr: device attributes
- * @buf: buffer that contains new attribute value
- * @count: size of buffer
- */
-static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
-                          const char *buf, size_t count)
-{
-       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
-       struct cmd_ds_mesh_config cmd;
-       uint32_t datum;
-       int ret;
-
-       memset(&cmd, 0, sizeof(cmd));
-       ret = sscanf(buf, "%d", &datum);
-       if (ret != 1 || datum < 1 || datum > 11)
-               return -EINVAL;
-
-       *((__le16 *)&cmd.data[0]) = cpu_to_le16(datum);
-       cmd.length = cpu_to_le16(sizeof(uint16_t));
-       ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
-                                  CMD_TYPE_MESH_SET_DEF_CHANNEL);
-       if (ret)
-               return ret;
-
-       return strlen(buf);
-}
-
-/**
- * mesh_id_get - Get function for sysfs attribute mesh_id
- * @dev: the &struct device
- * @attr: device attributes
- * @buf: buffer where data will be returned
- */
-static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
-                          char *buf)
-{
-       struct mrvl_mesh_defaults defs;
-       int ret;
-
-       ret = mesh_get_default_parameters(dev, &defs);
-
-       if (ret)
-               return ret;
-
-       if (defs.meshie.val.mesh_id_len > IEEE80211_MAX_SSID_LEN) {
-               dev_err(dev, "inconsistent mesh ID length\n");
-               defs.meshie.val.mesh_id_len = IEEE80211_MAX_SSID_LEN;
-       }
-
-       memcpy(buf, defs.meshie.val.mesh_id, defs.meshie.val.mesh_id_len);
-       buf[defs.meshie.val.mesh_id_len] = '\n';
-       buf[defs.meshie.val.mesh_id_len + 1] = '\0';
-
-       return defs.meshie.val.mesh_id_len + 1;
-}
-
-/**
- * mesh_id_set - Set function for sysfs attribute mesh_id
- * @dev: the &struct device
- * @attr: device attributes
- * @buf: buffer that contains new attribute value
- * @count: size of buffer
- */
-static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
-                          const char *buf, size_t count)
-{
-       struct cmd_ds_mesh_config cmd;
-       struct mrvl_mesh_defaults defs;
-       struct mrvl_meshie *ie;
-       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
-       int len;
-       int ret;
-
-       if (count < 2 || count > IEEE80211_MAX_SSID_LEN + 1)
-               return -EINVAL;
-
-       memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
-       ie = (struct mrvl_meshie *) &cmd.data[0];
-
-       /* fetch all other Information Element parameters */
-       ret = mesh_get_default_parameters(dev, &defs);
-
-       cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
-
-       /* transfer IE elements */
-       memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
-
-       len = count - 1;
-       memcpy(ie->val.mesh_id, buf, len);
-       /* SSID len */
-       ie->val.mesh_id_len = len;
-       /* IE len */
-       ie->len = sizeof(struct mrvl_meshie_val) - IEEE80211_MAX_SSID_LEN + len;
-
-       ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
-                                  CMD_TYPE_MESH_SET_MESH_IE);
-       if (ret)
-               return ret;
-
-       return strlen(buf);
-}
-
-/**
- * protocol_id_get - Get function for sysfs attribute protocol_id
- * @dev: the &struct device
- * @attr: device attributes
- * @buf: buffer where data will be returned
- */
-static ssize_t protocol_id_get(struct device *dev,
-                              struct device_attribute *attr, char *buf)
-{
-       struct mrvl_mesh_defaults defs;
-       int ret;
-
-       ret = mesh_get_default_parameters(dev, &defs);
-
-       if (ret)
-               return ret;
-
-       return snprintf(buf, 5, "%d\n", defs.meshie.val.active_protocol_id);
-}
-
-/**
- * protocol_id_set - Set function for sysfs attribute protocol_id
- * @dev: the &struct device
- * @attr: device attributes
- * @buf: buffer that contains new attribute value
- * @count: size of buffer
- */
-static ssize_t protocol_id_set(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t count)
-{
-       struct cmd_ds_mesh_config cmd;
-       struct mrvl_mesh_defaults defs;
-       struct mrvl_meshie *ie;
-       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
-       uint32_t datum;
-       int ret;
-
-       memset(&cmd, 0, sizeof(cmd));
-       ret = sscanf(buf, "%d", &datum);
-       if ((ret != 1) || (datum > 255))
-               return -EINVAL;
-
-       /* fetch all other Information Element parameters */
-       ret = mesh_get_default_parameters(dev, &defs);
-
-       cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
-
-       /* transfer IE elements */
-       ie = (struct mrvl_meshie *) &cmd.data[0];
-       memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
-       /* update protocol id */
-       ie->val.active_protocol_id = datum;
-
-       ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
-                                  CMD_TYPE_MESH_SET_MESH_IE);
-       if (ret)
-               return ret;
-
-       return strlen(buf);
-}
-
-/**
- * metric_id_get - Get function for sysfs attribute metric_id
- * @dev: the &struct device
- * @attr: device attributes
- * @buf: buffer where data will be returned
- */
-static ssize_t metric_id_get(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct mrvl_mesh_defaults defs;
-       int ret;
-
-       ret = mesh_get_default_parameters(dev, &defs);
-
-       if (ret)
-               return ret;
-
-       return snprintf(buf, 5, "%d\n", defs.meshie.val.active_metric_id);
-}
-
-/**
- * metric_id_set - Set function for sysfs attribute metric_id
- * @dev: the &struct device
- * @attr: device attributes
- * @buf: buffer that contains new attribute value
- * @count: size of buffer
- */
-static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
-                            const char *buf, size_t count)
-{
-       struct cmd_ds_mesh_config cmd;
-       struct mrvl_mesh_defaults defs;
-       struct mrvl_meshie *ie;
-       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
-       uint32_t datum;
-       int ret;
-
-       memset(&cmd, 0, sizeof(cmd));
-       ret = sscanf(buf, "%d", &datum);
-       if ((ret != 1) || (datum > 255))
-               return -EINVAL;
-
-       /* fetch all other Information Element parameters */
-       ret = mesh_get_default_parameters(dev, &defs);
-
-       cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
-
-       /* transfer IE elements */
-       ie = (struct mrvl_meshie *) &cmd.data[0];
-       memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
-       /* update metric id */
-       ie->val.active_metric_id = datum;
-
-       ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
-                                  CMD_TYPE_MESH_SET_MESH_IE);
-       if (ret)
-               return ret;
-
-       return strlen(buf);
-}
-
-/**
- * capability_get - Get function for sysfs attribute capability
- * @dev: the &struct device
- * @attr: device attributes
- * @buf: buffer where data will be returned
- */
-static ssize_t capability_get(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct mrvl_mesh_defaults defs;
-       int ret;
-
-       ret = mesh_get_default_parameters(dev, &defs);
-
-       if (ret)
-               return ret;
-
-       return snprintf(buf, 5, "%d\n", defs.meshie.val.mesh_capability);
-}
-
-/**
- * capability_set - Set function for sysfs attribute capability
- * @dev: the &struct device
- * @attr: device attributes
- * @buf: buffer that contains new attribute value
- * @count: size of buffer
- */
-static ssize_t capability_set(struct device *dev, struct device_attribute *attr,
-                             const char *buf, size_t count)
-{
-       struct cmd_ds_mesh_config cmd;
-       struct mrvl_mesh_defaults defs;
-       struct mrvl_meshie *ie;
-       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
-       uint32_t datum;
-       int ret;
-
-       memset(&cmd, 0, sizeof(cmd));
-       ret = sscanf(buf, "%d", &datum);
-       if ((ret != 1) || (datum > 255))
-               return -EINVAL;
-
-       /* fetch all other Information Element parameters */
-       ret = mesh_get_default_parameters(dev, &defs);
-
-       cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
-
-       /* transfer IE elements */
-       ie = (struct mrvl_meshie *) &cmd.data[0];
-       memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
-       /* update value */
-       ie->val.mesh_capability = datum;
-
-       ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
-                                  CMD_TYPE_MESH_SET_MESH_IE);
-       if (ret)
-               return ret;
-
-       return strlen(buf);
-}
-
-
-static DEVICE_ATTR(bootflag, 0644, bootflag_get, bootflag_set);
-static DEVICE_ATTR(boottime, 0644, boottime_get, boottime_set);
-static DEVICE_ATTR(channel, 0644, channel_get, channel_set);
-static DEVICE_ATTR(mesh_id, 0644, mesh_id_get, mesh_id_set);
-static DEVICE_ATTR(protocol_id, 0644, protocol_id_get, protocol_id_set);
-static DEVICE_ATTR(metric_id, 0644, metric_id_get, metric_id_set);
-static DEVICE_ATTR(capability, 0644, capability_get, capability_set);
-
-static struct attribute *boot_opts_attrs[] = {
-       &dev_attr_bootflag.attr,
-       &dev_attr_boottime.attr,
-       &dev_attr_channel.attr,
-       NULL
-};
-
-static const struct attribute_group boot_opts_group = {
-       .name = "boot_options",
-       .attrs = boot_opts_attrs,
-};
-
-static struct attribute *mesh_ie_attrs[] = {
-       &dev_attr_mesh_id.attr,
-       &dev_attr_protocol_id.attr,
-       &dev_attr_metric_id.attr,
-       &dev_attr_capability.attr,
-       NULL
-};
-
-static const struct attribute_group mesh_ie_group = {
-       .name = "mesh_ie",
-       .attrs = mesh_ie_attrs,
-};
-
-static void lbs_persist_config_init(struct net_device *dev)
-{
-       int ret;
-       ret = sysfs_create_group(&(dev->dev.kobj), &boot_opts_group);
-       ret = sysfs_create_group(&(dev->dev.kobj), &mesh_ie_group);
-}
-
-static void lbs_persist_config_remove(struct net_device *dev)
-{
-       sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group);
-       sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group);
-}
-
-
-/***************************************************************************
- * Initializing and starting, stopping mesh
- */
-
-/*
- * Check mesh FW version and appropriately send the mesh start
- * command
- */
-int lbs_init_mesh(struct lbs_private *priv)
-{
-       int ret = 0;
-
-       lbs_deb_enter(LBS_DEB_MESH);
-
-       /* Determine mesh_fw_ver from fwrelease and fwcapinfo */
-       /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
-       /* 5.110.22 have mesh command with 0xa3 command id */
-       /* 10.0.0.p0 FW brings in mesh config command with different id */
-       /* Check FW version MSB and initialize mesh_fw_ver */
-       if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) {
-               /* Enable mesh, if supported, and work out which TLV it uses.
-                  0x100 + 291 is an unofficial value used in 5.110.20.pXX
-                  0x100 + 37 is the official value used in 5.110.21.pXX
-                  but we check them in that order because 20.pXX doesn't
-                  give an error -- it just silently fails. */
-
-               /* 5.110.20.pXX firmware will fail the command if the channel
-                  doesn't match the existing channel. But only if the TLV
-                  is correct. If the channel is wrong, _BOTH_ versions will
-                  give an error to 0x100+291, and allow 0x100+37 to succeed.
-                  It's just that 5.110.20.pXX will not have done anything
-                  useful */
-
-               priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID;
-               if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1)) {
-                       priv->mesh_tlv = TLV_TYPE_MESH_ID;
-                       if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1))
-                               priv->mesh_tlv = 0;
-               }
-       } else
-       if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
-               (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)) {
-               /* 10.0.0.pXX new firmwares should succeed with TLV
-                * 0x100+37; Do not invoke command with old TLV.
-                */
-               priv->mesh_tlv = TLV_TYPE_MESH_ID;
-               if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1))
-                       priv->mesh_tlv = 0;
-       }
-
-       /* Stop meshing until interface is brought up */
-       lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, 1);
-
-       if (priv->mesh_tlv) {
-               sprintf(priv->mesh_ssid, "mesh");
-               priv->mesh_ssid_len = 4;
-               ret = 1;
-       }
-
-       lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
-       return ret;
-}
-
-void lbs_start_mesh(struct lbs_private *priv)
-{
-       lbs_add_mesh(priv);
-
-       if (device_create_file(&priv->dev->dev, &dev_attr_lbs_mesh))
-               netdev_err(priv->dev, "cannot register lbs_mesh attribute\n");
-}
-
-int lbs_deinit_mesh(struct lbs_private *priv)
-{
-       struct net_device *dev = priv->dev;
-       int ret = 0;
-
-       lbs_deb_enter(LBS_DEB_MESH);
-
-       if (priv->mesh_tlv) {
-               device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
-               ret = 1;
-       }
-
-       lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
-       return ret;
-}
-
-
-/**
- * lbs_mesh_stop - close the mshX interface
- *
- * @dev:       A pointer to &net_device structure
- * returns:    0
- */
-static int lbs_mesh_stop(struct net_device *dev)
-{
-       struct lbs_private *priv = dev->ml_priv;
-
-       lbs_deb_enter(LBS_DEB_MESH);
-       lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP,
-               lbs_mesh_get_channel(priv));
-
-       spin_lock_irq(&priv->driver_lock);
-
-       netif_stop_queue(dev);
-       netif_carrier_off(dev);
-
-       spin_unlock_irq(&priv->driver_lock);
-
-       lbs_update_mcast(priv);
-       if (!lbs_iface_active(priv))
-               lbs_stop_iface(priv);
-
-       lbs_deb_leave(LBS_DEB_MESH);
-       return 0;
-}
-
-/**
- * lbs_mesh_dev_open - open the mshX interface
- *
- * @dev:       A pointer to &net_device structure
- * returns:    0 or -EBUSY if monitor mode active
- */
-static int lbs_mesh_dev_open(struct net_device *dev)
-{
-       struct lbs_private *priv = dev->ml_priv;
-       int ret = 0;
-
-       lbs_deb_enter(LBS_DEB_NET);
-       if (!priv->iface_running) {
-               ret = lbs_start_iface(priv);
-               if (ret)
-                       goto out;
-       }
-
-       spin_lock_irq(&priv->driver_lock);
-
-       if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
-               ret = -EBUSY;
-               spin_unlock_irq(&priv->driver_lock);
-               goto out;
-       }
-
-       netif_carrier_on(dev);
-
-       if (!priv->tx_pending_len)
-               netif_wake_queue(dev);
-
-       spin_unlock_irq(&priv->driver_lock);
-
-       ret = lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
-               lbs_mesh_get_channel(priv));
-
-out:
-       lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
-       return ret;
-}
-
-static const struct net_device_ops mesh_netdev_ops = {
-       .ndo_open               = lbs_mesh_dev_open,
-       .ndo_stop               = lbs_mesh_stop,
-       .ndo_start_xmit         = lbs_hard_start_xmit,
-       .ndo_set_mac_address    = lbs_set_mac_address,
-       .ndo_set_rx_mode        = lbs_set_multicast_list,
-};
-
-/**
- * lbs_add_mesh - add mshX interface
- *
- * @priv:      A pointer to the &struct lbs_private structure
- * returns:    0 if successful, -X otherwise
- */
-static int lbs_add_mesh(struct lbs_private *priv)
-{
-       struct net_device *mesh_dev = NULL;
-       struct wireless_dev *mesh_wdev;
-       int ret = 0;
-
-       lbs_deb_enter(LBS_DEB_MESH);
-
-       /* Allocate a virtual mesh device */
-       mesh_wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
-       if (!mesh_wdev) {
-               lbs_deb_mesh("init mshX wireless device failed\n");
-               ret = -ENOMEM;
-               goto done;
-       }
-
-       mesh_dev = alloc_netdev(0, "msh%d", NET_NAME_UNKNOWN, ether_setup);
-       if (!mesh_dev) {
-               lbs_deb_mesh("init mshX device failed\n");
-               ret = -ENOMEM;
-               goto err_free_wdev;
-       }
-
-       mesh_wdev->iftype = NL80211_IFTYPE_MESH_POINT;
-       mesh_wdev->wiphy = priv->wdev->wiphy;
-       mesh_wdev->netdev = mesh_dev;
-
-       mesh_dev->ml_priv = priv;
-       mesh_dev->ieee80211_ptr = mesh_wdev;
-       priv->mesh_dev = mesh_dev;
-
-       mesh_dev->netdev_ops = &mesh_netdev_ops;
-       mesh_dev->ethtool_ops = &lbs_ethtool_ops;
-       eth_hw_addr_inherit(mesh_dev, priv->dev);
-
-       SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent);
-
-       mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
-       /* Register virtual mesh interface */
-       ret = register_netdev(mesh_dev);
-       if (ret) {
-               pr_err("cannot register mshX virtual interface\n");
-               goto err_free_netdev;
-       }
-
-       ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
-       if (ret)
-               goto err_unregister;
-
-       lbs_persist_config_init(mesh_dev);
-
-       /* Everything successful */
-       ret = 0;
-       goto done;
-
-err_unregister:
-       unregister_netdev(mesh_dev);
-
-err_free_netdev:
-       free_netdev(mesh_dev);
-
-err_free_wdev:
-       kfree(mesh_wdev);
-
-done:
-       lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
-       return ret;
-}
-
-void lbs_remove_mesh(struct lbs_private *priv)
-{
-       struct net_device *mesh_dev;
-
-       mesh_dev = priv->mesh_dev;
-       if (!mesh_dev)
-               return;
-
-       lbs_deb_enter(LBS_DEB_MESH);
-       netif_stop_queue(mesh_dev);
-       netif_carrier_off(mesh_dev);
-       sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
-       lbs_persist_config_remove(mesh_dev);
-       unregister_netdev(mesh_dev);
-       priv->mesh_dev = NULL;
-       kfree(mesh_dev->ieee80211_ptr);
-       free_netdev(mesh_dev);
-       lbs_deb_leave(LBS_DEB_MESH);
-}
-
-
-/***************************************************************************
- * Sending and receiving
- */
-struct net_device *lbs_mesh_set_dev(struct lbs_private *priv,
-       struct net_device *dev, struct rxpd *rxpd)
-{
-       if (priv->mesh_dev) {
-               if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID) {
-                       if (rxpd->rx_control & RxPD_MESH_FRAME)
-                               dev = priv->mesh_dev;
-               } else if (priv->mesh_tlv == TLV_TYPE_MESH_ID) {
-                       if (rxpd->u.bss.bss_num == MESH_IFACE_ID)
-                               dev = priv->mesh_dev;
-               }
-       }
-       return dev;
-}
-
-
-void lbs_mesh_set_txpd(struct lbs_private *priv,
-       struct net_device *dev, struct txpd *txpd)
-{
-       if (dev == priv->mesh_dev) {
-               if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID)
-                       txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
-               else if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
-                       txpd->u.bss.bss_num = MESH_IFACE_ID;
-       }
-}
-
-
-/***************************************************************************
- * Ethtool related
- */
-
-static const char * const mesh_stat_strings[] = {
-                       "drop_duplicate_bcast",
-                       "drop_ttl_zero",
-                       "drop_no_fwd_route",
-                       "drop_no_buffers",
-                       "fwded_unicast_cnt",
-                       "fwded_bcast_cnt",
-                       "drop_blind_table",
-                       "tx_failed_cnt"
-};
-
-void lbs_mesh_ethtool_get_stats(struct net_device *dev,
-       struct ethtool_stats *stats, uint64_t *data)
-{
-       struct lbs_private *priv = dev->ml_priv;
-       struct cmd_ds_mesh_access mesh_access;
-       int ret;
-
-       lbs_deb_enter(LBS_DEB_ETHTOOL);
-
-       /* Get Mesh Statistics */
-       ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_STATS, &mesh_access);
-
-       if (ret) {
-               memset(data, 0, MESH_STATS_NUM*(sizeof(uint64_t)));
-               return;
-       }
-
-       priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]);
-       priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]);
-       priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]);
-       priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]);
-       priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]);
-       priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]);
-       priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]);
-       priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]);
-
-       data[0] = priv->mstats.fwd_drop_rbt;
-       data[1] = priv->mstats.fwd_drop_ttl;
-       data[2] = priv->mstats.fwd_drop_noroute;
-       data[3] = priv->mstats.fwd_drop_nobuf;
-       data[4] = priv->mstats.fwd_unicast_cnt;
-       data[5] = priv->mstats.fwd_bcast_cnt;
-       data[6] = priv->mstats.drop_blind;
-       data[7] = priv->mstats.tx_failed_cnt;
-
-       lbs_deb_enter(LBS_DEB_ETHTOOL);
-}
-
-int lbs_mesh_ethtool_get_sset_count(struct net_device *dev, int sset)
-{
-       struct lbs_private *priv = dev->ml_priv;
-
-       if (sset == ETH_SS_STATS && dev == priv->mesh_dev)
-               return MESH_STATS_NUM;
-
-       return -EOPNOTSUPP;
-}
-
-void lbs_mesh_ethtool_get_strings(struct net_device *dev,
-       uint32_t stringset, uint8_t *s)
-{
-       int i;
-
-       lbs_deb_enter(LBS_DEB_ETHTOOL);
-
-       switch (stringset) {
-       case ETH_SS_STATS:
-               for (i = 0; i < MESH_STATS_NUM; i++) {
-                       memcpy(s + i * ETH_GSTRING_LEN,
-                                       mesh_stat_strings[i],
-                                       ETH_GSTRING_LEN);
-               }
-               break;
-       }
-       lbs_deb_enter(LBS_DEB_ETHTOOL);
-}
diff --git a/drivers/net/wireless/libertas/mesh.h b/drivers/net/wireless/libertas/mesh.h
deleted file mode 100644 (file)
index 6603f34..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Contains all definitions needed for the Libertas' MESH implementation.
- */
-#ifndef _LBS_MESH_H_
-#define _LBS_MESH_H_
-
-
-#include <net/iw_handler.h>
-#include <net/lib80211.h>
-
-#include "host.h"
-#include "dev.h"
-
-#ifdef CONFIG_LIBERTAS_MESH
-
-struct net_device;
-
-int lbs_init_mesh(struct lbs_private *priv);
-void lbs_start_mesh(struct lbs_private *priv);
-int lbs_deinit_mesh(struct lbs_private *priv);
-
-void lbs_remove_mesh(struct lbs_private *priv);
-
-static inline bool lbs_mesh_activated(struct lbs_private *priv)
-{
-       /* Mesh SSID is only programmed after successful init */
-       return priv->mesh_ssid_len != 0;
-}
-
-int lbs_mesh_set_channel(struct lbs_private *priv, u8 channel);
-
-/* Sending / Receiving */
-
-struct rxpd;
-struct txpd;
-
-struct net_device *lbs_mesh_set_dev(struct lbs_private *priv,
-       struct net_device *dev, struct rxpd *rxpd);
-void lbs_mesh_set_txpd(struct lbs_private *priv,
-       struct net_device *dev, struct txpd *txpd);
-
-
-/* Command handling */
-
-struct cmd_ds_command;
-struct cmd_ds_mesh_access;
-struct cmd_ds_mesh_config;
-
-
-/* Ethtool statistics */
-
-struct ethtool_stats;
-
-void lbs_mesh_ethtool_get_stats(struct net_device *dev,
-       struct ethtool_stats *stats, uint64_t *data);
-int lbs_mesh_ethtool_get_sset_count(struct net_device *dev, int sset);
-void lbs_mesh_ethtool_get_strings(struct net_device *dev,
-       uint32_t stringset, uint8_t *s);
-
-
-#else
-
-#define lbs_init_mesh(priv)
-#define lbs_deinit_mesh(priv)
-#define lbs_start_mesh(priv)
-#define lbs_add_mesh(priv)
-#define lbs_remove_mesh(priv)
-#define lbs_mesh_set_dev(priv, dev, rxpd) (dev)
-#define lbs_mesh_set_txpd(priv, dev, txpd)
-#define lbs_mesh_set_channel(priv, channel) (0)
-#define lbs_mesh_activated(priv) (false)
-
-#endif
-
-
-
-#endif
diff --git a/drivers/net/wireless/libertas/radiotap.h b/drivers/net/wireless/libertas/radiotap.h
deleted file mode 100644 (file)
index b3c8ea6..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#include <net/ieee80211_radiotap.h>
-
-struct tx_radiotap_hdr {
-       struct ieee80211_radiotap_header hdr;
-       u8 rate;
-       u8 txpower;
-       u8 rts_retries;
-       u8 data_retries;
-} __packed;
-
-#define TX_RADIOTAP_PRESENT (                          \
-       (1 << IEEE80211_RADIOTAP_RATE) |                \
-       (1 << IEEE80211_RADIOTAP_DBM_TX_POWER) |        \
-       (1 << IEEE80211_RADIOTAP_RTS_RETRIES) |         \
-       (1 << IEEE80211_RADIOTAP_DATA_RETRIES)  |       \
-       0)
-
-#define IEEE80211_FC_VERSION_MASK    0x0003
-#define IEEE80211_FC_TYPE_MASK       0x000c
-#define IEEE80211_FC_TYPE_MGT        0x0000
-#define IEEE80211_FC_TYPE_CTL        0x0004
-#define IEEE80211_FC_TYPE_DATA       0x0008
-#define IEEE80211_FC_SUBTYPE_MASK    0x00f0
-#define IEEE80211_FC_TOFROMDS_MASK   0x0300
-#define IEEE80211_FC_TODS_MASK       0x0100
-#define IEEE80211_FC_FROMDS_MASK     0x0200
-#define IEEE80211_FC_NODS            0x0000
-#define IEEE80211_FC_TODS            0x0100
-#define IEEE80211_FC_FROMDS          0x0200
-#define IEEE80211_FC_DSTODS          0x0300
-
-struct rx_radiotap_hdr {
-       struct ieee80211_radiotap_header hdr;
-       u8 flags;
-       u8 rate;
-       u8 antsignal;
-} __packed;
-
-#define RX_RADIOTAP_PRESENT (                  \
-       (1 << IEEE80211_RADIOTAP_FLAGS) |       \
-       (1 << IEEE80211_RADIOTAP_RATE) |        \
-       (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) |\
-       0)
-
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c
deleted file mode 100644 (file)
index e446fed..0000000
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * This file contains the handling of RX in wlan driver.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/etherdevice.h>
-#include <linux/hardirq.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/export.h>
-#include <net/cfg80211.h>
-
-#include "defs.h"
-#include "host.h"
-#include "radiotap.h"
-#include "decl.h"
-#include "dev.h"
-#include "mesh.h"
-
-struct eth803hdr {
-       u8 dest_addr[6];
-       u8 src_addr[6];
-       u16 h803_len;
-} __packed;
-
-struct rfc1042hdr {
-       u8 llc_dsap;
-       u8 llc_ssap;
-       u8 llc_ctrl;
-       u8 snap_oui[3];
-       u16 snap_type;
-} __packed;
-
-struct rxpackethdr {
-       struct eth803hdr eth803_hdr;
-       struct rfc1042hdr rfc1042_hdr;
-} __packed;
-
-struct rx80211packethdr {
-       struct rxpd rx_pd;
-       void *eth80211_hdr;
-} __packed;
-
-static int process_rxed_802_11_packet(struct lbs_private *priv,
-       struct sk_buff *skb);
-
-/**
- * lbs_process_rxed_packet - processes received packet and forwards it
- * to kernel/upper layer
- *
- * @priv:      A pointer to &struct lbs_private
- * @skb:       A pointer to skb which includes the received packet
- * returns:    0 or -1
- */
-int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
-{
-       int ret = 0;
-       struct net_device *dev = priv->dev;
-       struct rxpackethdr *p_rx_pkt;
-       struct rxpd *p_rx_pd;
-       int hdrchop;
-       struct ethhdr *p_ethhdr;
-       static const u8 rfc1042_eth_hdr[] = {
-               0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00
-       };
-
-       lbs_deb_enter(LBS_DEB_RX);
-
-       BUG_ON(!skb);
-
-       skb->ip_summed = CHECKSUM_NONE;
-
-       if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
-               ret = process_rxed_802_11_packet(priv, skb);
-               goto done;
-       }
-
-       p_rx_pd = (struct rxpd *) skb->data;
-       p_rx_pkt = (struct rxpackethdr *) ((u8 *)p_rx_pd +
-               le32_to_cpu(p_rx_pd->pkt_ptr));
-
-       dev = lbs_mesh_set_dev(priv, dev, p_rx_pd);
-
-       lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data,
-                min_t(unsigned int, skb->len, 100));
-
-       if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
-               lbs_deb_rx("rx err: frame received with bad length\n");
-               dev->stats.rx_length_errors++;
-               ret = -EINVAL;
-               dev_kfree_skb(skb);
-               goto done;
-       }
-
-       lbs_deb_rx("rx data: skb->len - pkt_ptr = %d-%zd = %zd\n",
-               skb->len, (size_t)le32_to_cpu(p_rx_pd->pkt_ptr),
-               skb->len - (size_t)le32_to_cpu(p_rx_pd->pkt_ptr));
-
-       lbs_deb_hex(LBS_DEB_RX, "RX Data: Dest", p_rx_pkt->eth803_hdr.dest_addr,
-               sizeof(p_rx_pkt->eth803_hdr.dest_addr));
-       lbs_deb_hex(LBS_DEB_RX, "RX Data: Src", p_rx_pkt->eth803_hdr.src_addr,
-               sizeof(p_rx_pkt->eth803_hdr.src_addr));
-
-       if (memcmp(&p_rx_pkt->rfc1042_hdr,
-                  rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) {
-               /*
-                *  Replace the 803 header and rfc1042 header (llc/snap) with an
-                *    EthernetII header, keep the src/dst and snap_type (ethertype)
-                *
-                *  The firmware only passes up SNAP frames converting
-                *    all RX Data from 802.11 to 802.2/LLC/SNAP frames.
-                *
-                *  To create the Ethernet II, just move the src, dst address right
-                *    before the snap_type.
-                */
-               p_ethhdr = (struct ethhdr *)
-                   ((u8 *) &p_rx_pkt->eth803_hdr
-                    + sizeof(p_rx_pkt->eth803_hdr) + sizeof(p_rx_pkt->rfc1042_hdr)
-                    - sizeof(p_rx_pkt->eth803_hdr.dest_addr)
-                    - sizeof(p_rx_pkt->eth803_hdr.src_addr)
-                    - sizeof(p_rx_pkt->rfc1042_hdr.snap_type));
-
-               memcpy(p_ethhdr->h_source, p_rx_pkt->eth803_hdr.src_addr,
-                      sizeof(p_ethhdr->h_source));
-               memcpy(p_ethhdr->h_dest, p_rx_pkt->eth803_hdr.dest_addr,
-                      sizeof(p_ethhdr->h_dest));
-
-               /* Chop off the rxpd + the excess memory from the 802.2/llc/snap header
-                *   that was removed
-                */
-               hdrchop = (u8 *)p_ethhdr - (u8 *)p_rx_pd;
-       } else {
-               lbs_deb_hex(LBS_DEB_RX, "RX Data: LLC/SNAP",
-                       (u8 *) &p_rx_pkt->rfc1042_hdr,
-                       sizeof(p_rx_pkt->rfc1042_hdr));
-
-               /* Chop off the rxpd */
-               hdrchop = (u8 *)&p_rx_pkt->eth803_hdr - (u8 *)p_rx_pd;
-       }
-
-       /* Chop off the leading header bytes so the skb points to the start of
-        *   either the reconstructed EthII frame or the 802.2/llc/snap frame
-        */
-       skb_pull(skb, hdrchop);
-
-       priv->cur_rate = lbs_fw_index_to_data_rate(p_rx_pd->rx_rate);
-
-       lbs_deb_rx("rx data: size of actual packet %d\n", skb->len);
-       dev->stats.rx_bytes += skb->len;
-       dev->stats.rx_packets++;
-
-       skb->protocol = eth_type_trans(skb, dev);
-       if (in_interrupt())
-               netif_rx(skb);
-       else
-               netif_rx_ni(skb);
-
-       ret = 0;
-done:
-       lbs_deb_leave_args(LBS_DEB_RX, "ret %d", ret);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(lbs_process_rxed_packet);
-
-/**
- * convert_mv_rate_to_radiotap - converts Tx/Rx rates from Marvell WLAN format
- * (see Table 2 in Section 3.1) to IEEE80211_RADIOTAP_RATE units (500 Kb/s)
- *
- * @rate:      Input rate
- * returns:    Output Rate (0 if invalid)
- */
-static u8 convert_mv_rate_to_radiotap(u8 rate)
-{
-       switch (rate) {
-       case 0:         /*   1 Mbps */
-               return 2;
-       case 1:         /*   2 Mbps */
-               return 4;
-       case 2:         /* 5.5 Mbps */
-               return 11;
-       case 3:         /*  11 Mbps */
-               return 22;
-       /* case 4: reserved */
-       case 5:         /*   6 Mbps */
-               return 12;
-       case 6:         /*   9 Mbps */
-               return 18;
-       case 7:         /*  12 Mbps */
-               return 24;
-       case 8:         /*  18 Mbps */
-               return 36;
-       case 9:         /*  24 Mbps */
-               return 48;
-       case 10:                /*  36 Mbps */
-               return 72;
-       case 11:                /*  48 Mbps */
-               return 96;
-       case 12:                /*  54 Mbps */
-               return 108;
-       }
-       pr_alert("Invalid Marvell WLAN rate %i\n", rate);
-       return 0;
-}
-
-/**
- * process_rxed_802_11_packet - processes a received 802.11 packet and forwards
- * it to kernel/upper layer
- *
- * @priv:      A pointer to &struct lbs_private
- * @skb:       A pointer to skb which includes the received packet
- * returns:    0 or -1
- */
-static int process_rxed_802_11_packet(struct lbs_private *priv,
-       struct sk_buff *skb)
-{
-       int ret = 0;
-       struct net_device *dev = priv->dev;
-       struct rx80211packethdr *p_rx_pkt;
-       struct rxpd *prxpd;
-       struct rx_radiotap_hdr radiotap_hdr;
-       struct rx_radiotap_hdr *pradiotap_hdr;
-
-       lbs_deb_enter(LBS_DEB_RX);
-
-       p_rx_pkt = (struct rx80211packethdr *) skb->data;
-       prxpd = &p_rx_pkt->rx_pd;
-
-       /* lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data, min(skb->len, 100)); */
-
-       if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
-               lbs_deb_rx("rx err: frame received with bad length\n");
-               dev->stats.rx_length_errors++;
-               ret = -EINVAL;
-               kfree_skb(skb);
-               goto done;
-       }
-
-       lbs_deb_rx("rx data: skb->len-sizeof(RxPd) = %d-%zd = %zd\n",
-              skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
-
-       /* create the exported radio header */
-
-       /* radiotap header */
-       memset(&radiotap_hdr, 0, sizeof(radiotap_hdr));
-       /* XXX must check radiotap_hdr.hdr.it_pad for pad */
-       radiotap_hdr.hdr.it_len = cpu_to_le16 (sizeof(struct rx_radiotap_hdr));
-       radiotap_hdr.hdr.it_present = cpu_to_le32 (RX_RADIOTAP_PRESENT);
-       radiotap_hdr.rate = convert_mv_rate_to_radiotap(prxpd->rx_rate);
-       /* XXX must check no carryout */
-       radiotap_hdr.antsignal = prxpd->snr + prxpd->nf;
-
-       /* chop the rxpd */
-       skb_pull(skb, sizeof(struct rxpd));
-
-       /* add space for the new radio header */
-       if ((skb_headroom(skb) < sizeof(struct rx_radiotap_hdr)) &&
-           pskb_expand_head(skb, sizeof(struct rx_radiotap_hdr), 0, GFP_ATOMIC)) {
-               netdev_alert(dev, "%s: couldn't pskb_expand_head\n", __func__);
-               ret = -ENOMEM;
-               kfree_skb(skb);
-               goto done;
-       }
-
-       pradiotap_hdr = (void *)skb_push(skb, sizeof(struct rx_radiotap_hdr));
-       memcpy(pradiotap_hdr, &radiotap_hdr, sizeof(struct rx_radiotap_hdr));
-
-       priv->cur_rate = lbs_fw_index_to_data_rate(prxpd->rx_rate);
-
-       lbs_deb_rx("rx data: size of actual packet %d\n", skb->len);
-       dev->stats.rx_bytes += skb->len;
-       dev->stats.rx_packets++;
-
-       skb->protocol = eth_type_trans(skb, priv->dev);
-
-       if (in_interrupt())
-               netif_rx(skb);
-       else
-               netif_rx_ni(skb);
-
-       ret = 0;
-
-done:
-       lbs_deb_leave_args(LBS_DEB_RX, "ret %d", ret);
-       return ret;
-}
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c
deleted file mode 100644 (file)
index c025f9c..0000000
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * This file contains the handling of TX in wlan driver.
- */
-#include <linux/hardirq.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/sched.h>
-#include <linux/export.h>
-#include <net/cfg80211.h>
-
-#include "host.h"
-#include "radiotap.h"
-#include "decl.h"
-#include "defs.h"
-#include "dev.h"
-#include "mesh.h"
-
-/**
- * convert_radiotap_rate_to_mv - converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE
- * units (500 Kb/s) into Marvell WLAN format (see Table 8 in Section 3.2.1)
- *
- * @rate:      Input rate
- * returns:    Output Rate (0 if invalid)
- */
-static u32 convert_radiotap_rate_to_mv(u8 rate)
-{
-       switch (rate) {
-       case 2:         /*   1 Mbps */
-               return 0 | (1 << 4);
-       case 4:         /*   2 Mbps */
-               return 1 | (1 << 4);
-       case 11:                /* 5.5 Mbps */
-               return 2 | (1 << 4);
-       case 22:                /*  11 Mbps */
-               return 3 | (1 << 4);
-       case 12:                /*   6 Mbps */
-               return 4 | (1 << 4);
-       case 18:                /*   9 Mbps */
-               return 5 | (1 << 4);
-       case 24:                /*  12 Mbps */
-               return 6 | (1 << 4);
-       case 36:                /*  18 Mbps */
-               return 7 | (1 << 4);
-       case 48:                /*  24 Mbps */
-               return 8 | (1 << 4);
-       case 72:                /*  36 Mbps */
-               return 9 | (1 << 4);
-       case 96:                /*  48 Mbps */
-               return 10 | (1 << 4);
-       case 108:               /*  54 Mbps */
-               return 11 | (1 << 4);
-       }
-       return 0;
-}
-
-/**
- * lbs_hard_start_xmit - checks the conditions and sends packet to IF
- * layer if everything is ok
- *
- * @skb:       A pointer to skb which includes TX packet
- * @dev:       A pointer to the &struct net_device
- * returns:    0 or -1
- */
-netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-       unsigned long flags;
-       struct lbs_private *priv = dev->ml_priv;
-       struct txpd *txpd;
-       char *p802x_hdr;
-       uint16_t pkt_len;
-       netdev_tx_t ret = NETDEV_TX_OK;
-
-       lbs_deb_enter(LBS_DEB_TX);
-
-       /* We need to protect against the queues being restarted before
-          we get round to stopping them */
-       spin_lock_irqsave(&priv->driver_lock, flags);
-
-       if (priv->surpriseremoved)
-               goto free;
-
-       if (!skb->len || (skb->len > MRVDRV_ETH_TX_PACKET_BUFFER_SIZE)) {
-               lbs_deb_tx("tx err: skb length %d 0 or > %zd\n",
-                      skb->len, MRVDRV_ETH_TX_PACKET_BUFFER_SIZE);
-               /* We'll never manage to send this one; drop it and return 'OK' */
-
-               dev->stats.tx_dropped++;
-               dev->stats.tx_errors++;
-               goto free;
-       }
-
-
-       netif_stop_queue(priv->dev);
-       if (priv->mesh_dev)
-               netif_stop_queue(priv->mesh_dev);
-
-       if (priv->tx_pending_len) {
-               /* This can happen if packets come in on the mesh and eth
-                  device simultaneously -- there's no mutual exclusion on
-                  hard_start_xmit() calls between devices. */
-               lbs_deb_tx("Packet on %s while busy\n", dev->name);
-               ret = NETDEV_TX_BUSY;
-               goto unlock;
-       }
-
-       priv->tx_pending_len = -1;
-       spin_unlock_irqrestore(&priv->driver_lock, flags);
-
-       lbs_deb_hex(LBS_DEB_TX, "TX Data", skb->data, min_t(unsigned int, skb->len, 100));
-
-       txpd = (void *)priv->tx_pending_buf;
-       memset(txpd, 0, sizeof(struct txpd));
-
-       p802x_hdr = skb->data;
-       pkt_len = skb->len;
-
-       if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
-               struct tx_radiotap_hdr *rtap_hdr = (void *)skb->data;
-
-               /* set txpd fields from the radiotap header */
-               txpd->tx_control = cpu_to_le32(convert_radiotap_rate_to_mv(rtap_hdr->rate));
-
-               /* skip the radiotap header */
-               p802x_hdr += sizeof(*rtap_hdr);
-               pkt_len -= sizeof(*rtap_hdr);
-
-               /* copy destination address from 802.11 header */
-               memcpy(txpd->tx_dest_addr_high, p802x_hdr + 4, ETH_ALEN);
-       } else {
-               /* copy destination address from 802.3 header */
-               memcpy(txpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN);
-       }
-
-       txpd->tx_packet_length = cpu_to_le16(pkt_len);
-       txpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd));
-
-       lbs_mesh_set_txpd(priv, dev, txpd);
-
-       lbs_deb_hex(LBS_DEB_TX, "txpd", (u8 *) &txpd, sizeof(struct txpd));
-
-       lbs_deb_hex(LBS_DEB_TX, "Tx Data", (u8 *) p802x_hdr, le16_to_cpu(txpd->tx_packet_length));
-
-       memcpy(&txpd[1], p802x_hdr, le16_to_cpu(txpd->tx_packet_length));
-
-       spin_lock_irqsave(&priv->driver_lock, flags);
-       priv->tx_pending_len = pkt_len + sizeof(struct txpd);
-
-       lbs_deb_tx("%s lined up packet\n", __func__);
-
-       dev->stats.tx_packets++;
-       dev->stats.tx_bytes += skb->len;
-
-       if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
-               /* Keep the skb to echo it back once Tx feedback is
-                  received from FW */
-               skb_orphan(skb);
-
-               /* Keep the skb around for when we get feedback */
-               priv->currenttxskb = skb;
-       } else {
- free:
-               dev_kfree_skb_any(skb);
-       }
-
- unlock:
-       spin_unlock_irqrestore(&priv->driver_lock, flags);
-       wake_up(&priv->waitq);
-
-       lbs_deb_leave_args(LBS_DEB_TX, "ret %d", ret);
-       return ret;
-}
-
-/**
- * lbs_send_tx_feedback - sends to the host the last transmitted packet,
- * filling the radiotap headers with transmission information.
- *
- * @priv:      A pointer to &struct lbs_private structure
- * @try_count: A 32-bit value containing transmission retry status.
- *
- * returns:    void
- */
-void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count)
-{
-       struct tx_radiotap_hdr *radiotap_hdr;
-
-       if (priv->wdev->iftype != NL80211_IFTYPE_MONITOR ||
-           priv->currenttxskb == NULL)
-               return;
-
-       radiotap_hdr = (struct tx_radiotap_hdr *)priv->currenttxskb->data;
-
-       radiotap_hdr->data_retries = try_count ?
-               (1 + priv->txretrycount - try_count) : 0;
-
-       priv->currenttxskb->protocol = eth_type_trans(priv->currenttxskb,
-                                                     priv->dev);
-       netif_rx(priv->currenttxskb);
-
-       priv->currenttxskb = NULL;
-
-       if (priv->connect_status == LBS_CONNECTED)
-               netif_wake_queue(priv->dev);
-
-       if (priv->mesh_dev && netif_running(priv->mesh_dev))
-               netif_wake_queue(priv->mesh_dev);
-}
-EXPORT_SYMBOL_GPL(lbs_send_tx_feedback);
diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h
deleted file mode 100644 (file)
index cf1d9b0..0000000
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * This header file contains definition for global types
- */
-#ifndef _LBS_TYPES_H_
-#define _LBS_TYPES_H_
-
-#include <linux/if_ether.h>
-#include <linux/ieee80211.h>
-#include <asm/byteorder.h>
-
-struct ieee_ie_header {
-       u8 id;
-       u8 len;
-} __packed;
-
-struct ieee_ie_cf_param_set {
-       struct ieee_ie_header header;
-
-       u8 cfpcnt;
-       u8 cfpperiod;
-       __le16 cfpmaxduration;
-       __le16 cfpdurationremaining;
-} __packed;
-
-
-struct ieee_ie_ibss_param_set {
-       struct ieee_ie_header header;
-
-       __le16 atimwindow;
-} __packed;
-
-union ieee_ss_param_set {
-       struct ieee_ie_cf_param_set cf;
-       struct ieee_ie_ibss_param_set ibss;
-} __packed;
-
-struct ieee_ie_fh_param_set {
-       struct ieee_ie_header header;
-
-       __le16 dwelltime;
-       u8 hopset;
-       u8 hoppattern;
-       u8 hopindex;
-} __packed;
-
-struct ieee_ie_ds_param_set {
-       struct ieee_ie_header header;
-
-       u8 channel;
-} __packed;
-
-union ieee_phy_param_set {
-       struct ieee_ie_fh_param_set fh;
-       struct ieee_ie_ds_param_set ds;
-} __packed;
-
-/* TLV  type ID definition */
-#define PROPRIETARY_TLV_BASE_ID                0x0100
-
-/* Terminating TLV type */
-#define MRVL_TERMINATE_TLV_ID          0xffff
-
-#define TLV_TYPE_SSID                          0x0000
-#define TLV_TYPE_RATES                         0x0001
-#define TLV_TYPE_PHY_FH                                0x0002
-#define TLV_TYPE_PHY_DS                                0x0003
-#define TLV_TYPE_CF                                0x0004
-#define TLV_TYPE_IBSS                          0x0006
-
-#define TLV_TYPE_DOMAIN                                0x0007
-
-#define TLV_TYPE_POWER_CAPABILITY      0x0021
-
-#define TLV_TYPE_KEY_MATERIAL       (PROPRIETARY_TLV_BASE_ID + 0)
-#define TLV_TYPE_CHANLIST           (PROPRIETARY_TLV_BASE_ID + 1)
-#define TLV_TYPE_NUMPROBES          (PROPRIETARY_TLV_BASE_ID + 2)
-#define TLV_TYPE_RSSI_LOW           (PROPRIETARY_TLV_BASE_ID + 4)
-#define TLV_TYPE_SNR_LOW            (PROPRIETARY_TLV_BASE_ID + 5)
-#define TLV_TYPE_FAILCOUNT          (PROPRIETARY_TLV_BASE_ID + 6)
-#define TLV_TYPE_BCNMISS            (PROPRIETARY_TLV_BASE_ID + 7)
-#define TLV_TYPE_LED_GPIO           (PROPRIETARY_TLV_BASE_ID + 8)
-#define TLV_TYPE_LEDBEHAVIOR        (PROPRIETARY_TLV_BASE_ID + 9)
-#define TLV_TYPE_PASSTHROUGH        (PROPRIETARY_TLV_BASE_ID + 10)
-#define TLV_TYPE_REASSOCAP          (PROPRIETARY_TLV_BASE_ID + 11)
-#define TLV_TYPE_POWER_TBL_2_4GHZ   (PROPRIETARY_TLV_BASE_ID + 12)
-#define TLV_TYPE_POWER_TBL_5GHZ     (PROPRIETARY_TLV_BASE_ID + 13)
-#define TLV_TYPE_BCASTPROBE        (PROPRIETARY_TLV_BASE_ID + 14)
-#define TLV_TYPE_NUMSSID_PROBE     (PROPRIETARY_TLV_BASE_ID + 15)
-#define TLV_TYPE_WMMQSTATUS        (PROPRIETARY_TLV_BASE_ID + 16)
-#define TLV_TYPE_CRYPTO_DATA       (PROPRIETARY_TLV_BASE_ID + 17)
-#define TLV_TYPE_WILDCARDSSID      (PROPRIETARY_TLV_BASE_ID + 18)
-#define TLV_TYPE_TSFTIMESTAMP      (PROPRIETARY_TLV_BASE_ID + 19)
-#define TLV_TYPE_RSSI_HIGH          (PROPRIETARY_TLV_BASE_ID + 22)
-#define TLV_TYPE_SNR_HIGH           (PROPRIETARY_TLV_BASE_ID + 23)
-#define TLV_TYPE_AUTH_TYPE          (PROPRIETARY_TLV_BASE_ID + 31)
-#define TLV_TYPE_MESH_ID            (PROPRIETARY_TLV_BASE_ID + 37)
-#define TLV_TYPE_OLD_MESH_ID        (PROPRIETARY_TLV_BASE_ID + 291)
-
-/* TLV related data structures */
-struct mrvl_ie_header {
-       __le16 type;
-       __le16 len;
-} __packed;
-
-struct mrvl_ie_data {
-       struct mrvl_ie_header header;
-       u8 Data[1];
-} __packed;
-
-struct mrvl_ie_rates_param_set {
-       struct mrvl_ie_header header;
-       u8 rates[1];
-} __packed;
-
-struct mrvl_ie_ssid_param_set {
-       struct mrvl_ie_header header;
-       u8 ssid[1];
-} __packed;
-
-struct mrvl_ie_wildcard_ssid_param_set {
-       struct mrvl_ie_header header;
-       u8 MaxSsidlength;
-       u8 ssid[1];
-} __packed;
-
-struct chanscanmode {
-#ifdef __BIG_ENDIAN_BITFIELD
-       u8 reserved_2_7:6;
-       u8 disablechanfilt:1;
-       u8 passivescan:1;
-#else
-       u8 passivescan:1;
-       u8 disablechanfilt:1;
-       u8 reserved_2_7:6;
-#endif
-} __packed;
-
-struct chanscanparamset {
-       u8 radiotype;
-       u8 channumber;
-       struct chanscanmode chanscanmode;
-       __le16 minscantime;
-       __le16 maxscantime;
-} __packed;
-
-struct mrvl_ie_chanlist_param_set {
-       struct mrvl_ie_header header;
-       struct chanscanparamset chanscanparam[1];
-} __packed;
-
-struct mrvl_ie_cf_param_set {
-       struct mrvl_ie_header header;
-       u8 cfpcnt;
-       u8 cfpperiod;
-       __le16 cfpmaxduration;
-       __le16 cfpdurationremaining;
-} __packed;
-
-struct mrvl_ie_ds_param_set {
-       struct mrvl_ie_header header;
-       u8 channel;
-} __packed;
-
-struct mrvl_ie_rsn_param_set {
-       struct mrvl_ie_header header;
-       u8 rsnie[1];
-} __packed;
-
-struct mrvl_ie_tsf_timestamp {
-       struct mrvl_ie_header header;
-       __le64 tsftable[1];
-} __packed;
-
-/* v9 and later firmware only */
-struct mrvl_ie_auth_type {
-       struct mrvl_ie_header header;
-       __le16 auth;
-} __packed;
-
-/*  Local Power capability */
-struct mrvl_ie_power_capability {
-       struct mrvl_ie_header header;
-       s8 minpower;
-       s8 maxpower;
-} __packed;
-
-/* used in CMD_802_11_SUBSCRIBE_EVENT for SNR, RSSI and Failure */
-struct mrvl_ie_thresholds {
-       struct mrvl_ie_header header;
-       u8 value;
-       u8 freq;
-} __packed;
-
-struct mrvl_ie_beacons_missed {
-       struct mrvl_ie_header header;
-       u8 beaconmissed;
-       u8 reserved;
-} __packed;
-
-struct mrvl_ie_num_probes {
-       struct mrvl_ie_header header;
-       __le16 numprobes;
-} __packed;
-
-struct mrvl_ie_bcast_probe {
-       struct mrvl_ie_header header;
-       __le16 bcastprobe;
-} __packed;
-
-struct mrvl_ie_num_ssid_probe {
-       struct mrvl_ie_header header;
-       __le16 numssidprobe;
-} __packed;
-
-struct led_pin {
-       u8 led;
-       u8 pin;
-} __packed;
-
-struct mrvl_ie_ledgpio {
-       struct mrvl_ie_header header;
-       struct led_pin ledpin[1];
-} __packed;
-
-struct led_bhv {
-       uint8_t firmwarestate;
-       uint8_t led;
-       uint8_t ledstate;
-       uint8_t ledarg;
-} __packed;
-
-
-struct mrvl_ie_ledbhv {
-       struct mrvl_ie_header header;
-       struct led_bhv ledbhv[1];
-} __packed;
-
-/*
- * Meant to be packed as the value member of a struct ieee80211_info_element.
- * Note that the len member of the ieee80211_info_element varies depending on
- * the mesh_id_len
- */
-struct mrvl_meshie_val {
-       uint8_t oui[3];
-       uint8_t type;
-       uint8_t subtype;
-       uint8_t version;
-       uint8_t active_protocol_id;
-       uint8_t active_metric_id;
-       uint8_t mesh_capability;
-       uint8_t mesh_id_len;
-       uint8_t mesh_id[IEEE80211_MAX_SSID_LEN];
-} __packed;
-
-struct mrvl_meshie {
-       u8 id, len;
-       struct mrvl_meshie_val val;
-} __packed;
-
-struct mrvl_mesh_defaults {
-       __le32 bootflag;
-       uint8_t boottime;
-       uint8_t reserved;
-       __le16 channel;
-       struct mrvl_meshie meshie;
-} __packed;
-
-#endif
diff --git a/drivers/net/wireless/marvell/Kconfig b/drivers/net/wireless/marvell/Kconfig
new file mode 100644 (file)
index 0000000..7842096
--- /dev/null
@@ -0,0 +1,16 @@
+config WLAN_VENDOR_MARVELL
+       bool "Marvell 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  cards. If you say Y, you will be asked for
+         your specific card in the following questions.
+
+if WLAN_VENDOR_MARVELL
+
+source "drivers/net/wireless/marvell/libertas/Kconfig"
+
+endif # WLAN_VENDOR_MARVELL
diff --git a/drivers/net/wireless/marvell/Makefile b/drivers/net/wireless/marvell/Makefile
new file mode 100644 (file)
index 0000000..6f7ac46
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_LIBERTAS)         += libertas/
diff --git a/drivers/net/wireless/marvell/libertas/Kconfig b/drivers/net/wireless/marvell/libertas/Kconfig
new file mode 100644 (file)
index 0000000..e6268ce
--- /dev/null
@@ -0,0 +1,45 @@
+config LIBERTAS
+       tristate "Marvell 8xxx Libertas WLAN driver support"
+       depends on CFG80211
+       select WIRELESS_EXT
+       select WEXT_SPY
+       select LIB80211
+       select FW_LOADER
+       ---help---
+         A library for Marvell Libertas 8xxx devices.
+
+config LIBERTAS_USB
+       tristate "Marvell Libertas 8388 USB 802.11b/g cards"
+       depends on 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
+       ---help---
+         A driver for Marvell Libertas 8385/8686/8688 SDIO devices.
+
+config LIBERTAS_SPI
+       tristate "Marvell Libertas 8686 SPI 802.11b/g cards"
+       depends on LIBERTAS && SPI
+       ---help---
+         A driver for Marvell Libertas 8686 SPI devices.
+
+config LIBERTAS_DEBUG
+       bool "Enable full debugging output in the Libertas module."
+       depends on LIBERTAS
+       ---help---
+         Debugging support.
+
+config LIBERTAS_MESH
+       bool "Enable mesh support"
+       depends on LIBERTAS
+       help
+         This enables Libertas' MESH support, used by e.g. the OLPC people.
diff --git a/drivers/net/wireless/marvell/libertas/LICENSE b/drivers/net/wireless/marvell/libertas/LICENSE
new file mode 100644 (file)
index 0000000..8862742
--- /dev/null
@@ -0,0 +1,16 @@
+  Copyright (c) 2003-2006, Marvell International Ltd.
+  All Rights Reserved
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms of version 2 of the GNU General Public License as
+  published by the Free Software Foundation.
+
+  This program is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
diff --git a/drivers/net/wireless/marvell/libertas/Makefile b/drivers/net/wireless/marvell/libertas/Makefile
new file mode 100644 (file)
index 0000000..eac72f7
--- /dev/null
@@ -0,0 +1,21 @@
+libertas-y += cfg.o
+libertas-y += cmd.o
+libertas-y += cmdresp.o
+libertas-y += debugfs.o
+libertas-y += ethtool.o
+libertas-y += main.o
+libertas-y += rx.o
+libertas-y += tx.o
+libertas-y += firmware.o
+libertas-$(CONFIG_LIBERTAS_MESH) += mesh.o
+
+usb8xxx-objs += if_usb.o
+libertas_cs-objs += if_cs.o
+libertas_sdio-objs += if_sdio.o
+libertas_spi-objs += if_spi.o
+
+obj-$(CONFIG_LIBERTAS)     += libertas.o
+obj-$(CONFIG_LIBERTAS_USB) += usb8xxx.o
+obj-$(CONFIG_LIBERTAS_CS)  += libertas_cs.o
+obj-$(CONFIG_LIBERTAS_SDIO) += libertas_sdio.o
+obj-$(CONFIG_LIBERTAS_SPI) += libertas_spi.o
diff --git a/drivers/net/wireless/marvell/libertas/README b/drivers/net/wireless/marvell/libertas/README
new file mode 100644 (file)
index 0000000..1a554a6
--- /dev/null
@@ -0,0 +1,239 @@
+================================================================================
+                       README for Libertas
+
+ (c) Copyright Â© 2003-2006, Marvell International Ltd.
+ All Rights Reserved
+
+ This software file (the "File") is distributed by Marvell International
+ Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ (the "License").  You may use, redistribute and/or modify this File in
+ accordance with the terms and conditions of the License, a copy of which
+ is available along with the File in the license.txt file or on the worldwide
+ web at http://www.gnu.org/licenses/gpl.txt.
+
+ THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ this warranty disclaimer.
+================================================================================
+
+=====================
+DRIVER LOADING
+=====================
+
+       o. Copy the firmware image (e.g. usb8388.bin) to /lib/firmware/
+
+       o. Load driver by using the following command:
+
+               insmod usb8388.ko [fw_name=usb8388.bin]
+
+=========================
+ETHTOOL
+=========================
+
+
+Use the -i option to retrieve version information from the driver.
+
+# ethtool -i eth0
+driver: libertas
+version: COMM-USB8388-318.p4
+firmware-version: 5.110.7
+bus-info:
+
+Use the -e option to read the EEPROM contents of the card.
+
+       Usage:
+       ethtool -e ethX [raw on|off] [offset N] [length N]
+
+       -e     retrieves and prints an EEPROM dump for the  specified  ethernet
+              device.   When raw is enabled, then it dumps the raw EEPROM data
+              to stdout. The length and offset parameters allow  dumping  cer-
+              tain portions of the EEPROM.  Default is to dump the entire EEP-
+              ROM.
+
+# ethtool -e eth0 offset 0 length 16
+Offset          Values
+------          ------
+0x0000          38 33 30 58 00 00 34 f4 00 00 10 00 00 c4 17 00
+
+========================
+DEBUGFS COMMANDS
+========================
+
+those commands are used via debugfs interface
+
+===========
+rdmac
+rdbbp
+rdrf
+       These commands are used to read the MAC, BBP and RF registers from the
+       card.  These commands take one parameter that specifies the offset
+       location that is to be read.  This parameter must be specified in
+       hexadecimal (its possible to precede preceding the number with a "0x").
+
+       Path: /sys/kernel/debug/libertas_wireless/ethX/registers/
+
+       Usage:
+               echo "0xa123" > rdmac ; cat rdmac
+               echo "0xa123" > rdbbp ; cat rdbbp
+               echo "0xa123" > rdrf ; cat rdrf
+wrmac
+wrbbp
+wrrf
+       These commands are used to write the MAC, BBP and RF registers in the
+       card.  These commands take two parameters that specify the offset
+       location and the value that is to be written. This parameters must
+       be specified in hexadecimal (its possible to precede the number
+       with a "0x").
+
+       Usage:
+               echo "0xa123 0xaa" > wrmac
+               echo "0xa123 0xaa" > wrbbp
+               echo "0xa123 0xaa" > wrrf
+
+sleepparams
+       This command is used to set the sleepclock configurations
+
+       Path: /sys/kernel/debug/libertas_wireless/ethX/
+
+       Usage:
+               cat sleepparams: reads the current sleepclock configuration
+
+               echo "p1 p2 p3 p4 p5 p6" > sleepparams: writes the sleepclock configuration.
+
+               where:
+                       p1 is Sleep clock error in ppm (0-65535)
+                       p2 is Wakeup offset in usec (0-65535)
+                       p3 is Clock stabilization time in usec (0-65535)
+                       p4 is Control periodic calibration (0-2)
+                       p5 is Control the use of external sleep clock (0-2)
+                       p6 is reserved for debug (0-65535)
+
+subscribed_events
+
+       The subscribed_events directory contains the interface for the
+       subscribed events API.
+
+       Path: /sys/kernel/debug/libertas_wireless/ethX/subscribed_events/
+
+       Each event is represented by a filename. Each filename consists of the
+       following three fields:
+       Value Frequency Subscribed
+
+       To read the current values for a given event, do:
+               cat event
+       To set the current values, do:
+               echo "60 2 1" > event
+
+       Frequency field specifies the reporting frequency for this event.
+       If it is set to 0, then the event is reported only once, and then
+       automatically unsubscribed. If it is set to 1, then the event is
+       reported every time it occurs. If it is set to N, then the event is
+       reported every Nth time it occurs.
+
+       beacon_missed
+       Value field specifies the number of consecutive missing beacons which
+       triggers the LINK_LOSS event. This event is generated only once after
+       which the firmware resets its state. At initialization, the LINK_LOSS
+       event is subscribed by default. The default value of MissedBeacons is
+       60.
+
+       failure_count
+       Value field specifies the consecutive failure count threshold which
+       triggers the generation of the MAX_FAIL event. Once this event is
+       generated, the consecutive failure count is reset to 0.
+       At initialization, the MAX_FAIL event is NOT subscribed by
+       default.
+
+       high_rssi
+       This event is generated when the average received RSSI in beacons goes
+       above a threshold, specified by Value.
+
+       low_rssi
+       This event is generated when the average received RSSI in beacons goes
+       below a threshold, specified by Value.
+
+       high_snr
+       This event is generated when the average received SNR in beacons goes
+       above a threshold, specified by Value.
+
+       low_snr
+       This event is generated when the average received SNR in beacons goes
+       below a threshold, specified by Value.
+
+extscan
+       This command is used to do a specific scan.
+
+       Path: /sys/kernel/debug/libertas_wireless/ethX/
+
+       Usage: echo "SSID" > extscan
+
+       Example:
+               echo "LINKSYS-AP" > extscan
+
+       To see the results of use getscantable command.
+
+getscantable
+
+       Display the current contents of the driver scan table (ie. get the
+       scan results).
+
+       Path: /sys/kernel/debug/libertas_wireless/ethX/
+
+       Usage:
+               cat getscantable
+
+setuserscan
+       Initiate a customized scan and retrieve the results
+
+
+       Path: /sys/kernel/debug/libertas_wireless/ethX/
+
+    Usage:
+       echo "[ARGS]" > setuserscan
+
+         where [ARGS]:
+
+      bssid=xx:xx:xx:xx:xx:xx  specify a BSSID filter for the scan
+      ssid="[SSID]"            specify a SSID filter for the scan
+      keep=[0 or 1]            keep the previous scan results (1), discard (0)
+      dur=[scan time]          time to scan for each channel in milliseconds
+      type=[1,2,3]             BSS type: 1 (Infra), 2(Adhoc), 3(Any)
+
+    Any combination of the above arguments can be supplied on the command
+    line. If dur tokens are absent, the driver default setting will be used.
+    The bssid and ssid fields, if blank, will produce an unfiltered scan.
+    The type field will default to 3 (Any) and the keep field will default
+    to 0 (Discard).
+
+    Examples:
+    1) Perform a passive scan on all channels for 20 ms per channel:
+            echo "dur=20" > setuserscan
+
+    2) Perform an active scan for a specific SSID:
+            echo "ssid="TestAP"" > setuserscan
+
+    3) Scan all available channels (B/G, A bands) for a specific BSSID, keep
+       the current scan table intact, update existing or append new scan data:
+            echo "bssid=00:50:43:20:12:82 keep=1" > setuserscan
+
+    4) Scan for all infrastructure networks.
+       Keep the previous scan table intact. Update any duplicate BSSID/SSID
+       matches with the new scan data:
+            echo "type=1 keep=1" > setuserscan
+
+    All entries in the scan table (not just the new scan data when keep=1)
+    will be displayed upon completion by use of the getscantable ioctl.
+
+hostsleep
+       This command is used to enable/disable host sleep.
+       Note: Host sleep parameters should be configured using
+       "ethtool -s ethX wol X" command before enabling host sleep.
+
+       Path: /sys/kernel/debug/libertas_wireless/ethX/
+
+       Usage:
+               cat hostsleep: reads the current hostsleep state
+               echo "1" > hostsleep : enable host sleep.
+               echo "0" > hostsleep : disable host sleep
+
diff --git a/drivers/net/wireless/marvell/libertas/cfg.c b/drivers/net/wireless/marvell/libertas/cfg.c
new file mode 100644 (file)
index 0000000..8317afd
--- /dev/null
@@ -0,0 +1,2215 @@
+/*
+ * Implement cfg80211 ("iw") support.
+ *
+ * Copyright (C) 2009 M&N Solutions GmbH, 61191 Rosbach, Germany
+ * Holger Schurig <hs4233@mail.mn-solutions.de>
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/hardirq.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/slab.h>
+#include <linux/ieee80211.h>
+#include <net/cfg80211.h>
+#include <asm/unaligned.h>
+
+#include "decl.h"
+#include "cfg.h"
+#include "cmd.h"
+#include "mesh.h"
+
+
+#define CHAN2G(_channel, _freq, _flags) {        \
+       .band             = IEEE80211_BAND_2GHZ, \
+       .center_freq      = (_freq),             \
+       .hw_value         = (_channel),          \
+       .flags            = (_flags),            \
+       .max_antenna_gain = 0,                   \
+       .max_power        = 30,                  \
+}
+
+static struct ieee80211_channel lbs_2ghz_channels[] = {
+       CHAN2G(1,  2412, 0),
+       CHAN2G(2,  2417, 0),
+       CHAN2G(3,  2422, 0),
+       CHAN2G(4,  2427, 0),
+       CHAN2G(5,  2432, 0),
+       CHAN2G(6,  2437, 0),
+       CHAN2G(7,  2442, 0),
+       CHAN2G(8,  2447, 0),
+       CHAN2G(9,  2452, 0),
+       CHAN2G(10, 2457, 0),
+       CHAN2G(11, 2462, 0),
+       CHAN2G(12, 2467, 0),
+       CHAN2G(13, 2472, 0),
+       CHAN2G(14, 2484, 0),
+};
+
+#define RATETAB_ENT(_rate, _hw_value, _flags) { \
+       .bitrate  = (_rate),                    \
+       .hw_value = (_hw_value),                \
+       .flags    = (_flags),                   \
+}
+
+
+/* Table 6 in section 3.2.1.1 */
+static struct ieee80211_rate lbs_rates[] = {
+       RATETAB_ENT(10,  0,  0),
+       RATETAB_ENT(20,  1,  0),
+       RATETAB_ENT(55,  2,  0),
+       RATETAB_ENT(110, 3,  0),
+       RATETAB_ENT(60,  9,  0),
+       RATETAB_ENT(90,  6,  0),
+       RATETAB_ENT(120, 7,  0),
+       RATETAB_ENT(180, 8,  0),
+       RATETAB_ENT(240, 9,  0),
+       RATETAB_ENT(360, 10, 0),
+       RATETAB_ENT(480, 11, 0),
+       RATETAB_ENT(540, 12, 0),
+};
+
+static struct ieee80211_supported_band lbs_band_2ghz = {
+       .channels = lbs_2ghz_channels,
+       .n_channels = ARRAY_SIZE(lbs_2ghz_channels),
+       .bitrates = lbs_rates,
+       .n_bitrates = ARRAY_SIZE(lbs_rates),
+};
+
+
+static const u32 cipher_suites[] = {
+       WLAN_CIPHER_SUITE_WEP40,
+       WLAN_CIPHER_SUITE_WEP104,
+       WLAN_CIPHER_SUITE_TKIP,
+       WLAN_CIPHER_SUITE_CCMP,
+};
+
+/* Time to stay on the channel */
+#define LBS_DWELL_PASSIVE 100
+#define LBS_DWELL_ACTIVE  40
+
+
+/***************************************************************************
+ * Misc utility functions
+ *
+ * TLVs are Marvell specific. They are very similar to IEs, they have the
+ * same structure: type, length, data*. The only difference: for IEs, the
+ * type and length are u8, but for TLVs they're __le16.
+ */
+
+/*
+ * Convert NL80211's auth_type to the one from Libertas, see chapter 5.9.1
+ * in the firmware spec
+ */
+static int lbs_auth_to_authtype(enum nl80211_auth_type auth_type)
+{
+       int ret = -ENOTSUPP;
+
+       switch (auth_type) {
+       case NL80211_AUTHTYPE_OPEN_SYSTEM:
+       case NL80211_AUTHTYPE_SHARED_KEY:
+               ret = auth_type;
+               break;
+       case NL80211_AUTHTYPE_AUTOMATIC:
+               ret = NL80211_AUTHTYPE_OPEN_SYSTEM;
+               break;
+       case NL80211_AUTHTYPE_NETWORK_EAP:
+               ret = 0x80;
+               break;
+       default:
+               /* silence compiler */
+               break;
+       }
+       return ret;
+}
+
+
+/*
+ * Various firmware commands need the list of supported rates, but with
+ * the hight-bit set for basic rates
+ */
+static int lbs_add_rates(u8 *rates)
+{
+       size_t i;
+
+       for (i = 0; i < ARRAY_SIZE(lbs_rates); i++) {
+               u8 rate = lbs_rates[i].bitrate / 5;
+               if (rate == 0x02 || rate == 0x04 ||
+                   rate == 0x0b || rate == 0x16)
+                       rate |= 0x80;
+               rates[i] = rate;
+       }
+       return ARRAY_SIZE(lbs_rates);
+}
+
+
+/***************************************************************************
+ * TLV utility functions
+ *
+ * TLVs are Marvell specific. They are very similar to IEs, they have the
+ * same structure: type, length, data*. The only difference: for IEs, the
+ * type and length are u8, but for TLVs they're __le16.
+ */
+
+
+/*
+ * Add ssid TLV
+ */
+#define LBS_MAX_SSID_TLV_SIZE                  \
+       (sizeof(struct mrvl_ie_header)          \
+        + IEEE80211_MAX_SSID_LEN)
+
+static int lbs_add_ssid_tlv(u8 *tlv, const u8 *ssid, int ssid_len)
+{
+       struct mrvl_ie_ssid_param_set *ssid_tlv = (void *)tlv;
+
+       /*
+        * TLV-ID SSID  00 00
+        * length       06 00
+        * ssid         4d 4e 54 45 53 54
+        */
+       ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID);
+       ssid_tlv->header.len = cpu_to_le16(ssid_len);
+       memcpy(ssid_tlv->ssid, ssid, ssid_len);
+       return sizeof(ssid_tlv->header) + ssid_len;
+}
+
+
+/*
+ * Add channel list TLV (section 8.4.2)
+ *
+ * Actual channel data comes from priv->wdev->wiphy->channels.
+ */
+#define LBS_MAX_CHANNEL_LIST_TLV_SIZE                                  \
+       (sizeof(struct mrvl_ie_header)                                  \
+        + (LBS_SCAN_BEFORE_NAP * sizeof(struct chanscanparamset)))
+
+static int lbs_add_channel_list_tlv(struct lbs_private *priv, u8 *tlv,
+                                   int last_channel, int active_scan)
+{
+       int chanscanparamsize = sizeof(struct chanscanparamset) *
+               (last_channel - priv->scan_channel);
+
+       struct mrvl_ie_header *header = (void *) tlv;
+
+       /*
+        * TLV-ID CHANLIST  01 01
+        * length           0e 00
+        * channel          00 01 00 00 00 64 00
+        *   radio type     00
+        *   channel           01
+        *   scan type            00
+        *   min scan time           00 00
+        *   max scan time                 64 00
+        * channel 2        00 02 00 00 00 64 00
+        *
+        */
+
+       header->type = cpu_to_le16(TLV_TYPE_CHANLIST);
+       header->len  = cpu_to_le16(chanscanparamsize);
+       tlv += sizeof(struct mrvl_ie_header);
+
+       /* lbs_deb_scan("scan: channels %d to %d\n", priv->scan_channel,
+                    last_channel); */
+       memset(tlv, 0, chanscanparamsize);
+
+       while (priv->scan_channel < last_channel) {
+               struct chanscanparamset *param = (void *) tlv;
+
+               param->radiotype = CMD_SCAN_RADIO_TYPE_BG;
+               param->channumber =
+                       priv->scan_req->channels[priv->scan_channel]->hw_value;
+               if (active_scan) {
+                       param->maxscantime = cpu_to_le16(LBS_DWELL_ACTIVE);
+               } else {
+                       param->chanscanmode.passivescan = 1;
+                       param->maxscantime = cpu_to_le16(LBS_DWELL_PASSIVE);
+               }
+               tlv += sizeof(struct chanscanparamset);
+               priv->scan_channel++;
+       }
+       return sizeof(struct mrvl_ie_header) + chanscanparamsize;
+}
+
+
+/*
+ * Add rates TLV
+ *
+ * The rates are in lbs_bg_rates[], but for the 802.11b
+ * rates the high bit is set. We add this TLV only because
+ * there's a firmware which otherwise doesn't report all
+ * APs in range.
+ */
+#define LBS_MAX_RATES_TLV_SIZE                 \
+       (sizeof(struct mrvl_ie_header)          \
+        + (ARRAY_SIZE(lbs_rates)))
+
+/* Adds a TLV with all rates the hardware supports */
+static int lbs_add_supported_rates_tlv(u8 *tlv)
+{
+       size_t i;
+       struct mrvl_ie_rates_param_set *rate_tlv = (void *)tlv;
+
+       /*
+        * TLV-ID RATES  01 00
+        * length        0e 00
+        * rates         82 84 8b 96 0c 12 18 24 30 48 60 6c
+        */
+       rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES);
+       tlv += sizeof(rate_tlv->header);
+       i = lbs_add_rates(tlv);
+       tlv += i;
+       rate_tlv->header.len = cpu_to_le16(i);
+       return sizeof(rate_tlv->header) + i;
+}
+
+/* Add common rates from a TLV and return the new end of the TLV */
+static u8 *
+add_ie_rates(u8 *tlv, const u8 *ie, int *nrates)
+{
+       int hw, ap, ap_max = ie[1];
+       u8 hw_rate;
+
+       /* Advance past IE header */
+       ie += 2;
+
+       lbs_deb_hex(LBS_DEB_ASSOC, "AP IE Rates", (u8 *) ie, ap_max);
+
+       for (hw = 0; hw < ARRAY_SIZE(lbs_rates); hw++) {
+               hw_rate = lbs_rates[hw].bitrate / 5;
+               for (ap = 0; ap < ap_max; ap++) {
+                       if (hw_rate == (ie[ap] & 0x7f)) {
+                               *tlv++ = ie[ap];
+                               *nrates = *nrates + 1;
+                       }
+               }
+       }
+       return tlv;
+}
+
+/*
+ * Adds a TLV with all rates the hardware *and* BSS supports.
+ */
+static int lbs_add_common_rates_tlv(u8 *tlv, struct cfg80211_bss *bss)
+{
+       struct mrvl_ie_rates_param_set *rate_tlv = (void *)tlv;
+       const u8 *rates_eid, *ext_rates_eid;
+       int n = 0;
+
+       rcu_read_lock();
+       rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
+       ext_rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
+
+       /*
+        * 01 00                   TLV_TYPE_RATES
+        * 04 00                   len
+        * 82 84 8b 96             rates
+        */
+       rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES);
+       tlv += sizeof(rate_tlv->header);
+
+       /* Add basic rates */
+       if (rates_eid) {
+               tlv = add_ie_rates(tlv, rates_eid, &n);
+
+               /* Add extended rates, if any */
+               if (ext_rates_eid)
+                       tlv = add_ie_rates(tlv, ext_rates_eid, &n);
+       } else {
+               lbs_deb_assoc("assoc: bss had no basic rate IE\n");
+               /* Fallback: add basic 802.11b rates */
+               *tlv++ = 0x82;
+               *tlv++ = 0x84;
+               *tlv++ = 0x8b;
+               *tlv++ = 0x96;
+               n = 4;
+       }
+       rcu_read_unlock();
+
+       rate_tlv->header.len = cpu_to_le16(n);
+       return sizeof(rate_tlv->header) + n;
+}
+
+
+/*
+ * Add auth type TLV.
+ *
+ * This is only needed for newer firmware (V9 and up).
+ */
+#define LBS_MAX_AUTH_TYPE_TLV_SIZE \
+       sizeof(struct mrvl_ie_auth_type)
+
+static int lbs_add_auth_type_tlv(u8 *tlv, enum nl80211_auth_type auth_type)
+{
+       struct mrvl_ie_auth_type *auth = (void *) tlv;
+
+       /*
+        * 1f 01  TLV_TYPE_AUTH_TYPE
+        * 01 00  len
+        * 01     auth type
+        */
+       auth->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
+       auth->header.len = cpu_to_le16(sizeof(*auth)-sizeof(auth->header));
+       auth->auth = cpu_to_le16(lbs_auth_to_authtype(auth_type));
+       return sizeof(*auth);
+}
+
+
+/*
+ * Add channel (phy ds) TLV
+ */
+#define LBS_MAX_CHANNEL_TLV_SIZE \
+       sizeof(struct mrvl_ie_header)
+
+static int lbs_add_channel_tlv(u8 *tlv, u8 channel)
+{
+       struct mrvl_ie_ds_param_set *ds = (void *) tlv;
+
+       /*
+        * 03 00  TLV_TYPE_PHY_DS
+        * 01 00  len
+        * 06     channel
+        */
+       ds->header.type = cpu_to_le16(TLV_TYPE_PHY_DS);
+       ds->header.len = cpu_to_le16(sizeof(*ds)-sizeof(ds->header));
+       ds->channel = channel;
+       return sizeof(*ds);
+}
+
+
+/*
+ * Add (empty) CF param TLV of the form:
+ */
+#define LBS_MAX_CF_PARAM_TLV_SIZE              \
+       sizeof(struct mrvl_ie_header)
+
+static int lbs_add_cf_param_tlv(u8 *tlv)
+{
+       struct mrvl_ie_cf_param_set *cf = (void *)tlv;
+
+       /*
+        * 04 00  TLV_TYPE_CF
+        * 06 00  len
+        * 00     cfpcnt
+        * 00     cfpperiod
+        * 00 00  cfpmaxduration
+        * 00 00  cfpdurationremaining
+        */
+       cf->header.type = cpu_to_le16(TLV_TYPE_CF);
+       cf->header.len = cpu_to_le16(sizeof(*cf)-sizeof(cf->header));
+       return sizeof(*cf);
+}
+
+/*
+ * Add WPA TLV
+ */
+#define LBS_MAX_WPA_TLV_SIZE                   \
+       (sizeof(struct mrvl_ie_header)          \
+        + 128 /* TODO: I guessed the size */)
+
+static int lbs_add_wpa_tlv(u8 *tlv, const u8 *ie, u8 ie_len)
+{
+       size_t tlv_len;
+
+       /*
+        * We need just convert an IE to an TLV. IEs use u8 for the header,
+        *   u8      type
+        *   u8      len
+        *   u8[]    data
+        * but TLVs use __le16 instead:
+        *   __le16  type
+        *   __le16  len
+        *   u8[]    data
+        */
+       *tlv++ = *ie++;
+       *tlv++ = 0;
+       tlv_len = *tlv++ = *ie++;
+       *tlv++ = 0;
+       while (tlv_len--)
+               *tlv++ = *ie++;
+       /* the TLV is two bytes larger than the IE */
+       return ie_len + 2;
+}
+
+/*
+ * Set Channel
+ */
+
+static int lbs_cfg_set_monitor_channel(struct wiphy *wiphy,
+                                      struct cfg80211_chan_def *chandef)
+{
+       struct lbs_private *priv = wiphy_priv(wiphy);
+       int ret = -ENOTSUPP;
+
+       lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d",
+                          chandef->chan->center_freq,
+                          cfg80211_get_chandef_type(chandef));
+
+       if (cfg80211_get_chandef_type(chandef) != NL80211_CHAN_NO_HT)
+               goto out;
+
+       ret = lbs_set_channel(priv, chandef->chan->hw_value);
+
+ out:
+       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+       return ret;
+}
+
+static int lbs_cfg_set_mesh_channel(struct wiphy *wiphy,
+                                   struct net_device *netdev,
+                                   struct ieee80211_channel *channel)
+{
+       struct lbs_private *priv = wiphy_priv(wiphy);
+       int ret = -ENOTSUPP;
+
+       lbs_deb_enter_args(LBS_DEB_CFG80211, "iface %s freq %d",
+                          netdev_name(netdev), channel->center_freq);
+
+       if (netdev != priv->mesh_dev)
+               goto out;
+
+       ret = lbs_mesh_set_channel(priv, channel->hw_value);
+
+ out:
+       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+       return ret;
+}
+
+
+
+/*
+ * Scanning
+ */
+
+/*
+ * When scanning, the firmware doesn't send a nul packet with the power-safe
+ * bit to the AP. So we cannot stay away from our current channel too long,
+ * otherwise we loose data. So take a "nap" while scanning every other
+ * while.
+ */
+#define LBS_SCAN_BEFORE_NAP 4
+
+
+/*
+ * When the firmware reports back a scan-result, it gives us an "u8 rssi",
+ * which isn't really an RSSI, as it becomes larger when moving away from
+ * the AP. Anyway, we need to convert that into mBm.
+ */
+#define LBS_SCAN_RSSI_TO_MBM(rssi) \
+       ((-(int)rssi + 3)*100)
+
+static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
+       struct cmd_header *resp)
+{
+       struct cfg80211_bss *bss;
+       struct cmd_ds_802_11_scan_rsp *scanresp = (void *)resp;
+       int bsssize;
+       const u8 *pos;
+       const u8 *tsfdesc;
+       int tsfsize;
+       int i;
+       int ret = -EILSEQ;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       bsssize = get_unaligned_le16(&scanresp->bssdescriptsize);
+
+       lbs_deb_scan("scan response: %d BSSs (%d bytes); resp size %d bytes\n",
+                       scanresp->nr_sets, bsssize, le16_to_cpu(resp->size));
+
+       if (scanresp->nr_sets == 0) {
+               ret = 0;
+               goto done;
+       }
+
+       /*
+        * The general layout of the scan response is described in chapter
+        * 5.7.1. Basically we have a common part, then any number of BSS
+        * descriptor sections. Finally we have section with the same number
+        * of TSFs.
+        *
+        * cmd_ds_802_11_scan_rsp
+        *   cmd_header
+        *   pos_size
+        *   nr_sets
+        *   bssdesc 1
+        *     bssid
+        *     rssi
+        *     timestamp
+        *     intvl
+        *     capa
+        *     IEs
+        *   bssdesc 2
+        *   bssdesc n
+        *   MrvlIEtypes_TsfFimestamp_t
+        *     TSF for BSS 1
+        *     TSF for BSS 2
+        *     TSF for BSS n
+        */
+
+       pos = scanresp->bssdesc_and_tlvbuffer;
+
+       lbs_deb_hex(LBS_DEB_SCAN, "SCAN_RSP", scanresp->bssdesc_and_tlvbuffer,
+                       scanresp->bssdescriptsize);
+
+       tsfdesc = pos + bsssize;
+       tsfsize = 4 + 8 * scanresp->nr_sets;
+       lbs_deb_hex(LBS_DEB_SCAN, "SCAN_TSF", (u8 *) tsfdesc, tsfsize);
+
+       /* Validity check: we expect a Marvell-Local TLV */
+       i = get_unaligned_le16(tsfdesc);
+       tsfdesc += 2;
+       if (i != TLV_TYPE_TSFTIMESTAMP) {
+               lbs_deb_scan("scan response: invalid TSF Timestamp %d\n", i);
+               goto done;
+       }
+
+       /*
+        * Validity check: the TLV holds TSF values with 8 bytes each, so
+        * the size in the TLV must match the nr_sets value
+        */
+       i = get_unaligned_le16(tsfdesc);
+       tsfdesc += 2;
+       if (i / 8 != scanresp->nr_sets) {
+               lbs_deb_scan("scan response: invalid number of TSF timestamp "
+                            "sets (expected %d got %d)\n", scanresp->nr_sets,
+                            i / 8);
+               goto done;
+       }
+
+       for (i = 0; i < scanresp->nr_sets; i++) {
+               const u8 *bssid;
+               const u8 *ie;
+               int left;
+               int ielen;
+               int rssi;
+               u16 intvl;
+               u16 capa;
+               int chan_no = -1;
+               const u8 *ssid = NULL;
+               u8 ssid_len = 0;
+
+               int len = get_unaligned_le16(pos);
+               pos += 2;
+
+               /* BSSID */
+               bssid = pos;
+               pos += ETH_ALEN;
+               /* RSSI */
+               rssi = *pos++;
+               /* Packet time stamp */
+               pos += 8;
+               /* Beacon interval */
+               intvl = get_unaligned_le16(pos);
+               pos += 2;
+               /* Capabilities */
+               capa = get_unaligned_le16(pos);
+               pos += 2;
+
+               /* To find out the channel, we must parse the IEs */
+               ie = pos;
+               /*
+                * 6+1+8+2+2: size of BSSID, RSSI, time stamp, beacon
+                * interval, capabilities
+                */
+               ielen = left = len - (6 + 1 + 8 + 2 + 2);
+               while (left >= 2) {
+                       u8 id, elen;
+                       id = *pos++;
+                       elen = *pos++;
+                       left -= 2;
+                       if (elen > left) {
+                               lbs_deb_scan("scan response: invalid IE fmt\n");
+                               goto done;
+                       }
+
+                       if (id == WLAN_EID_DS_PARAMS)
+                               chan_no = *pos;
+                       if (id == WLAN_EID_SSID) {
+                               ssid = pos;
+                               ssid_len = elen;
+                       }
+                       left -= elen;
+                       pos += elen;
+               }
+
+               /* No channel, no luck */
+               if (chan_no != -1) {
+                       struct wiphy *wiphy = priv->wdev->wiphy;
+                       int freq = ieee80211_channel_to_frequency(chan_no,
+                                                       IEEE80211_BAND_2GHZ);
+                       struct ieee80211_channel *channel =
+                               ieee80211_get_channel(wiphy, freq);
+
+                       lbs_deb_scan("scan: %pM, capa %04x, chan %2d, %*pE, %d dBm\n",
+                                    bssid, capa, chan_no, ssid_len, ssid,
+                                    LBS_SCAN_RSSI_TO_MBM(rssi)/100);
+
+                       if (channel &&
+                           !(channel->flags & IEEE80211_CHAN_DISABLED)) {
+                               bss = cfg80211_inform_bss(wiphy, channel,
+                                       CFG80211_BSS_FTYPE_UNKNOWN,
+                                       bssid, get_unaligned_le64(tsfdesc),
+                                       capa, intvl, ie, ielen,
+                                       LBS_SCAN_RSSI_TO_MBM(rssi),
+                                       GFP_KERNEL);
+                               cfg80211_put_bss(wiphy, bss);
+                       }
+               } else
+                       lbs_deb_scan("scan response: missing BSS channel IE\n");
+
+               tsfdesc += 8;
+       }
+       ret = 0;
+
+ done:
+       lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
+       return ret;
+}
+
+
+/*
+ * Our scan command contains a TLV, consting of a SSID TLV, a channel list
+ * TLV and a rates TLV. Determine the maximum size of them:
+ */
+#define LBS_SCAN_MAX_CMD_SIZE                  \
+       (sizeof(struct cmd_ds_802_11_scan)      \
+        + LBS_MAX_SSID_TLV_SIZE                \
+        + LBS_MAX_CHANNEL_LIST_TLV_SIZE        \
+        + LBS_MAX_RATES_TLV_SIZE)
+
+/*
+ * Assumes priv->scan_req is initialized and valid
+ * Assumes priv->scan_channel is initialized
+ */
+static void lbs_scan_worker(struct work_struct *work)
+{
+       struct lbs_private *priv =
+               container_of(work, struct lbs_private, scan_work.work);
+       struct cmd_ds_802_11_scan *scan_cmd;
+       u8 *tlv; /* pointer into our current, growing TLV storage area */
+       int last_channel;
+       int running, carrier;
+
+       lbs_deb_enter(LBS_DEB_SCAN);
+
+       scan_cmd = kzalloc(LBS_SCAN_MAX_CMD_SIZE, GFP_KERNEL);
+       if (scan_cmd == NULL)
+               goto out_no_scan_cmd;
+
+       /* prepare fixed part of scan command */
+       scan_cmd->bsstype = CMD_BSS_TYPE_ANY;
+
+       /* stop network while we're away from our main channel */
+       running = !netif_queue_stopped(priv->dev);
+       carrier = netif_carrier_ok(priv->dev);
+       if (running)
+               netif_stop_queue(priv->dev);
+       if (carrier)
+               netif_carrier_off(priv->dev);
+
+       /* prepare fixed part of scan command */
+       tlv = scan_cmd->tlvbuffer;
+
+       /* add SSID TLV */
+       if (priv->scan_req->n_ssids && priv->scan_req->ssids[0].ssid_len > 0)
+               tlv += lbs_add_ssid_tlv(tlv,
+                                       priv->scan_req->ssids[0].ssid,
+                                       priv->scan_req->ssids[0].ssid_len);
+
+       /* add channel TLVs */
+       last_channel = priv->scan_channel + LBS_SCAN_BEFORE_NAP;
+       if (last_channel > priv->scan_req->n_channels)
+               last_channel = priv->scan_req->n_channels;
+       tlv += lbs_add_channel_list_tlv(priv, tlv, last_channel,
+               priv->scan_req->n_ssids);
+
+       /* add rates TLV */
+       tlv += lbs_add_supported_rates_tlv(tlv);
+
+       if (priv->scan_channel < priv->scan_req->n_channels) {
+               cancel_delayed_work(&priv->scan_work);
+               if (netif_running(priv->dev))
+                       queue_delayed_work(priv->work_thread, &priv->scan_work,
+                               msecs_to_jiffies(300));
+       }
+
+       /* This is the final data we are about to send */
+       scan_cmd->hdr.size = cpu_to_le16(tlv - (u8 *)scan_cmd);
+       lbs_deb_hex(LBS_DEB_SCAN, "SCAN_CMD", (void *)scan_cmd,
+                   sizeof(*scan_cmd));
+       lbs_deb_hex(LBS_DEB_SCAN, "SCAN_TLV", scan_cmd->tlvbuffer,
+                   tlv - scan_cmd->tlvbuffer);
+
+       __lbs_cmd(priv, CMD_802_11_SCAN, &scan_cmd->hdr,
+               le16_to_cpu(scan_cmd->hdr.size),
+               lbs_ret_scan, 0);
+
+       if (priv->scan_channel >= priv->scan_req->n_channels) {
+               /* Mark scan done */
+               cancel_delayed_work(&priv->scan_work);
+               lbs_scan_done(priv);
+       }
+
+       /* Restart network */
+       if (carrier)
+               netif_carrier_on(priv->dev);
+       if (running && !priv->tx_pending_len)
+               netif_wake_queue(priv->dev);
+
+       kfree(scan_cmd);
+
+       /* Wake up anything waiting on scan completion */
+       if (priv->scan_req == NULL) {
+               lbs_deb_scan("scan: waking up waiters\n");
+               wake_up_all(&priv->scan_q);
+       }
+
+ out_no_scan_cmd:
+       lbs_deb_leave(LBS_DEB_SCAN);
+}
+
+static void _internal_start_scan(struct lbs_private *priv, bool internal,
+       struct cfg80211_scan_request *request)
+{
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       lbs_deb_scan("scan: ssids %d, channels %d, ie_len %zd\n",
+               request->n_ssids, request->n_channels, request->ie_len);
+
+       priv->scan_channel = 0;
+       priv->scan_req = request;
+       priv->internal_scan = internal;
+
+       queue_delayed_work(priv->work_thread, &priv->scan_work,
+               msecs_to_jiffies(50));
+
+       lbs_deb_leave(LBS_DEB_CFG80211);
+}
+
+/*
+ * Clean up priv->scan_req.  Should be used to handle the allocation details.
+ */
+void lbs_scan_done(struct lbs_private *priv)
+{
+       WARN_ON(!priv->scan_req);
+
+       if (priv->internal_scan)
+               kfree(priv->scan_req);
+       else
+               cfg80211_scan_done(priv->scan_req, false);
+
+       priv->scan_req = NULL;
+}
+
+static int lbs_cfg_scan(struct wiphy *wiphy,
+       struct cfg80211_scan_request *request)
+{
+       struct lbs_private *priv = wiphy_priv(wiphy);
+       int ret = 0;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       if (priv->scan_req || delayed_work_pending(&priv->scan_work)) {
+               /* old scan request not yet processed */
+               ret = -EAGAIN;
+               goto out;
+       }
+
+       _internal_start_scan(priv, false, request);
+
+       if (priv->surpriseremoved)
+               ret = -EIO;
+
+ out:
+       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+       return ret;
+}
+
+
+
+
+/*
+ * Events
+ */
+
+void lbs_send_disconnect_notification(struct lbs_private *priv,
+                                     bool locally_generated)
+{
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       cfg80211_disconnected(priv->dev, 0, NULL, 0, locally_generated,
+                             GFP_KERNEL);
+
+       lbs_deb_leave(LBS_DEB_CFG80211);
+}
+
+void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event)
+{
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       cfg80211_michael_mic_failure(priv->dev,
+               priv->assoc_bss,
+               event == MACREG_INT_CODE_MIC_ERR_MULTICAST ?
+                       NL80211_KEYTYPE_GROUP :
+                       NL80211_KEYTYPE_PAIRWISE,
+               -1,
+               NULL,
+               GFP_KERNEL);
+
+       lbs_deb_leave(LBS_DEB_CFG80211);
+}
+
+
+
+
+/*
+ * Connect/disconnect
+ */
+
+
+/*
+ * This removes all WEP keys
+ */
+static int lbs_remove_wep_keys(struct lbs_private *priv)
+{
+       struct cmd_ds_802_11_set_wep cmd;
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       cmd.keyindex = cpu_to_le16(priv->wep_tx_key);
+       cmd.action = cpu_to_le16(CMD_ACT_REMOVE);
+
+       ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd);
+
+       lbs_deb_leave(LBS_DEB_CFG80211);
+       return ret;
+}
+
+/*
+ * Set WEP keys
+ */
+static int lbs_set_wep_keys(struct lbs_private *priv)
+{
+       struct cmd_ds_802_11_set_wep cmd;
+       int i;
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       /*
+        * command         13 00
+        * size            50 00
+        * sequence        xx xx
+        * result          00 00
+        * action          02 00     ACT_ADD
+        * transmit key    00 00
+        * type for key 1  01        WEP40
+        * type for key 2  00
+        * type for key 3  00
+        * type for key 4  00
+        * key 1           39 39 39 39 39 00 00 00
+        *                 00 00 00 00 00 00 00 00
+        * key 2           00 00 00 00 00 00 00 00
+        *                 00 00 00 00 00 00 00 00
+        * key 3           00 00 00 00 00 00 00 00
+        *                 00 00 00 00 00 00 00 00
+        * key 4           00 00 00 00 00 00 00 00
+        */
+       if (priv->wep_key_len[0] || priv->wep_key_len[1] ||
+           priv->wep_key_len[2] || priv->wep_key_len[3]) {
+               /* Only set wep keys if we have at least one of them */
+               memset(&cmd, 0, sizeof(cmd));
+               cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+               cmd.keyindex = cpu_to_le16(priv->wep_tx_key);
+               cmd.action = cpu_to_le16(CMD_ACT_ADD);
+
+               for (i = 0; i < 4; i++) {
+                       switch (priv->wep_key_len[i]) {
+                       case WLAN_KEY_LEN_WEP40:
+                               cmd.keytype[i] = CMD_TYPE_WEP_40_BIT;
+                               break;
+                       case WLAN_KEY_LEN_WEP104:
+                               cmd.keytype[i] = CMD_TYPE_WEP_104_BIT;
+                               break;
+                       default:
+                               cmd.keytype[i] = 0;
+                               break;
+                       }
+                       memcpy(cmd.keymaterial[i], priv->wep_key[i],
+                              priv->wep_key_len[i]);
+               }
+
+               ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd);
+       } else {
+               /* Otherwise remove all wep keys */
+               ret = lbs_remove_wep_keys(priv);
+       }
+
+       lbs_deb_leave(LBS_DEB_CFG80211);
+       return ret;
+}
+
+
+/*
+ * Enable/Disable RSN status
+ */
+static int lbs_enable_rsn(struct lbs_private *priv, int enable)
+{
+       struct cmd_ds_802_11_enable_rsn cmd;
+       int ret;
+
+       lbs_deb_enter_args(LBS_DEB_CFG80211, "%d", enable);
+
+       /*
+        * cmd       2f 00
+        * size      0c 00
+        * sequence  xx xx
+        * result    00 00
+        * action    01 00    ACT_SET
+        * enable    01 00
+        */
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       cmd.action = cpu_to_le16(CMD_ACT_SET);
+       cmd.enable = cpu_to_le16(enable);
+
+       ret = lbs_cmd_with_response(priv, CMD_802_11_ENABLE_RSN, &cmd);
+
+       lbs_deb_leave(LBS_DEB_CFG80211);
+       return ret;
+}
+
+
+/*
+ * Set WPA/WPA key material
+ */
+
+/*
+ * like "struct cmd_ds_802_11_key_material", but with cmd_header. Once we
+ * get rid of WEXT, this should go into host.h
+ */
+
+struct cmd_key_material {
+       struct cmd_header hdr;
+
+       __le16 action;
+       struct MrvlIEtype_keyParamSet param;
+} __packed;
+
+static int lbs_set_key_material(struct lbs_private *priv,
+                               int key_type, int key_info,
+                               const u8 *key, u16 key_len)
+{
+       struct cmd_key_material cmd;
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       /*
+        * Example for WPA (TKIP):
+        *
+        * cmd       5e 00
+        * size      34 00
+        * sequence  xx xx
+        * result    00 00
+        * action    01 00
+        * TLV type  00 01    key param
+        * length    00 26
+        * key type  01 00    TKIP
+        * key info  06 00    UNICAST | ENABLED
+        * key len   20 00
+        * key       32 bytes
+        */
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       cmd.action = cpu_to_le16(CMD_ACT_SET);
+       cmd.param.type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+       cmd.param.length = cpu_to_le16(sizeof(cmd.param) - 4);
+       cmd.param.keytypeid = cpu_to_le16(key_type);
+       cmd.param.keyinfo = cpu_to_le16(key_info);
+       cmd.param.keylen = cpu_to_le16(key_len);
+       if (key && key_len)
+               memcpy(cmd.param.key, key, key_len);
+
+       ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd);
+
+       lbs_deb_leave(LBS_DEB_CFG80211);
+       return ret;
+}
+
+
+/*
+ * Sets the auth type (open, shared, etc) in the firmware. That
+ * we use CMD_802_11_AUTHENTICATE is misleading, this firmware
+ * command doesn't send an authentication frame at all, it just
+ * stores the auth_type.
+ */
+static int lbs_set_authtype(struct lbs_private *priv,
+                           struct cfg80211_connect_params *sme)
+{
+       struct cmd_ds_802_11_authenticate cmd;
+       int ret;
+
+       lbs_deb_enter_args(LBS_DEB_CFG80211, "%d", sme->auth_type);
+
+       /*
+        * cmd        11 00
+        * size       19 00
+        * sequence   xx xx
+        * result     00 00
+        * BSS id     00 13 19 80 da 30
+        * auth type  00
+        * reserved   00 00 00 00 00 00 00 00 00 00
+        */
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       if (sme->bssid)
+               memcpy(cmd.bssid, sme->bssid, ETH_ALEN);
+       /* convert auth_type */
+       ret = lbs_auth_to_authtype(sme->auth_type);
+       if (ret < 0)
+               goto done;
+
+       cmd.authtype = ret;
+       ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd);
+
+ done:
+       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+       return ret;
+}
+
+
+/*
+ * Create association request
+ */
+#define LBS_ASSOC_MAX_CMD_SIZE                     \
+       (sizeof(struct cmd_ds_802_11_associate)    \
+        - 512 /* cmd_ds_802_11_associate.iebuf */ \
+        + LBS_MAX_SSID_TLV_SIZE                   \
+        + LBS_MAX_CHANNEL_TLV_SIZE                \
+        + LBS_MAX_CF_PARAM_TLV_SIZE               \
+        + LBS_MAX_AUTH_TYPE_TLV_SIZE              \
+        + LBS_MAX_WPA_TLV_SIZE)
+
+static int lbs_associate(struct lbs_private *priv,
+               struct cfg80211_bss *bss,
+               struct cfg80211_connect_params *sme)
+{
+       struct cmd_ds_802_11_associate_response *resp;
+       struct cmd_ds_802_11_associate *cmd = kzalloc(LBS_ASSOC_MAX_CMD_SIZE,
+                                                     GFP_KERNEL);
+       const u8 *ssid_eid;
+       size_t len, resp_ie_len;
+       int status;
+       int ret;
+       u8 *pos = &(cmd->iebuf[0]);
+       u8 *tmp;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       if (!cmd) {
+               ret = -ENOMEM;
+               goto done;
+       }
+
+       /*
+        * cmd              50 00
+        * length           34 00
+        * sequence         xx xx
+        * result           00 00
+        * BSS id           00 13 19 80 da 30
+        * capabilities     11 00
+        * listen interval  0a 00
+        * beacon interval  00 00
+        * DTIM period      00
+        * TLVs             xx   (up to 512 bytes)
+        */
+       cmd->hdr.command = cpu_to_le16(CMD_802_11_ASSOCIATE);
+
+       /* Fill in static fields */
+       memcpy(cmd->bssid, bss->bssid, ETH_ALEN);
+       cmd->listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL);
+       cmd->capability = cpu_to_le16(bss->capability);
+
+       /* add SSID TLV */
+       rcu_read_lock();
+       ssid_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SSID);
+       if (ssid_eid)
+               pos += lbs_add_ssid_tlv(pos, ssid_eid + 2, ssid_eid[1]);
+       else
+               lbs_deb_assoc("no SSID\n");
+       rcu_read_unlock();
+
+       /* add DS param TLV */
+       if (bss->channel)
+               pos += lbs_add_channel_tlv(pos, bss->channel->hw_value);
+       else
+               lbs_deb_assoc("no channel\n");
+
+       /* add (empty) CF param TLV */
+       pos += lbs_add_cf_param_tlv(pos);
+
+       /* add rates TLV */
+       tmp = pos + 4; /* skip Marvell IE header */
+       pos += lbs_add_common_rates_tlv(pos, bss);
+       lbs_deb_hex(LBS_DEB_ASSOC, "Common Rates", tmp, pos - tmp);
+
+       /* add auth type TLV */
+       if (MRVL_FW_MAJOR_REV(priv->fwrelease) >= 9)
+               pos += lbs_add_auth_type_tlv(pos, sme->auth_type);
+
+       /* add WPA/WPA2 TLV */
+       if (sme->ie && sme->ie_len)
+               pos += lbs_add_wpa_tlv(pos, sme->ie, sme->ie_len);
+
+       len = (sizeof(*cmd) - sizeof(cmd->iebuf)) +
+               (u16)(pos - (u8 *) &cmd->iebuf);
+       cmd->hdr.size = cpu_to_le16(len);
+
+       lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_CMD", (u8 *) cmd,
+                       le16_to_cpu(cmd->hdr.size));
+
+       /* store for later use */
+       memcpy(priv->assoc_bss, bss->bssid, ETH_ALEN);
+
+       ret = lbs_cmd_with_response(priv, CMD_802_11_ASSOCIATE, cmd);
+       if (ret)
+               goto done;
+
+       /* generate connect message to cfg80211 */
+
+       resp = (void *) cmd; /* recast for easier field access */
+       status = le16_to_cpu(resp->statuscode);
+
+       /* Older FW versions map the IEEE 802.11 Status Code in the association
+        * response to the following values returned in resp->statuscode:
+        *
+        *    IEEE Status Code                Marvell Status Code
+        *    0                       ->      0x0000 ASSOC_RESULT_SUCCESS
+        *    13                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
+        *    14                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
+        *    15                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
+        *    16                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
+        *    others                  ->      0x0003 ASSOC_RESULT_REFUSED
+        *
+        * Other response codes:
+        *    0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused)
+        *    0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for
+        *                                    association response from the AP)
+        */
+       if (MRVL_FW_MAJOR_REV(priv->fwrelease) <= 8) {
+               switch (status) {
+               case 0:
+                       break;
+               case 1:
+                       lbs_deb_assoc("invalid association parameters\n");
+                       status = WLAN_STATUS_CAPS_UNSUPPORTED;
+                       break;
+               case 2:
+                       lbs_deb_assoc("timer expired while waiting for AP\n");
+                       status = WLAN_STATUS_AUTH_TIMEOUT;
+                       break;
+               case 3:
+                       lbs_deb_assoc("association refused by AP\n");
+                       status = WLAN_STATUS_ASSOC_DENIED_UNSPEC;
+                       break;
+               case 4:
+                       lbs_deb_assoc("authentication refused by AP\n");
+                       status = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
+                       break;
+               default:
+                       lbs_deb_assoc("association failure %d\n", status);
+                       /* v5 OLPC firmware does return the AP status code if
+                        * it's not one of the values above.  Let that through.
+                        */
+                       break;
+               }
+       }
+
+       lbs_deb_assoc("status %d, statuscode 0x%04x, capability 0x%04x, "
+                     "aid 0x%04x\n", status, le16_to_cpu(resp->statuscode),
+                     le16_to_cpu(resp->capability), le16_to_cpu(resp->aid));
+
+       resp_ie_len = le16_to_cpu(resp->hdr.size)
+               - sizeof(resp->hdr)
+               - 6;
+       cfg80211_connect_result(priv->dev,
+                               priv->assoc_bss,
+                               sme->ie, sme->ie_len,
+                               resp->iebuf, resp_ie_len,
+                               status,
+                               GFP_KERNEL);
+
+       if (status == 0) {
+               /* TODO: get rid of priv->connect_status */
+               priv->connect_status = LBS_CONNECTED;
+               netif_carrier_on(priv->dev);
+               if (!priv->tx_pending_len)
+                       netif_tx_wake_all_queues(priv->dev);
+       }
+
+       kfree(cmd);
+done:
+       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+       return ret;
+}
+
+static struct cfg80211_scan_request *
+_new_connect_scan_req(struct wiphy *wiphy, struct cfg80211_connect_params *sme)
+{
+       struct cfg80211_scan_request *creq = NULL;
+       int i, n_channels = ieee80211_get_num_supported_channels(wiphy);
+       enum ieee80211_band band;
+
+       creq = kzalloc(sizeof(*creq) + sizeof(struct cfg80211_ssid) +
+                      n_channels * sizeof(void *),
+                      GFP_ATOMIC);
+       if (!creq)
+               return NULL;
+
+       /* SSIDs come after channels */
+       creq->ssids = (void *)&creq->channels[n_channels];
+       creq->n_channels = n_channels;
+       creq->n_ssids = 1;
+
+       /* Scan all available channels */
+       i = 0;
+       for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+               int j;
+
+               if (!wiphy->bands[band])
+                       continue;
+
+               for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
+                       /* ignore disabled channels */
+                       if (wiphy->bands[band]->channels[j].flags &
+                                               IEEE80211_CHAN_DISABLED)
+                               continue;
+
+                       creq->channels[i] = &wiphy->bands[band]->channels[j];
+                       i++;
+               }
+       }
+       if (i) {
+               /* Set real number of channels specified in creq->channels[] */
+               creq->n_channels = i;
+
+               /* Scan for the SSID we're going to connect to */
+               memcpy(creq->ssids[0].ssid, sme->ssid, sme->ssid_len);
+               creq->ssids[0].ssid_len = sme->ssid_len;
+       } else {
+               /* No channels found... */
+               kfree(creq);
+               creq = NULL;
+       }
+
+       return creq;
+}
+
+static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
+                          struct cfg80211_connect_params *sme)
+{
+       struct lbs_private *priv = wiphy_priv(wiphy);
+       struct cfg80211_bss *bss = NULL;
+       int ret = 0;
+       u8 preamble = RADIO_PREAMBLE_SHORT;
+
+       if (dev == priv->mesh_dev)
+               return -EOPNOTSUPP;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       if (!sme->bssid) {
+               struct cfg80211_scan_request *creq;
+
+               /*
+                * Scan for the requested network after waiting for existing
+                * scans to finish.
+                */
+               lbs_deb_assoc("assoc: waiting for existing scans\n");
+               wait_event_interruptible_timeout(priv->scan_q,
+                                                (priv->scan_req == NULL),
+                                                (15 * HZ));
+
+               creq = _new_connect_scan_req(wiphy, sme);
+               if (!creq) {
+                       ret = -EINVAL;
+                       goto done;
+               }
+
+               lbs_deb_assoc("assoc: scanning for compatible AP\n");
+               _internal_start_scan(priv, true, creq);
+
+               lbs_deb_assoc("assoc: waiting for scan to complete\n");
+               wait_event_interruptible_timeout(priv->scan_q,
+                                                (priv->scan_req == NULL),
+                                                (15 * HZ));
+               lbs_deb_assoc("assoc: scanning completed\n");
+       }
+
+       /* Find the BSS we want using available scan results */
+       bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,
+               sme->ssid, sme->ssid_len, IEEE80211_BSS_TYPE_ESS,
+               IEEE80211_PRIVACY_ANY);
+       if (!bss) {
+               wiphy_err(wiphy, "assoc: bss %pM not in scan results\n",
+                         sme->bssid);
+               ret = -ENOENT;
+               goto done;
+       }
+       lbs_deb_assoc("trying %pM\n", bss->bssid);
+       lbs_deb_assoc("cipher 0x%x, key index %d, key len %d\n",
+                     sme->crypto.cipher_group,
+                     sme->key_idx, sme->key_len);
+
+       /* As this is a new connection, clear locally stored WEP keys */
+       priv->wep_tx_key = 0;
+       memset(priv->wep_key, 0, sizeof(priv->wep_key));
+       memset(priv->wep_key_len, 0, sizeof(priv->wep_key_len));
+
+       /* set/remove WEP keys */
+       switch (sme->crypto.cipher_group) {
+       case WLAN_CIPHER_SUITE_WEP40:
+       case WLAN_CIPHER_SUITE_WEP104:
+               /* Store provided WEP keys in priv-> */
+               priv->wep_tx_key = sme->key_idx;
+               priv->wep_key_len[sme->key_idx] = sme->key_len;
+               memcpy(priv->wep_key[sme->key_idx], sme->key, sme->key_len);
+               /* Set WEP keys and WEP mode */
+               lbs_set_wep_keys(priv);
+               priv->mac_control |= CMD_ACT_MAC_WEP_ENABLE;
+               lbs_set_mac_control(priv);
+               /* No RSN mode for WEP */
+               lbs_enable_rsn(priv, 0);
+               break;
+       case 0: /* there's no WLAN_CIPHER_SUITE_NONE definition */
+               /*
+                * If we don't have no WEP, no WPA and no WPA2,
+                * we remove all keys like in the WPA/WPA2 setup,
+                * we just don't set RSN.
+                *
+                * Therefore: fall-through
+                */
+       case WLAN_CIPHER_SUITE_TKIP:
+       case WLAN_CIPHER_SUITE_CCMP:
+               /* Remove WEP keys and WEP mode */
+               lbs_remove_wep_keys(priv);
+               priv->mac_control &= ~CMD_ACT_MAC_WEP_ENABLE;
+               lbs_set_mac_control(priv);
+
+               /* clear the WPA/WPA2 keys */
+               lbs_set_key_material(priv,
+                       KEY_TYPE_ID_WEP, /* doesn't matter */
+                       KEY_INFO_WPA_UNICAST,
+                       NULL, 0);
+               lbs_set_key_material(priv,
+                       KEY_TYPE_ID_WEP, /* doesn't matter */
+                       KEY_INFO_WPA_MCAST,
+                       NULL, 0);
+               /* RSN mode for WPA/WPA2 */
+               lbs_enable_rsn(priv, sme->crypto.cipher_group != 0);
+               break;
+       default:
+               wiphy_err(wiphy, "unsupported cipher group 0x%x\n",
+                         sme->crypto.cipher_group);
+               ret = -ENOTSUPP;
+               goto done;
+       }
+
+       ret = lbs_set_authtype(priv, sme);
+       if (ret == -ENOTSUPP) {
+               wiphy_err(wiphy, "unsupported authtype 0x%x\n", sme->auth_type);
+               goto done;
+       }
+
+       lbs_set_radio(priv, preamble, 1);
+
+       /* Do the actual association */
+       ret = lbs_associate(priv, bss, sme);
+
+ done:
+       if (bss)
+               cfg80211_put_bss(wiphy, bss);
+       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+       return ret;
+}
+
+int lbs_disconnect(struct lbs_private *priv, u16 reason)
+{
+       struct cmd_ds_802_11_deauthenticate cmd;
+       int ret;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       /* Mildly ugly to use a locally store my own BSSID ... */
+       memcpy(cmd.macaddr, &priv->assoc_bss, ETH_ALEN);
+       cmd.reasoncode = cpu_to_le16(reason);
+
+       ret = lbs_cmd_with_response(priv, CMD_802_11_DEAUTHENTICATE, &cmd);
+       if (ret)
+               return ret;
+
+       cfg80211_disconnected(priv->dev,
+                       reason,
+                       NULL, 0, true,
+                       GFP_KERNEL);
+       priv->connect_status = LBS_DISCONNECTED;
+
+       return 0;
+}
+
+static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev,
+       u16 reason_code)
+{
+       struct lbs_private *priv = wiphy_priv(wiphy);
+
+       if (dev == priv->mesh_dev)
+               return -EOPNOTSUPP;
+
+       lbs_deb_enter_args(LBS_DEB_CFG80211, "reason_code %d", reason_code);
+
+       /* store for lbs_cfg_ret_disconnect() */
+       priv->disassoc_reason = reason_code;
+
+       return lbs_disconnect(priv, reason_code);
+}
+
+static int lbs_cfg_set_default_key(struct wiphy *wiphy,
+                                  struct net_device *netdev,
+                                  u8 key_index, bool unicast,
+                                  bool multicast)
+{
+       struct lbs_private *priv = wiphy_priv(wiphy);
+
+       if (netdev == priv->mesh_dev)
+               return -EOPNOTSUPP;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       if (key_index != priv->wep_tx_key) {
+               lbs_deb_assoc("set_default_key: to %d\n", key_index);
+               priv->wep_tx_key = key_index;
+               lbs_set_wep_keys(priv);
+       }
+
+       return 0;
+}
+
+
+static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev,
+                          u8 idx, bool pairwise, const u8 *mac_addr,
+                          struct key_params *params)
+{
+       struct lbs_private *priv = wiphy_priv(wiphy);
+       u16 key_info;
+       u16 key_type;
+       int ret = 0;
+
+       if (netdev == priv->mesh_dev)
+               return -EOPNOTSUPP;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       lbs_deb_assoc("add_key: cipher 0x%x, mac_addr %pM\n",
+                     params->cipher, mac_addr);
+       lbs_deb_assoc("add_key: key index %d, key len %d\n",
+                     idx, params->key_len);
+       if (params->key_len)
+               lbs_deb_hex(LBS_DEB_CFG80211, "KEY",
+                           params->key, params->key_len);
+
+       lbs_deb_assoc("add_key: seq len %d\n", params->seq_len);
+       if (params->seq_len)
+               lbs_deb_hex(LBS_DEB_CFG80211, "SEQ",
+                           params->seq, params->seq_len);
+
+       switch (params->cipher) {
+       case WLAN_CIPHER_SUITE_WEP40:
+       case WLAN_CIPHER_SUITE_WEP104:
+               /* actually compare if something has changed ... */
+               if ((priv->wep_key_len[idx] != params->key_len) ||
+                       memcmp(priv->wep_key[idx],
+                              params->key, params->key_len) != 0) {
+                       priv->wep_key_len[idx] = params->key_len;
+                       memcpy(priv->wep_key[idx],
+                              params->key, params->key_len);
+                       lbs_set_wep_keys(priv);
+               }
+               break;
+       case WLAN_CIPHER_SUITE_TKIP:
+       case WLAN_CIPHER_SUITE_CCMP:
+               key_info = KEY_INFO_WPA_ENABLED | ((idx == 0)
+                                                  ? KEY_INFO_WPA_UNICAST
+                                                  : KEY_INFO_WPA_MCAST);
+               key_type = (params->cipher == WLAN_CIPHER_SUITE_TKIP)
+                       ? KEY_TYPE_ID_TKIP
+                       : KEY_TYPE_ID_AES;
+               lbs_set_key_material(priv,
+                                    key_type,
+                                    key_info,
+                                    params->key, params->key_len);
+               break;
+       default:
+               wiphy_err(wiphy, "unhandled cipher 0x%x\n", params->cipher);
+               ret = -ENOTSUPP;
+               break;
+       }
+
+       return ret;
+}
+
+
+static int lbs_cfg_del_key(struct wiphy *wiphy, struct net_device *netdev,
+                          u8 key_index, bool pairwise, const u8 *mac_addr)
+{
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       lbs_deb_assoc("del_key: key_idx %d, mac_addr %pM\n",
+                     key_index, mac_addr);
+
+#ifdef TODO
+       struct lbs_private *priv = wiphy_priv(wiphy);
+       /*
+        * I think can keep this a NO-OP, because:
+
+        * - we clear all keys whenever we do lbs_cfg_connect() anyway
+        * - neither "iw" nor "wpa_supplicant" won't call this during
+        *   an ongoing connection
+        * - TODO: but I have to check if this is still true when
+        *   I set the AP to periodic re-keying
+        * - we've not kzallec() something when we've added a key at
+        *   lbs_cfg_connect() or lbs_cfg_add_key().
+        *
+        * This causes lbs_cfg_del_key() only called at disconnect time,
+        * where we'd just waste time deleting a key that is not going
+        * to be used anyway.
+        */
+       if (key_index < 3 && priv->wep_key_len[key_index]) {
+               priv->wep_key_len[key_index] = 0;
+               lbs_set_wep_keys(priv);
+       }
+#endif
+
+       return 0;
+}
+
+
+/*
+ * Get station
+ */
+
+static int lbs_cfg_get_station(struct wiphy *wiphy, struct net_device *dev,
+                              const u8 *mac, struct station_info *sinfo)
+{
+       struct lbs_private *priv = wiphy_priv(wiphy);
+       s8 signal, noise;
+       int ret;
+       size_t i;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES) |
+                        BIT(NL80211_STA_INFO_TX_PACKETS) |
+                        BIT(NL80211_STA_INFO_RX_BYTES) |
+                        BIT(NL80211_STA_INFO_RX_PACKETS);
+       sinfo->tx_bytes = priv->dev->stats.tx_bytes;
+       sinfo->tx_packets = priv->dev->stats.tx_packets;
+       sinfo->rx_bytes = priv->dev->stats.rx_bytes;
+       sinfo->rx_packets = priv->dev->stats.rx_packets;
+
+       /* Get current RSSI */
+       ret = lbs_get_rssi(priv, &signal, &noise);
+       if (ret == 0) {
+               sinfo->signal = signal;
+               sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
+       }
+
+       /* Convert priv->cur_rate from hw_value to NL80211 value */
+       for (i = 0; i < ARRAY_SIZE(lbs_rates); i++) {
+               if (priv->cur_rate == lbs_rates[i].hw_value) {
+                       sinfo->txrate.legacy = lbs_rates[i].bitrate;
+                       sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+
+
+
+/*
+ * Change interface
+ */
+
+static int lbs_change_intf(struct wiphy *wiphy, struct net_device *dev,
+       enum nl80211_iftype type, u32 *flags,
+              struct vif_params *params)
+{
+       struct lbs_private *priv = wiphy_priv(wiphy);
+       int ret = 0;
+
+       if (dev == priv->mesh_dev)
+               return -EOPNOTSUPP;
+
+       switch (type) {
+       case NL80211_IFTYPE_MONITOR:
+       case NL80211_IFTYPE_STATION:
+       case NL80211_IFTYPE_ADHOC:
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       if (priv->iface_running)
+               ret = lbs_set_iface_type(priv, type);
+
+       if (!ret)
+               priv->wdev->iftype = type;
+
+       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+       return ret;
+}
+
+
+
+/*
+ * IBSS (Ad-Hoc)
+ */
+
+/*
+ * The firmware needs the following bits masked out of the beacon-derived
+ * capability field when associating/joining to a BSS:
+ *  9 (QoS), 11 (APSD), 12 (unused), 14 (unused), 15 (unused)
+ */
+#define CAPINFO_MASK (~(0xda00))
+
+
+static void lbs_join_post(struct lbs_private *priv,
+                         struct cfg80211_ibss_params *params,
+                         u8 *bssid, u16 capability)
+{
+       u8 fake_ie[2 + IEEE80211_MAX_SSID_LEN + /* ssid */
+                  2 + 4 +                      /* basic rates */
+                  2 + 1 +                      /* DS parameter */
+                  2 + 2 +                      /* atim */
+                  2 + 8];                      /* extended rates */
+       u8 *fake = fake_ie;
+       struct cfg80211_bss *bss;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       /*
+        * For cfg80211_inform_bss, we'll need a fake IE, as we can't get
+        * the real IE from the firmware. So we fabricate a fake IE based on
+        * what the firmware actually sends (sniffed with wireshark).
+        */
+       /* Fake SSID IE */
+       *fake++ = WLAN_EID_SSID;
+       *fake++ = params->ssid_len;
+       memcpy(fake, params->ssid, params->ssid_len);
+       fake += params->ssid_len;
+       /* Fake supported basic rates IE */
+       *fake++ = WLAN_EID_SUPP_RATES;
+       *fake++ = 4;
+       *fake++ = 0x82;
+       *fake++ = 0x84;
+       *fake++ = 0x8b;
+       *fake++ = 0x96;
+       /* Fake DS channel IE */
+       *fake++ = WLAN_EID_DS_PARAMS;
+       *fake++ = 1;
+       *fake++ = params->chandef.chan->hw_value;
+       /* Fake IBSS params IE */
+       *fake++ = WLAN_EID_IBSS_PARAMS;
+       *fake++ = 2;
+       *fake++ = 0; /* ATIM=0 */
+       *fake++ = 0;
+       /* Fake extended rates IE, TODO: don't add this for 802.11b only,
+        * but I don't know how this could be checked */
+       *fake++ = WLAN_EID_EXT_SUPP_RATES;
+       *fake++ = 8;
+       *fake++ = 0x0c;
+       *fake++ = 0x12;
+       *fake++ = 0x18;
+       *fake++ = 0x24;
+       *fake++ = 0x30;
+       *fake++ = 0x48;
+       *fake++ = 0x60;
+       *fake++ = 0x6c;
+       lbs_deb_hex(LBS_DEB_CFG80211, "IE", fake_ie, fake - fake_ie);
+
+       bss = cfg80211_inform_bss(priv->wdev->wiphy,
+                                 params->chandef.chan,
+                                 CFG80211_BSS_FTYPE_UNKNOWN,
+                                 bssid,
+                                 0,
+                                 capability,
+                                 params->beacon_interval,
+                                 fake_ie, fake - fake_ie,
+                                 0, GFP_KERNEL);
+       cfg80211_put_bss(priv->wdev->wiphy, bss);
+
+       memcpy(priv->wdev->ssid, params->ssid, params->ssid_len);
+       priv->wdev->ssid_len = params->ssid_len;
+
+       cfg80211_ibss_joined(priv->dev, bssid, params->chandef.chan,
+                            GFP_KERNEL);
+
+       /* TODO: consider doing this at MACREG_INT_CODE_LINK_SENSED time */
+       priv->connect_status = LBS_CONNECTED;
+       netif_carrier_on(priv->dev);
+       if (!priv->tx_pending_len)
+               netif_wake_queue(priv->dev);
+
+       lbs_deb_leave(LBS_DEB_CFG80211);
+}
+
+static int lbs_ibss_join_existing(struct lbs_private *priv,
+       struct cfg80211_ibss_params *params,
+       struct cfg80211_bss *bss)
+{
+       const u8 *rates_eid;
+       struct cmd_ds_802_11_ad_hoc_join cmd;
+       u8 preamble = RADIO_PREAMBLE_SHORT;
+       int ret = 0;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       /* TODO: set preamble based on scan result */
+       ret = lbs_set_radio(priv, preamble, 1);
+       if (ret)
+               goto out;
+
+       /*
+        * Example CMD_802_11_AD_HOC_JOIN command:
+        *
+        * command         2c 00         CMD_802_11_AD_HOC_JOIN
+        * size            65 00
+        * sequence        xx xx
+        * result          00 00
+        * bssid           02 27 27 97 2f 96
+        * ssid            49 42 53 53 00 00 00 00
+        *                 00 00 00 00 00 00 00 00
+        *                 00 00 00 00 00 00 00 00
+        *                 00 00 00 00 00 00 00 00
+        * type            02            CMD_BSS_TYPE_IBSS
+        * beacon period   64 00
+        * dtim period     00
+        * timestamp       00 00 00 00 00 00 00 00
+        * localtime       00 00 00 00 00 00 00 00
+        * IE DS           03
+        * IE DS len       01
+        * IE DS channel   01
+        * reserveed       00 00 00 00
+        * IE IBSS         06
+        * IE IBSS len     02
+        * IE IBSS atim    00 00
+        * reserved        00 00 00 00
+        * capability      02 00
+        * rates           82 84 8b 96 0c 12 18 24 30 48 60 6c 00
+        * fail timeout    ff 00
+        * probe delay     00 00
+        */
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+
+       memcpy(cmd.bss.bssid, bss->bssid, ETH_ALEN);
+       memcpy(cmd.bss.ssid, params->ssid, params->ssid_len);
+       cmd.bss.type = CMD_BSS_TYPE_IBSS;
+       cmd.bss.beaconperiod = cpu_to_le16(params->beacon_interval);
+       cmd.bss.ds.header.id = WLAN_EID_DS_PARAMS;
+       cmd.bss.ds.header.len = 1;
+       cmd.bss.ds.channel = params->chandef.chan->hw_value;
+       cmd.bss.ibss.header.id = WLAN_EID_IBSS_PARAMS;
+       cmd.bss.ibss.header.len = 2;
+       cmd.bss.ibss.atimwindow = 0;
+       cmd.bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK);
+
+       /* set rates to the intersection of our rates and the rates in the
+          bss */
+       rcu_read_lock();
+       rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
+       if (!rates_eid) {
+               lbs_add_rates(cmd.bss.rates);
+       } else {
+               int hw, i;
+               u8 rates_max = rates_eid[1];
+               u8 *rates = cmd.bss.rates;
+               for (hw = 0; hw < ARRAY_SIZE(lbs_rates); hw++) {
+                       u8 hw_rate = lbs_rates[hw].bitrate / 5;
+                       for (i = 0; i < rates_max; i++) {
+                               if (hw_rate == (rates_eid[i+2] & 0x7f)) {
+                                       u8 rate = rates_eid[i+2];
+                                       if (rate == 0x02 || rate == 0x04 ||
+                                           rate == 0x0b || rate == 0x16)
+                                               rate |= 0x80;
+                                       *rates++ = rate;
+                               }
+                       }
+               }
+       }
+       rcu_read_unlock();
+
+       /* Only v8 and below support setting this */
+       if (MRVL_FW_MAJOR_REV(priv->fwrelease) <= 8) {
+               cmd.failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
+               cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
+       }
+       ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd);
+       if (ret)
+               goto out;
+
+       /*
+        * This is a sample response to CMD_802_11_AD_HOC_JOIN:
+        *
+        * response        2c 80
+        * size            09 00
+        * sequence        xx xx
+        * result          00 00
+        * reserved        00
+        */
+       lbs_join_post(priv, params, bss->bssid, bss->capability);
+
+ out:
+       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+       return ret;
+}
+
+
+
+static int lbs_ibss_start_new(struct lbs_private *priv,
+       struct cfg80211_ibss_params *params)
+{
+       struct cmd_ds_802_11_ad_hoc_start cmd;
+       struct cmd_ds_802_11_ad_hoc_result *resp =
+               (struct cmd_ds_802_11_ad_hoc_result *) &cmd;
+       u8 preamble = RADIO_PREAMBLE_SHORT;
+       int ret = 0;
+       u16 capability;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       ret = lbs_set_radio(priv, preamble, 1);
+       if (ret)
+               goto out;
+
+       /*
+        * Example CMD_802_11_AD_HOC_START command:
+        *
+        * command         2b 00         CMD_802_11_AD_HOC_START
+        * size            b1 00
+        * sequence        xx xx
+        * result          00 00
+        * ssid            54 45 53 54 00 00 00 00
+        *                 00 00 00 00 00 00 00 00
+        *                 00 00 00 00 00 00 00 00
+        *                 00 00 00 00 00 00 00 00
+        * bss type        02
+        * beacon period   64 00
+        * dtim period     00
+        * IE IBSS         06
+        * IE IBSS len     02
+        * IE IBSS atim    00 00
+        * reserved        00 00 00 00
+        * IE DS           03
+        * IE DS len       01
+        * IE DS channel   01
+        * reserved        00 00 00 00
+        * probe delay     00 00
+        * capability      02 00
+        * rates           82 84 8b 96   (basic rates with have bit 7 set)
+        *                 0c 12 18 24 30 48 60 6c
+        * padding         100 bytes
+        */
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       memcpy(cmd.ssid, params->ssid, params->ssid_len);
+       cmd.bsstype = CMD_BSS_TYPE_IBSS;
+       cmd.beaconperiod = cpu_to_le16(params->beacon_interval);
+       cmd.ibss.header.id = WLAN_EID_IBSS_PARAMS;
+       cmd.ibss.header.len = 2;
+       cmd.ibss.atimwindow = 0;
+       cmd.ds.header.id = WLAN_EID_DS_PARAMS;
+       cmd.ds.header.len = 1;
+       cmd.ds.channel = params->chandef.chan->hw_value;
+       /* Only v8 and below support setting probe delay */
+       if (MRVL_FW_MAJOR_REV(priv->fwrelease) <= 8)
+               cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
+       /* TODO: mix in WLAN_CAPABILITY_PRIVACY */
+       capability = WLAN_CAPABILITY_IBSS;
+       cmd.capability = cpu_to_le16(capability);
+       lbs_add_rates(cmd.rates);
+
+
+       ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_START, &cmd);
+       if (ret)
+               goto out;
+
+       /*
+        * This is a sample response to CMD_802_11_AD_HOC_JOIN:
+        *
+        * response        2b 80
+        * size            14 00
+        * sequence        xx xx
+        * result          00 00
+        * reserved        00
+        * bssid           02 2b 7b 0f 86 0e
+        */
+       lbs_join_post(priv, params, resp->bssid, capability);
+
+ out:
+       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+       return ret;
+}
+
+
+static int lbs_join_ibss(struct wiphy *wiphy, struct net_device *dev,
+               struct cfg80211_ibss_params *params)
+{
+       struct lbs_private *priv = wiphy_priv(wiphy);
+       int ret = 0;
+       struct cfg80211_bss *bss;
+
+       if (dev == priv->mesh_dev)
+               return -EOPNOTSUPP;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       if (!params->chandef.chan) {
+               ret = -ENOTSUPP;
+               goto out;
+       }
+
+       ret = lbs_set_channel(priv, params->chandef.chan->hw_value);
+       if (ret)
+               goto out;
+
+       /* Search if someone is beaconing. This assumes that the
+        * bss list is populated already */
+       bss = cfg80211_get_bss(wiphy, params->chandef.chan, params->bssid,
+               params->ssid, params->ssid_len,
+               IEEE80211_BSS_TYPE_IBSS, IEEE80211_PRIVACY_ANY);
+
+       if (bss) {
+               ret = lbs_ibss_join_existing(priv, params, bss);
+               cfg80211_put_bss(wiphy, bss);
+       } else
+               ret = lbs_ibss_start_new(priv, params);
+
+
+ out:
+       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+       return ret;
+}
+
+
+static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
+{
+       struct lbs_private *priv = wiphy_priv(wiphy);
+       struct cmd_ds_802_11_ad_hoc_stop cmd;
+       int ret = 0;
+
+       if (dev == priv->mesh_dev)
+               return -EOPNOTSUPP;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_STOP, &cmd);
+
+       /* TODO: consider doing this at MACREG_INT_CODE_ADHOC_BCN_LOST time */
+       lbs_mac_event_disconnected(priv, true);
+
+       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+       return ret;
+}
+
+
+
+
+/*
+ * Initialization
+ */
+
+static struct cfg80211_ops lbs_cfg80211_ops = {
+       .set_monitor_channel = lbs_cfg_set_monitor_channel,
+       .libertas_set_mesh_channel = lbs_cfg_set_mesh_channel,
+       .scan = lbs_cfg_scan,
+       .connect = lbs_cfg_connect,
+       .disconnect = lbs_cfg_disconnect,
+       .add_key = lbs_cfg_add_key,
+       .del_key = lbs_cfg_del_key,
+       .set_default_key = lbs_cfg_set_default_key,
+       .get_station = lbs_cfg_get_station,
+       .change_virtual_intf = lbs_change_intf,
+       .join_ibss = lbs_join_ibss,
+       .leave_ibss = lbs_leave_ibss,
+};
+
+
+/*
+ * At this time lbs_private *priv doesn't even exist, so we just allocate
+ * memory and don't initialize the wiphy further. This is postponed until we
+ * can talk to the firmware and happens at registration time in
+ * lbs_cfg_wiphy_register().
+ */
+struct wireless_dev *lbs_cfg_alloc(struct device *dev)
+{
+       int ret = 0;
+       struct wireless_dev *wdev;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
+       if (!wdev)
+               return ERR_PTR(-ENOMEM);
+
+       wdev->wiphy = wiphy_new(&lbs_cfg80211_ops, sizeof(struct lbs_private));
+       if (!wdev->wiphy) {
+               dev_err(dev, "cannot allocate wiphy\n");
+               ret = -ENOMEM;
+               goto err_wiphy_new;
+       }
+
+       lbs_deb_leave(LBS_DEB_CFG80211);
+       return wdev;
+
+ err_wiphy_new:
+       kfree(wdev);
+       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+       return ERR_PTR(ret);
+}
+
+
+static void lbs_cfg_set_regulatory_hint(struct lbs_private *priv)
+{
+       struct region_code_mapping {
+               const char *cn;
+               int code;
+       };
+
+       /* Section 5.17.2 */
+       static const struct region_code_mapping regmap[] = {
+               {"US ", 0x10}, /* US FCC */
+               {"CA ", 0x20}, /* Canada */
+               {"EU ", 0x30}, /* ETSI   */
+               {"ES ", 0x31}, /* Spain  */
+               {"FR ", 0x32}, /* France */
+               {"JP ", 0x40}, /* Japan  */
+       };
+       size_t i;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       for (i = 0; i < ARRAY_SIZE(regmap); i++)
+               if (regmap[i].code == priv->regioncode) {
+                       regulatory_hint(priv->wdev->wiphy, regmap[i].cn);
+                       break;
+               }
+
+       lbs_deb_leave(LBS_DEB_CFG80211);
+}
+
+static void lbs_reg_notifier(struct wiphy *wiphy,
+                            struct regulatory_request *request)
+{
+       struct lbs_private *priv = wiphy_priv(wiphy);
+
+       lbs_deb_enter_args(LBS_DEB_CFG80211, "cfg80211 regulatory domain "
+                       "callback for domain %c%c\n", request->alpha2[0],
+                       request->alpha2[1]);
+
+       memcpy(priv->country_code, request->alpha2, sizeof(request->alpha2));
+       if (lbs_iface_active(priv))
+               lbs_set_11d_domain_info(priv);
+
+       lbs_deb_leave(LBS_DEB_CFG80211);
+}
+
+/*
+ * This function get's called after lbs_setup_firmware() determined the
+ * firmware capabities. So we can setup the wiphy according to our
+ * hardware/firmware.
+ */
+int lbs_cfg_register(struct lbs_private *priv)
+{
+       struct wireless_dev *wdev = priv->wdev;
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       wdev->wiphy->max_scan_ssids = 1;
+       wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+
+       wdev->wiphy->interface_modes =
+                       BIT(NL80211_IFTYPE_STATION) |
+                       BIT(NL80211_IFTYPE_ADHOC);
+       if (lbs_rtap_supported(priv))
+               wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
+       if (lbs_mesh_activated(priv))
+               wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MESH_POINT);
+
+       wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &lbs_band_2ghz;
+
+       /*
+        * We could check priv->fwcapinfo && FW_CAPINFO_WPA, but I have
+        * never seen a firmware without WPA
+        */
+       wdev->wiphy->cipher_suites = cipher_suites;
+       wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
+       wdev->wiphy->reg_notifier = lbs_reg_notifier;
+
+       ret = wiphy_register(wdev->wiphy);
+       if (ret < 0)
+               pr_err("cannot register wiphy device\n");
+
+       priv->wiphy_registered = true;
+
+       ret = register_netdev(priv->dev);
+       if (ret)
+               pr_err("cannot register network device\n");
+
+       INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker);
+
+       lbs_cfg_set_regulatory_hint(priv);
+
+       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+       return ret;
+}
+
+void lbs_scan_deinit(struct lbs_private *priv)
+{
+       lbs_deb_enter(LBS_DEB_CFG80211);
+       cancel_delayed_work_sync(&priv->scan_work);
+}
+
+
+void lbs_cfg_free(struct lbs_private *priv)
+{
+       struct wireless_dev *wdev = priv->wdev;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       if (!wdev)
+               return;
+
+       if (priv->wiphy_registered)
+               wiphy_unregister(wdev->wiphy);
+
+       if (wdev->wiphy)
+               wiphy_free(wdev->wiphy);
+
+       kfree(wdev);
+}
diff --git a/drivers/net/wireless/marvell/libertas/cfg.h b/drivers/net/wireless/marvell/libertas/cfg.h
new file mode 100644 (file)
index 0000000..acccc29
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef __LBS_CFG80211_H__
+#define __LBS_CFG80211_H__
+
+struct device;
+struct lbs_private;
+struct regulatory_request;
+struct wiphy;
+
+struct wireless_dev *lbs_cfg_alloc(struct device *dev);
+int lbs_cfg_register(struct lbs_private *priv);
+void lbs_cfg_free(struct lbs_private *priv);
+
+void lbs_send_disconnect_notification(struct lbs_private *priv,
+                                     bool locally_generated);
+void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event);
+
+void lbs_scan_done(struct lbs_private *priv);
+void lbs_scan_deinit(struct lbs_private *priv);
+int lbs_disconnect(struct lbs_private *priv, u16 reason);
+
+#endif
diff --git a/drivers/net/wireless/marvell/libertas/cmd.c b/drivers/net/wireless/marvell/libertas/cmd.c
new file mode 100644 (file)
index 0000000..0387a5b
--- /dev/null
@@ -0,0 +1,1725 @@
+/*
+ * This file contains the handling of command.
+ * It prepares command and sends it to firmware when it is ready.
+ */
+
+#include <linux/hardirq.h>
+#include <linux/kfifo.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/if_arp.h>
+#include <linux/export.h>
+
+#include "decl.h"
+#include "cfg.h"
+#include "cmd.h"
+
+#define CAL_NF(nf)             ((s32)(-(s32)(nf)))
+#define CAL_RSSI(snr, nf)      ((s32)((s32)(snr) + CAL_NF(nf)))
+
+/**
+ * lbs_cmd_copyback - Simple callback that copies response back into command
+ *
+ * @priv:      A pointer to &struct lbs_private structure
+ * @extra:     A pointer to the original command structure for which
+ *             'resp' is a response
+ * @resp:      A pointer to the command response
+ *
+ * returns:    0 on success, error on failure
+ */
+int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra,
+                    struct cmd_header *resp)
+{
+       struct cmd_header *buf = (void *)extra;
+       uint16_t copy_len;
+
+       copy_len = min(le16_to_cpu(buf->size), le16_to_cpu(resp->size));
+       memcpy(buf, resp, copy_len);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(lbs_cmd_copyback);
+
+/**
+ *  lbs_cmd_async_callback - Simple callback that ignores the result.
+ *  Use this if you just want to send a command to the hardware, but don't
+ *  care for the result.
+ *
+ *  @priv:     ignored
+ *  @extra:    ignored
+ *  @resp:     ignored
+ *
+ *  returns:   0 for success
+ */
+static int lbs_cmd_async_callback(struct lbs_private *priv, unsigned long extra,
+                    struct cmd_header *resp)
+{
+       return 0;
+}
+
+
+/**
+ *  is_command_allowed_in_ps - tests if a command is allowed in Power Save mode
+ *
+ *  @cmd:      the command ID
+ *
+ *  returns:   1 if allowed, 0 if not allowed
+ */
+static u8 is_command_allowed_in_ps(u16 cmd)
+{
+       switch (cmd) {
+       case CMD_802_11_RSSI:
+               return 1;
+       case CMD_802_11_HOST_SLEEP_CFG:
+               return 1;
+       default:
+               break;
+       }
+       return 0;
+}
+
+/**
+ *  lbs_update_hw_spec - Updates the hardware details like MAC address
+ *  and regulatory region
+ *
+ *  @priv:     A pointer to &struct lbs_private structure
+ *
+ *  returns:   0 on success, error on failure
+ */
+int lbs_update_hw_spec(struct lbs_private *priv)
+{
+       struct cmd_ds_get_hw_spec cmd;
+       int ret = -1;
+       u32 i;
+
+       lbs_deb_enter(LBS_DEB_CMD);
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       memcpy(cmd.permanentaddr, priv->current_addr, ETH_ALEN);
+       ret = lbs_cmd_with_response(priv, CMD_GET_HW_SPEC, &cmd);
+       if (ret)
+               goto out;
+
+       priv->fwcapinfo = le32_to_cpu(cmd.fwcapinfo);
+
+       /* The firmware release is in an interesting format: the patch
+        * level is in the most significant nibble ... so fix that: */
+       priv->fwrelease = le32_to_cpu(cmd.fwrelease);
+       priv->fwrelease = (priv->fwrelease << 8) |
+               (priv->fwrelease >> 24 & 0xff);
+
+       /* Some firmware capabilities:
+        * CF card    firmware 5.0.16p0:   cap 0x00000303
+        * USB dongle firmware 5.110.17p2: cap 0x00000303
+        */
+       netdev_info(priv->dev, "%pM, fw %u.%u.%up%u, cap 0x%08x\n",
+               cmd.permanentaddr,
+               priv->fwrelease >> 24 & 0xff,
+               priv->fwrelease >> 16 & 0xff,
+               priv->fwrelease >>  8 & 0xff,
+               priv->fwrelease       & 0xff,
+               priv->fwcapinfo);
+       lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n",
+                   cmd.hwifversion, cmd.version);
+
+       /* Clamp region code to 8-bit since FW spec indicates that it should
+        * only ever be 8-bit, even though the field size is 16-bit.  Some firmware
+        * returns non-zero high 8 bits here.
+        *
+        * Firmware version 4.0.102 used in CF8381 has region code shifted.  We
+        * need to check for this problem and handle it properly.
+        */
+       if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V4)
+               priv->regioncode = (le16_to_cpu(cmd.regioncode) >> 8) & 0xFF;
+       else
+               priv->regioncode = le16_to_cpu(cmd.regioncode) & 0xFF;
+
+       for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
+               /* use the region code to search for the index */
+               if (priv->regioncode == lbs_region_code_to_index[i])
+                       break;
+       }
+
+       /* if it's unidentified region code, use the default (USA) */
+       if (i >= MRVDRV_MAX_REGION_CODE) {
+               priv->regioncode = 0x10;
+               netdev_info(priv->dev,
+                           "unidentified region code; using the default (USA)\n");
+       }
+
+       if (priv->current_addr[0] == 0xff)
+               memmove(priv->current_addr, cmd.permanentaddr, ETH_ALEN);
+
+       if (!priv->copied_hwaddr) {
+               memcpy(priv->dev->dev_addr, priv->current_addr, ETH_ALEN);
+               if (priv->mesh_dev)
+                       memcpy(priv->mesh_dev->dev_addr,
+                               priv->current_addr, ETH_ALEN);
+               priv->copied_hwaddr = 1;
+       }
+
+out:
+       lbs_deb_leave(LBS_DEB_CMD);
+       return ret;
+}
+
+static int lbs_ret_host_sleep_cfg(struct lbs_private *priv, unsigned long dummy,
+                       struct cmd_header *resp)
+{
+       lbs_deb_enter(LBS_DEB_CMD);
+       if (priv->is_host_sleep_activated) {
+               priv->is_host_sleep_configured = 0;
+               if (priv->psstate == PS_STATE_FULL_POWER) {
+                       priv->is_host_sleep_activated = 0;
+                       wake_up_interruptible(&priv->host_sleep_q);
+               }
+       } else {
+               priv->is_host_sleep_configured = 1;
+       }
+       lbs_deb_leave(LBS_DEB_CMD);
+       return 0;
+}
+
+int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
+               struct wol_config *p_wol_config)
+{
+       struct cmd_ds_host_sleep cmd_config;
+       int ret;
+
+       /*
+        * Certain firmware versions do not support EHS_REMOVE_WAKEUP command
+        * and the card will return a failure.  Since we need to be
+        * able to reset the mask, in those cases we set a 0 mask instead.
+        */
+       if (criteria == EHS_REMOVE_WAKEUP && !priv->ehs_remove_supported)
+               criteria = 0;
+
+       cmd_config.hdr.size = cpu_to_le16(sizeof(cmd_config));
+       cmd_config.criteria = cpu_to_le32(criteria);
+       cmd_config.gpio = priv->wol_gpio;
+       cmd_config.gap = priv->wol_gap;
+
+       if (p_wol_config != NULL)
+               memcpy((uint8_t *)&cmd_config.wol_conf, (uint8_t *)p_wol_config,
+                               sizeof(struct wol_config));
+       else
+               cmd_config.wol_conf.action = CMD_ACT_ACTION_NONE;
+
+       ret = __lbs_cmd(priv, CMD_802_11_HOST_SLEEP_CFG, &cmd_config.hdr,
+                       le16_to_cpu(cmd_config.hdr.size),
+                       lbs_ret_host_sleep_cfg, 0);
+       if (!ret) {
+               if (p_wol_config)
+                       memcpy((uint8_t *) p_wol_config,
+                                       (uint8_t *)&cmd_config.wol_conf,
+                                       sizeof(struct wol_config));
+       } else {
+               netdev_info(priv->dev, "HOST_SLEEP_CFG failed %d\n", ret);
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(lbs_host_sleep_cfg);
+
+/**
+ *  lbs_set_ps_mode - Sets the Power Save mode
+ *
+ *  @priv:     A pointer to &struct lbs_private structure
+ *  @cmd_action: The Power Save operation (PS_MODE_ACTION_ENTER_PS or
+ *                         PS_MODE_ACTION_EXIT_PS)
+ *  @block:    Whether to block on a response or not
+ *
+ *  returns:   0 on success, error on failure
+ */
+int lbs_set_ps_mode(struct lbs_private *priv, u16 cmd_action, bool block)
+{
+       struct cmd_ds_802_11_ps_mode cmd;
+       int ret = 0;
+
+       lbs_deb_enter(LBS_DEB_CMD);
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       cmd.action = cpu_to_le16(cmd_action);
+
+       if (cmd_action == PS_MODE_ACTION_ENTER_PS) {
+               lbs_deb_cmd("PS_MODE: action ENTER_PS\n");
+               cmd.multipledtim = cpu_to_le16(1);  /* Default DTIM multiple */
+       } else if (cmd_action == PS_MODE_ACTION_EXIT_PS) {
+               lbs_deb_cmd("PS_MODE: action EXIT_PS\n");
+       } else {
+               /* We don't handle CONFIRM_SLEEP here because it needs to
+                * be fastpathed to the firmware.
+                */
+               lbs_deb_cmd("PS_MODE: unknown action 0x%X\n", cmd_action);
+               ret = -EOPNOTSUPP;
+               goto out;
+       }
+
+       if (block)
+               ret = lbs_cmd_with_response(priv, CMD_802_11_PS_MODE, &cmd);
+       else
+               lbs_cmd_async(priv, CMD_802_11_PS_MODE, &cmd.hdr, sizeof (cmd));
+
+out:
+       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+       return ret;
+}
+
+int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
+                               struct sleep_params *sp)
+{
+       struct cmd_ds_802_11_sleep_params cmd;
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_CMD);
+
+       if (cmd_action == CMD_ACT_GET) {
+               memset(&cmd, 0, sizeof(cmd));
+       } else {
+               cmd.error = cpu_to_le16(sp->sp_error);
+               cmd.offset = cpu_to_le16(sp->sp_offset);
+               cmd.stabletime = cpu_to_le16(sp->sp_stabletime);
+               cmd.calcontrol = sp->sp_calcontrol;
+               cmd.externalsleepclk = sp->sp_extsleepclk;
+               cmd.reserved = cpu_to_le16(sp->sp_reserved);
+       }
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       cmd.action = cpu_to_le16(cmd_action);
+
+       ret = lbs_cmd_with_response(priv, CMD_802_11_SLEEP_PARAMS, &cmd);
+
+       if (!ret) {
+               lbs_deb_cmd("error 0x%x, offset 0x%x, stabletime 0x%x, "
+                           "calcontrol 0x%x extsleepclk 0x%x\n",
+                           le16_to_cpu(cmd.error), le16_to_cpu(cmd.offset),
+                           le16_to_cpu(cmd.stabletime), cmd.calcontrol,
+                           cmd.externalsleepclk);
+
+               sp->sp_error = le16_to_cpu(cmd.error);
+               sp->sp_offset = le16_to_cpu(cmd.offset);
+               sp->sp_stabletime = le16_to_cpu(cmd.stabletime);
+               sp->sp_calcontrol = cmd.calcontrol;
+               sp->sp_extsleepclk = cmd.externalsleepclk;
+               sp->sp_reserved = le16_to_cpu(cmd.reserved);
+       }
+
+       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+       return 0;
+}
+
+static int lbs_wait_for_ds_awake(struct lbs_private *priv)
+{
+       int ret = 0;
+
+       lbs_deb_enter(LBS_DEB_CMD);
+
+       if (priv->is_deep_sleep) {
+               if (!wait_event_interruptible_timeout(priv->ds_awake_q,
+                                       !priv->is_deep_sleep, (10 * HZ))) {
+                       netdev_err(priv->dev, "ds_awake_q: timer expired\n");
+                       ret = -1;
+               }
+       }
+
+       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+       return ret;
+}
+
+int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep)
+{
+       int ret =  0;
+
+       lbs_deb_enter(LBS_DEB_CMD);
+
+       if (deep_sleep) {
+               if (priv->is_deep_sleep != 1) {
+                       lbs_deb_cmd("deep sleep: sleep\n");
+                       BUG_ON(!priv->enter_deep_sleep);
+                       ret = priv->enter_deep_sleep(priv);
+                       if (!ret) {
+                               netif_stop_queue(priv->dev);
+                               netif_carrier_off(priv->dev);
+                       }
+               } else {
+                       netdev_err(priv->dev, "deep sleep: already enabled\n");
+               }
+       } else {
+               if (priv->is_deep_sleep) {
+                       lbs_deb_cmd("deep sleep: wakeup\n");
+                       BUG_ON(!priv->exit_deep_sleep);
+                       ret = priv->exit_deep_sleep(priv);
+                       if (!ret) {
+                               ret = lbs_wait_for_ds_awake(priv);
+                               if (ret)
+                                       netdev_err(priv->dev,
+                                                  "deep sleep: wakeup failed\n");
+                       }
+               }
+       }
+
+       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+       return ret;
+}
+
+static int lbs_ret_host_sleep_activate(struct lbs_private *priv,
+               unsigned long dummy,
+               struct cmd_header *cmd)
+{
+       lbs_deb_enter(LBS_DEB_FW);
+       priv->is_host_sleep_activated = 1;
+       wake_up_interruptible(&priv->host_sleep_q);
+       lbs_deb_leave(LBS_DEB_FW);
+       return 0;
+}
+
+int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep)
+{
+       struct cmd_header cmd;
+       int ret = 0;
+       uint32_t criteria = EHS_REMOVE_WAKEUP;
+
+       lbs_deb_enter(LBS_DEB_CMD);
+
+       if (host_sleep) {
+               if (priv->is_host_sleep_activated != 1) {
+                       memset(&cmd, 0, sizeof(cmd));
+                       ret = lbs_host_sleep_cfg(priv, priv->wol_criteria,
+                                       (struct wol_config *)NULL);
+                       if (ret) {
+                               netdev_info(priv->dev,
+                                           "Host sleep configuration failed: %d\n",
+                                           ret);
+                               return ret;
+                       }
+                       if (priv->psstate == PS_STATE_FULL_POWER) {
+                               ret = __lbs_cmd(priv,
+                                               CMD_802_11_HOST_SLEEP_ACTIVATE,
+                                               &cmd,
+                                               sizeof(cmd),
+                                               lbs_ret_host_sleep_activate, 0);
+                               if (ret)
+                                       netdev_info(priv->dev,
+                                                   "HOST_SLEEP_ACTIVATE failed: %d\n",
+                                                   ret);
+                       }
+
+                       if (!wait_event_interruptible_timeout(
+                                               priv->host_sleep_q,
+                                               priv->is_host_sleep_activated,
+                                               (10 * HZ))) {
+                               netdev_err(priv->dev,
+                                          "host_sleep_q: timer expired\n");
+                               ret = -1;
+                       }
+               } else {
+                       netdev_err(priv->dev, "host sleep: already enabled\n");
+               }
+       } else {
+               if (priv->is_host_sleep_activated)
+                       ret = lbs_host_sleep_cfg(priv, criteria,
+                                       (struct wol_config *)NULL);
+       }
+
+       return ret;
+}
+
+/**
+ *  lbs_set_snmp_mib - Set an SNMP MIB value
+ *
+ *  @priv:     A pointer to &struct lbs_private structure
+ *  @oid:      The OID to set in the firmware
+ *  @val:      Value to set the OID to
+ *
+ *  returns:           0 on success, error on failure
+ */
+int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val)
+{
+       struct cmd_ds_802_11_snmp_mib cmd;
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_CMD);
+
+       memset(&cmd, 0, sizeof (cmd));
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       cmd.action = cpu_to_le16(CMD_ACT_SET);
+       cmd.oid = cpu_to_le16((u16) oid);
+
+       switch (oid) {
+       case SNMP_MIB_OID_BSS_TYPE:
+               cmd.bufsize = cpu_to_le16(sizeof(u8));
+               cmd.value[0] = val;
+               break;
+       case SNMP_MIB_OID_11D_ENABLE:
+       case SNMP_MIB_OID_FRAG_THRESHOLD:
+       case SNMP_MIB_OID_RTS_THRESHOLD:
+       case SNMP_MIB_OID_SHORT_RETRY_LIMIT:
+       case SNMP_MIB_OID_LONG_RETRY_LIMIT:
+               cmd.bufsize = cpu_to_le16(sizeof(u16));
+               *((__le16 *)(&cmd.value)) = cpu_to_le16(val);
+               break;
+       default:
+               lbs_deb_cmd("SNMP_CMD: (set) unhandled OID 0x%x\n", oid);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       lbs_deb_cmd("SNMP_CMD: (set) oid 0x%x, oid size 0x%x, value 0x%x\n",
+                   le16_to_cpu(cmd.oid), le16_to_cpu(cmd.bufsize), val);
+
+       ret = lbs_cmd_with_response(priv, CMD_802_11_SNMP_MIB, &cmd);
+
+out:
+       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+       return ret;
+}
+
+/**
+ *  lbs_get_snmp_mib - Get an SNMP MIB value
+ *
+ *  @priv:     A pointer to &struct lbs_private structure
+ *  @oid:      The OID to retrieve from the firmware
+ *  @out_val:  Location for the returned value
+ *
+ *  returns:   0 on success, error on failure
+ */
+int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val)
+{
+       struct cmd_ds_802_11_snmp_mib cmd;
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_CMD);
+
+       memset(&cmd, 0, sizeof (cmd));
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       cmd.action = cpu_to_le16(CMD_ACT_GET);
+       cmd.oid = cpu_to_le16(oid);
+
+       ret = lbs_cmd_with_response(priv, CMD_802_11_SNMP_MIB, &cmd);
+       if (ret)
+               goto out;
+
+       switch (le16_to_cpu(cmd.bufsize)) {
+       case sizeof(u8):
+               *out_val = cmd.value[0];
+               break;
+       case sizeof(u16):
+               *out_val = le16_to_cpu(*((__le16 *)(&cmd.value)));
+               break;
+       default:
+               lbs_deb_cmd("SNMP_CMD: (get) unhandled OID 0x%x size %d\n",
+                           oid, le16_to_cpu(cmd.bufsize));
+               break;
+       }
+
+out:
+       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+       return ret;
+}
+
+/**
+ *  lbs_get_tx_power - Get the min, max, and current TX power
+ *
+ *  @priv:     A pointer to &struct lbs_private structure
+ *  @curlevel: Current power level in dBm
+ *  @minlevel: Minimum supported power level in dBm (optional)
+ *  @maxlevel: Maximum supported power level in dBm (optional)
+ *
+ *  returns:   0 on success, error on failure
+ */
+int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel,
+                    s16 *maxlevel)
+{
+       struct cmd_ds_802_11_rf_tx_power cmd;
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_CMD);
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       cmd.action = cpu_to_le16(CMD_ACT_GET);
+
+       ret = lbs_cmd_with_response(priv, CMD_802_11_RF_TX_POWER, &cmd);
+       if (ret == 0) {
+               *curlevel = le16_to_cpu(cmd.curlevel);
+               if (minlevel)
+                       *minlevel = cmd.minlevel;
+               if (maxlevel)
+                       *maxlevel = cmd.maxlevel;
+       }
+
+       lbs_deb_leave(LBS_DEB_CMD);
+       return ret;
+}
+
+/**
+ *  lbs_set_tx_power - Set the TX power
+ *
+ *  @priv:     A pointer to &struct lbs_private structure
+ *  @dbm:      The desired power level in dBm
+ *
+ *  returns:           0 on success, error on failure
+ */
+int lbs_set_tx_power(struct lbs_private *priv, s16 dbm)
+{
+       struct cmd_ds_802_11_rf_tx_power cmd;
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_CMD);
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       cmd.action = cpu_to_le16(CMD_ACT_SET);
+       cmd.curlevel = cpu_to_le16(dbm);
+
+       lbs_deb_cmd("SET_RF_TX_POWER: %d dBm\n", dbm);
+
+       ret = lbs_cmd_with_response(priv, CMD_802_11_RF_TX_POWER, &cmd);
+
+       lbs_deb_leave(LBS_DEB_CMD);
+       return ret;
+}
+
+/**
+ *  lbs_set_monitor_mode - Enable or disable monitor mode
+ *  (only implemented on OLPC usb8388 FW)
+ *
+ *  @priv:     A pointer to &struct lbs_private structure
+ *  @enable:   1 to enable monitor mode, 0 to disable
+ *
+ *  returns:   0 on success, error on failure
+ */
+int lbs_set_monitor_mode(struct lbs_private *priv, int enable)
+{
+       struct cmd_ds_802_11_monitor_mode cmd;
+       int ret;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       cmd.action = cpu_to_le16(CMD_ACT_SET);
+       if (enable)
+               cmd.mode = cpu_to_le16(0x1);
+
+       lbs_deb_cmd("SET_MONITOR_MODE: %d\n", enable);
+
+       ret = lbs_cmd_with_response(priv, CMD_802_11_MONITOR_MODE, &cmd);
+       if (ret == 0) {
+               priv->dev->type = enable ? ARPHRD_IEEE80211_RADIOTAP :
+                                               ARPHRD_ETHER;
+       }
+
+       lbs_deb_leave(LBS_DEB_CMD);
+       return ret;
+}
+
+/**
+ *  lbs_get_channel - Get the radio channel
+ *
+ *  @priv:     A pointer to &struct lbs_private structure
+ *
+ *  returns:   The channel on success, error on failure
+ */
+static int lbs_get_channel(struct lbs_private *priv)
+{
+       struct cmd_ds_802_11_rf_channel cmd;
+       int ret = 0;
+
+       lbs_deb_enter(LBS_DEB_CMD);
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_GET);
+
+       ret = lbs_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
+       if (ret)
+               goto out;
+
+       ret = le16_to_cpu(cmd.channel);
+       lbs_deb_cmd("current radio channel is %d\n", ret);
+
+out:
+       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+       return ret;
+}
+
+int lbs_update_channel(struct lbs_private *priv)
+{
+       int ret;
+
+       /* the channel in f/w could be out of sync; get the current channel */
+       lbs_deb_enter(LBS_DEB_ASSOC);
+
+       ret = lbs_get_channel(priv);
+       if (ret > 0) {
+               priv->channel = ret;
+               ret = 0;
+       }
+       lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
+       return ret;
+}
+
+/**
+ *  lbs_set_channel - Set the radio channel
+ *
+ *  @priv:     A pointer to &struct lbs_private structure
+ *  @channel:  The desired channel, or 0 to clear a locked channel
+ *
+ *  returns:   0 on success, error on failure
+ */
+int lbs_set_channel(struct lbs_private *priv, u8 channel)
+{
+       struct cmd_ds_802_11_rf_channel cmd;
+#ifdef DEBUG
+       u8 old_channel = priv->channel;
+#endif
+       int ret = 0;
+
+       lbs_deb_enter(LBS_DEB_CMD);
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_SET);
+       cmd.channel = cpu_to_le16(channel);
+
+       ret = lbs_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
+       if (ret)
+               goto out;
+
+       priv->channel = (uint8_t) le16_to_cpu(cmd.channel);
+       lbs_deb_cmd("channel switch from %d to %d\n", old_channel,
+               priv->channel);
+
+out:
+       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+       return ret;
+}
+
+/**
+ * lbs_get_rssi - Get current RSSI and noise floor
+ *
+ * @priv:      A pointer to &struct lbs_private structure
+ * @rssi:      On successful return, signal level in mBm
+ * @nf:                On successful return, Noise floor
+ *
+ * returns:    The channel on success, error on failure
+ */
+int lbs_get_rssi(struct lbs_private *priv, s8 *rssi, s8 *nf)
+{
+       struct cmd_ds_802_11_rssi cmd;
+       int ret = 0;
+
+       lbs_deb_enter(LBS_DEB_CMD);
+
+       BUG_ON(rssi == NULL);
+       BUG_ON(nf == NULL);
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       /* Average SNR over last 8 beacons */
+       cmd.n_or_snr = cpu_to_le16(8);
+
+       ret = lbs_cmd_with_response(priv, CMD_802_11_RSSI, &cmd);
+       if (ret == 0) {
+               *nf = CAL_NF(le16_to_cpu(cmd.nf));
+               *rssi = CAL_RSSI(le16_to_cpu(cmd.n_or_snr), le16_to_cpu(cmd.nf));
+       }
+
+       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+       return ret;
+}
+
+/**
+ *  lbs_set_11d_domain_info - Send regulatory and 802.11d domain information
+ *  to the firmware
+ *
+ *  @priv:     pointer to &struct lbs_private
+ *
+ *  returns:   0 on success, error code on failure
+*/
+int lbs_set_11d_domain_info(struct lbs_private *priv)
+{
+       struct wiphy *wiphy = priv->wdev->wiphy;
+       struct ieee80211_supported_band **bands = wiphy->bands;
+       struct cmd_ds_802_11d_domain_info cmd;
+       struct mrvl_ie_domain_param_set *domain = &cmd.domain;
+       struct ieee80211_country_ie_triplet *t;
+       enum ieee80211_band band;
+       struct ieee80211_channel *ch;
+       u8 num_triplet = 0;
+       u8 num_parsed_chan = 0;
+       u8 first_channel = 0, next_chan = 0, max_pwr = 0;
+       u8 i, flag = 0;
+       size_t triplet_size;
+       int ret = 0;
+
+       lbs_deb_enter(LBS_DEB_11D);
+       if (!priv->country_code[0])
+               goto out;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.action = cpu_to_le16(CMD_ACT_SET);
+
+       lbs_deb_11d("Setting country code '%c%c'\n",
+                   priv->country_code[0], priv->country_code[1]);
+
+       domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
+
+       /* Set country code */
+       domain->country_code[0] = priv->country_code[0];
+       domain->country_code[1] = priv->country_code[1];
+       domain->country_code[2] = ' ';
+
+       /* Now set up the channel triplets; firmware is somewhat picky here
+        * and doesn't validate channel numbers and spans; hence it would
+        * interpret a triplet of (36, 4, 20) as channels 36, 37, 38, 39.  Since
+        * the last 3 aren't valid channels, the driver is responsible for
+        * splitting that up into 4 triplet pairs of (36, 1, 20) + (40, 1, 20)
+        * etc.
+        */
+       for (band = 0;
+            (band < IEEE80211_NUM_BANDS) && (num_triplet < MAX_11D_TRIPLETS);
+            band++) {
+
+               if (!bands[band])
+                       continue;
+
+               for (i = 0;
+                    (i < bands[band]->n_channels) && (num_triplet < MAX_11D_TRIPLETS);
+                    i++) {
+                       ch = &bands[band]->channels[i];
+                       if (ch->flags & IEEE80211_CHAN_DISABLED)
+                               continue;
+
+                       if (!flag) {
+                               flag = 1;
+                               next_chan = first_channel = (u32) ch->hw_value;
+                               max_pwr = ch->max_power;
+                               num_parsed_chan = 1;
+                               continue;
+                       }
+
+                       if ((ch->hw_value == next_chan + 1) &&
+                                       (ch->max_power == max_pwr)) {
+                               /* Consolidate adjacent channels */
+                               next_chan++;
+                               num_parsed_chan++;
+                       } else {
+                               /* Add this triplet */
+                               lbs_deb_11d("11D triplet (%d, %d, %d)\n",
+                                       first_channel, num_parsed_chan,
+                                       max_pwr);
+                               t = &domain->triplet[num_triplet];
+                               t->chans.first_channel = first_channel;
+                               t->chans.num_channels = num_parsed_chan;
+                               t->chans.max_power = max_pwr;
+                               num_triplet++;
+                               flag = 0;
+                       }
+               }
+
+               if (flag) {
+                       /* Add last triplet */
+                       lbs_deb_11d("11D triplet (%d, %d, %d)\n", first_channel,
+                               num_parsed_chan, max_pwr);
+                       t = &domain->triplet[num_triplet];
+                       t->chans.first_channel = first_channel;
+                       t->chans.num_channels = num_parsed_chan;
+                       t->chans.max_power = max_pwr;
+                       num_triplet++;
+               }
+       }
+
+       lbs_deb_11d("# triplets %d\n", num_triplet);
+
+       /* Set command header sizes */
+       triplet_size = num_triplet * sizeof(struct ieee80211_country_ie_triplet);
+       domain->header.len = cpu_to_le16(sizeof(domain->country_code) +
+                                       triplet_size);
+
+       lbs_deb_hex(LBS_DEB_11D, "802.11D domain param set",
+                       (u8 *) &cmd.domain.country_code,
+                       le16_to_cpu(domain->header.len));
+
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd.hdr) +
+                                  sizeof(cmd.action) +
+                                  sizeof(cmd.domain.header) +
+                                  sizeof(cmd.domain.country_code) +
+                                  triplet_size);
+
+       ret = lbs_cmd_with_response(priv, CMD_802_11D_DOMAIN_INFO, &cmd);
+
+out:
+       lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
+       return ret;
+}
+
+/**
+ *  lbs_get_reg - Read a MAC, Baseband, or RF register
+ *
+ *  @priv:     pointer to &struct lbs_private
+ *  @reg:      register command, one of CMD_MAC_REG_ACCESS,
+ *             CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS
+ *  @offset:   byte offset of the register to get
+ *  @value:    on success, the value of the register at 'offset'
+ *
+ *  returns:   0 on success, error code on failure
+*/
+int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value)
+{
+       struct cmd_ds_reg_access cmd;
+       int ret = 0;
+
+       lbs_deb_enter(LBS_DEB_CMD);
+
+       BUG_ON(value == NULL);
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       cmd.action = cpu_to_le16(CMD_ACT_GET);
+       cmd.offset = cpu_to_le16(offset);
+
+       if (reg != CMD_MAC_REG_ACCESS &&
+           reg != CMD_BBP_REG_ACCESS &&
+           reg != CMD_RF_REG_ACCESS) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ret = lbs_cmd_with_response(priv, reg, &cmd);
+       if (!ret) {
+               if (reg == CMD_BBP_REG_ACCESS || reg == CMD_RF_REG_ACCESS)
+                       *value = cmd.value.bbp_rf;
+               else if (reg == CMD_MAC_REG_ACCESS)
+                       *value = le32_to_cpu(cmd.value.mac);
+       }
+
+out:
+       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+       return ret;
+}
+
+/**
+ *  lbs_set_reg - Write a MAC, Baseband, or RF register
+ *
+ *  @priv:     pointer to &struct lbs_private
+ *  @reg:      register command, one of CMD_MAC_REG_ACCESS,
+ *             CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS
+ *  @offset:   byte offset of the register to set
+ *  @value:    the value to write to the register at 'offset'
+ *
+ *  returns:   0 on success, error code on failure
+*/
+int lbs_set_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 value)
+{
+       struct cmd_ds_reg_access cmd;
+       int ret = 0;
+
+       lbs_deb_enter(LBS_DEB_CMD);
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       cmd.action = cpu_to_le16(CMD_ACT_SET);
+       cmd.offset = cpu_to_le16(offset);
+
+       if (reg == CMD_BBP_REG_ACCESS || reg == CMD_RF_REG_ACCESS)
+               cmd.value.bbp_rf = (u8) (value & 0xFF);
+       else if (reg == CMD_MAC_REG_ACCESS)
+               cmd.value.mac = cpu_to_le32(value);
+       else {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ret = lbs_cmd_with_response(priv, reg, &cmd);
+
+out:
+       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+       return ret;
+}
+
+static void lbs_queue_cmd(struct lbs_private *priv,
+                         struct cmd_ctrl_node *cmdnode)
+{
+       unsigned long flags;
+       int addtail = 1;
+
+       lbs_deb_enter(LBS_DEB_HOST);
+
+       if (!cmdnode) {
+               lbs_deb_host("QUEUE_CMD: cmdnode is NULL\n");
+               goto done;
+       }
+       if (!cmdnode->cmdbuf->size) {
+               lbs_deb_host("DNLD_CMD: cmd size is zero\n");
+               goto done;
+       }
+       cmdnode->result = 0;
+
+       /* Exit_PS command needs to be queued in the header always. */
+       if (le16_to_cpu(cmdnode->cmdbuf->command) == CMD_802_11_PS_MODE) {
+               struct cmd_ds_802_11_ps_mode *psm = (void *) &cmdnode->cmdbuf;
+
+               if (psm->action == cpu_to_le16(PS_MODE_ACTION_EXIT_PS)) {
+                       if (priv->psstate != PS_STATE_FULL_POWER)
+                               addtail = 0;
+               }
+       }
+
+       if (le16_to_cpu(cmdnode->cmdbuf->command) == CMD_802_11_WAKEUP_CONFIRM)
+               addtail = 0;
+
+       spin_lock_irqsave(&priv->driver_lock, flags);
+
+       if (addtail)
+               list_add_tail(&cmdnode->list, &priv->cmdpendingq);
+       else
+               list_add(&cmdnode->list, &priv->cmdpendingq);
+
+       spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+       lbs_deb_host("QUEUE_CMD: inserted command 0x%04x into cmdpendingq\n",
+                    le16_to_cpu(cmdnode->cmdbuf->command));
+
+done:
+       lbs_deb_leave(LBS_DEB_HOST);
+}
+
+static void lbs_submit_command(struct lbs_private *priv,
+                              struct cmd_ctrl_node *cmdnode)
+{
+       unsigned long flags;
+       struct cmd_header *cmd;
+       uint16_t cmdsize;
+       uint16_t command;
+       int timeo = 3 * HZ;
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_HOST);
+
+       cmd = cmdnode->cmdbuf;
+
+       spin_lock_irqsave(&priv->driver_lock, flags);
+       priv->seqnum++;
+       cmd->seqnum = cpu_to_le16(priv->seqnum);
+       priv->cur_cmd = cmdnode;
+       spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+       cmdsize = le16_to_cpu(cmd->size);
+       command = le16_to_cpu(cmd->command);
+
+       /* These commands take longer */
+       if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE)
+               timeo = 5 * HZ;
+
+       lbs_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d\n",
+                    command, le16_to_cpu(cmd->seqnum), cmdsize);
+       lbs_deb_hex(LBS_DEB_CMD, "DNLD_CMD", (void *) cmdnode->cmdbuf, cmdsize);
+
+       ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize);
+
+       if (ret) {
+               netdev_info(priv->dev, "DNLD_CMD: hw_host_to_card failed: %d\n",
+                           ret);
+               /* Reset dnld state machine, report failure */
+               priv->dnld_sent = DNLD_RES_RECEIVED;
+               lbs_complete_command(priv, cmdnode, ret);
+       }
+
+       if (command == CMD_802_11_DEEP_SLEEP) {
+               if (priv->is_auto_deep_sleep_enabled) {
+                       priv->wakeup_dev_required = 1;
+                       priv->dnld_sent = 0;
+               }
+               priv->is_deep_sleep = 1;
+               lbs_complete_command(priv, cmdnode, 0);
+       } else {
+               /* Setup the timer after transmit command */
+               mod_timer(&priv->command_timer, jiffies + timeo);
+       }
+
+       lbs_deb_leave(LBS_DEB_HOST);
+}
+
+/*
+ *  This function inserts command node to cmdfreeq
+ *  after cleans it. Requires priv->driver_lock held.
+ */
+static void __lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
+                                        struct cmd_ctrl_node *cmdnode)
+{
+       lbs_deb_enter(LBS_DEB_HOST);
+
+       if (!cmdnode)
+               goto out;
+
+       cmdnode->callback = NULL;
+       cmdnode->callback_arg = 0;
+
+       memset(cmdnode->cmdbuf, 0, LBS_CMD_BUFFER_SIZE);
+
+       list_add_tail(&cmdnode->list, &priv->cmdfreeq);
+ out:
+       lbs_deb_leave(LBS_DEB_HOST);
+}
+
+static void lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
+       struct cmd_ctrl_node *ptempcmd)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->driver_lock, flags);
+       __lbs_cleanup_and_insert_cmd(priv, ptempcmd);
+       spin_unlock_irqrestore(&priv->driver_lock, flags);
+}
+
+void __lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
+                           int result)
+{
+       /*
+        * Normally, commands are removed from cmdpendingq before being
+        * submitted. However, we can arrive here on alternative codepaths
+        * where the command is still pending. Make sure the command really
+        * isn't part of a list at this point.
+        */
+       list_del_init(&cmd->list);
+
+       cmd->result = result;
+       cmd->cmdwaitqwoken = 1;
+       wake_up(&cmd->cmdwait_q);
+
+       if (!cmd->callback || cmd->callback == lbs_cmd_async_callback)
+               __lbs_cleanup_and_insert_cmd(priv, cmd);
+       priv->cur_cmd = NULL;
+       wake_up(&priv->waitq);
+}
+
+void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
+                         int result)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&priv->driver_lock, flags);
+       __lbs_complete_command(priv, cmd, result);
+       spin_unlock_irqrestore(&priv->driver_lock, flags);
+}
+
+int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on)
+{
+       struct cmd_ds_802_11_radio_control cmd;
+       int ret = -EINVAL;
+
+       lbs_deb_enter(LBS_DEB_CMD);
+
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       cmd.action = cpu_to_le16(CMD_ACT_SET);
+       cmd.control = 0;
+
+       /* Only v8 and below support setting the preamble */
+       if (priv->fwrelease < 0x09000000) {
+               switch (preamble) {
+               case RADIO_PREAMBLE_SHORT:
+               case RADIO_PREAMBLE_AUTO:
+               case RADIO_PREAMBLE_LONG:
+                       cmd.control = cpu_to_le16(preamble);
+                       break;
+               default:
+                       goto out;
+               }
+       }
+
+       if (radio_on)
+               cmd.control |= cpu_to_le16(0x1);
+       else {
+               cmd.control &= cpu_to_le16(~0x1);
+               priv->txpower_cur = 0;
+       }
+
+       lbs_deb_cmd("RADIO_CONTROL: radio %s, preamble %d\n",
+                   radio_on ? "ON" : "OFF", preamble);
+
+       priv->radio_on = radio_on;
+
+       ret = lbs_cmd_with_response(priv, CMD_802_11_RADIO_CONTROL, &cmd);
+
+out:
+       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+       return ret;
+}
+
+void lbs_set_mac_control(struct lbs_private *priv)
+{
+       struct cmd_ds_mac_control cmd;
+
+       lbs_deb_enter(LBS_DEB_CMD);
+
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       cmd.action = cpu_to_le16(priv->mac_control);
+       cmd.reserved = 0;
+
+       lbs_cmd_async(priv, CMD_MAC_CONTROL, &cmd.hdr, sizeof(cmd));
+
+       lbs_deb_leave(LBS_DEB_CMD);
+}
+
+int lbs_set_mac_control_sync(struct lbs_private *priv)
+{
+       struct cmd_ds_mac_control cmd;
+       int ret = 0;
+
+       lbs_deb_enter(LBS_DEB_CMD);
+
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       cmd.action = cpu_to_le16(priv->mac_control);
+       cmd.reserved = 0;
+       ret = lbs_cmd_with_response(priv, CMD_MAC_CONTROL, &cmd);
+
+       lbs_deb_leave(LBS_DEB_CMD);
+       return ret;
+}
+
+/**
+ *  lbs_allocate_cmd_buffer - allocates the command buffer and links
+ *  it to command free queue
+ *
+ *  @priv:     A pointer to &struct lbs_private structure
+ *
+ *  returns:   0 for success or -1 on error
+ */
+int lbs_allocate_cmd_buffer(struct lbs_private *priv)
+{
+       int ret = 0;
+       u32 bufsize;
+       u32 i;
+       struct cmd_ctrl_node *cmdarray;
+
+       lbs_deb_enter(LBS_DEB_HOST);
+
+       /* Allocate and initialize the command array */
+       bufsize = sizeof(struct cmd_ctrl_node) * LBS_NUM_CMD_BUFFERS;
+       if (!(cmdarray = kzalloc(bufsize, GFP_KERNEL))) {
+               lbs_deb_host("ALLOC_CMD_BUF: tempcmd_array is NULL\n");
+               ret = -1;
+               goto done;
+       }
+       priv->cmd_array = cmdarray;
+
+       /* Allocate and initialize each command buffer in the command array */
+       for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
+               cmdarray[i].cmdbuf = kzalloc(LBS_CMD_BUFFER_SIZE, GFP_KERNEL);
+               if (!cmdarray[i].cmdbuf) {
+                       lbs_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n");
+                       ret = -1;
+                       goto done;
+               }
+       }
+
+       for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
+               init_waitqueue_head(&cmdarray[i].cmdwait_q);
+               lbs_cleanup_and_insert_cmd(priv, &cmdarray[i]);
+       }
+       ret = 0;
+
+done:
+       lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
+       return ret;
+}
+
+/**
+ *  lbs_free_cmd_buffer - free the command buffer
+ *
+ *  @priv:     A pointer to &struct lbs_private structure
+ *
+ *  returns:   0 for success
+ */
+int lbs_free_cmd_buffer(struct lbs_private *priv)
+{
+       struct cmd_ctrl_node *cmdarray;
+       unsigned int i;
+
+       lbs_deb_enter(LBS_DEB_HOST);
+
+       /* need to check if cmd array is allocated or not */
+       if (priv->cmd_array == NULL) {
+               lbs_deb_host("FREE_CMD_BUF: cmd_array is NULL\n");
+               goto done;
+       }
+
+       cmdarray = priv->cmd_array;
+
+       /* Release shared memory buffers */
+       for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
+               if (cmdarray[i].cmdbuf) {
+                       kfree(cmdarray[i].cmdbuf);
+                       cmdarray[i].cmdbuf = NULL;
+               }
+       }
+
+       /* Release cmd_ctrl_node */
+       if (priv->cmd_array) {
+               kfree(priv->cmd_array);
+               priv->cmd_array = NULL;
+       }
+
+done:
+       lbs_deb_leave(LBS_DEB_HOST);
+       return 0;
+}
+
+/**
+ *  lbs_get_free_cmd_node - gets a free command node if available in
+ *  command free queue
+ *
+ *  @priv:     A pointer to &struct lbs_private structure
+ *
+ *  returns:   A pointer to &cmd_ctrl_node structure on success
+ *             or %NULL on error
+ */
+static struct cmd_ctrl_node *lbs_get_free_cmd_node(struct lbs_private *priv)
+{
+       struct cmd_ctrl_node *tempnode;
+       unsigned long flags;
+
+       lbs_deb_enter(LBS_DEB_HOST);
+
+       if (!priv)
+               return NULL;
+
+       spin_lock_irqsave(&priv->driver_lock, flags);
+
+       if (!list_empty(&priv->cmdfreeq)) {
+               tempnode = list_first_entry(&priv->cmdfreeq,
+                                           struct cmd_ctrl_node, list);
+               list_del_init(&tempnode->list);
+       } else {
+               lbs_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n");
+               tempnode = NULL;
+       }
+
+       spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+       lbs_deb_leave(LBS_DEB_HOST);
+       return tempnode;
+}
+
+/**
+ *  lbs_execute_next_command - execute next command in command
+ *  pending queue. Will put firmware back to PS mode if applicable.
+ *
+ *  @priv:     A pointer to &struct lbs_private structure
+ *
+ *  returns:   0 on success or -1 on error
+ */
+int lbs_execute_next_command(struct lbs_private *priv)
+{
+       struct cmd_ctrl_node *cmdnode = NULL;
+       struct cmd_header *cmd;
+       unsigned long flags;
+       int ret = 0;
+
+       /* Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the
+        * only caller to us is lbs_thread() and we get even when a
+        * data packet is received */
+       lbs_deb_enter(LBS_DEB_THREAD);
+
+       spin_lock_irqsave(&priv->driver_lock, flags);
+
+       if (priv->cur_cmd) {
+               netdev_alert(priv->dev,
+                            "EXEC_NEXT_CMD: already processing command!\n");
+               spin_unlock_irqrestore(&priv->driver_lock, flags);
+               ret = -1;
+               goto done;
+       }
+
+       if (!list_empty(&priv->cmdpendingq)) {
+               cmdnode = list_first_entry(&priv->cmdpendingq,
+                                          struct cmd_ctrl_node, list);
+       }
+
+       spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+       if (cmdnode) {
+               cmd = cmdnode->cmdbuf;
+
+               if (is_command_allowed_in_ps(le16_to_cpu(cmd->command))) {
+                       if ((priv->psstate == PS_STATE_SLEEP) ||
+                           (priv->psstate == PS_STATE_PRE_SLEEP)) {
+                               lbs_deb_host(
+                                      "EXEC_NEXT_CMD: cannot send cmd 0x%04x in psstate %d\n",
+                                      le16_to_cpu(cmd->command),
+                                      priv->psstate);
+                               ret = -1;
+                               goto done;
+                       }
+                       lbs_deb_host("EXEC_NEXT_CMD: OK to send command "
+                                    "0x%04x in psstate %d\n",
+                                    le16_to_cpu(cmd->command), priv->psstate);
+               } else if (priv->psstate != PS_STATE_FULL_POWER) {
+                       /*
+                        * 1. Non-PS command:
+                        * Queue it. set needtowakeup to TRUE if current state
+                        * is SLEEP, otherwise call send EXIT_PS.
+                        * 2. PS command but not EXIT_PS:
+                        * Ignore it.
+                        * 3. PS command EXIT_PS:
+                        * Set needtowakeup to TRUE if current state is SLEEP,
+                        * otherwise send this command down to firmware
+                        * immediately.
+                        */
+                       if (cmd->command != cpu_to_le16(CMD_802_11_PS_MODE)) {
+                               /*  Prepare to send Exit PS,
+                                *  this non PS command will be sent later */
+                               if ((priv->psstate == PS_STATE_SLEEP)
+                                   || (priv->psstate == PS_STATE_PRE_SLEEP)
+                                   ) {
+                                       /* w/ new scheme, it will not reach here.
+                                          since it is blocked in main_thread. */
+                                       priv->needtowakeup = 1;
+                               } else {
+                                       lbs_set_ps_mode(priv,
+                                                       PS_MODE_ACTION_EXIT_PS,
+                                                       false);
+                               }
+
+                               ret = 0;
+                               goto done;
+                       } else {
+                               /*
+                                * PS command. Ignore it if it is not Exit_PS.
+                                * otherwise send it down immediately.
+                                */
+                               struct cmd_ds_802_11_ps_mode *psm = (void *)&cmd[1];
+
+                               lbs_deb_host(
+                                      "EXEC_NEXT_CMD: PS cmd, action 0x%02x\n",
+                                      psm->action);
+                               if (psm->action !=
+                                   cpu_to_le16(PS_MODE_ACTION_EXIT_PS)) {
+                                       lbs_deb_host(
+                                              "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");
+                                       lbs_complete_command(priv, cmdnode, 0);
+
+                                       ret = 0;
+                                       goto done;
+                               }
+
+                               if ((priv->psstate == PS_STATE_SLEEP) ||
+                                   (priv->psstate == PS_STATE_PRE_SLEEP)) {
+                                       lbs_deb_host(
+                                              "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n");
+                                       lbs_complete_command(priv, cmdnode, 0);
+                                       priv->needtowakeup = 1;
+
+                                       ret = 0;
+                                       goto done;
+                               }
+
+                               lbs_deb_host(
+                                      "EXEC_NEXT_CMD: sending EXIT_PS\n");
+                       }
+               }
+               spin_lock_irqsave(&priv->driver_lock, flags);
+               list_del_init(&cmdnode->list);
+               spin_unlock_irqrestore(&priv->driver_lock, flags);
+               lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n",
+                           le16_to_cpu(cmd->command));
+               lbs_submit_command(priv, cmdnode);
+       } else {
+               /*
+                * check if in power save mode, if yes, put the device back
+                * to PS mode
+                */
+#ifdef TODO
+               /*
+                * This was the old code for libertas+wext. Someone that
+                * understands this beast should re-code it in a sane way.
+                *
+                * I actually don't understand why this is related to WPA
+                * and to connection status, shouldn't powering should be
+                * independ of such things?
+                */
+               if ((priv->psmode != LBS802_11POWERMODECAM) &&
+                   (priv->psstate == PS_STATE_FULL_POWER) &&
+                   ((priv->connect_status == LBS_CONNECTED) ||
+                   lbs_mesh_connected(priv))) {
+                       if (priv->secinfo.WPAenabled ||
+                           priv->secinfo.WPA2enabled) {
+                               /* check for valid WPA group keys */
+                               if (priv->wpa_mcast_key.len ||
+                                   priv->wpa_unicast_key.len) {
+                                       lbs_deb_host(
+                                              "EXEC_NEXT_CMD: WPA enabled and GTK_SET"
+                                              " go back to PS_SLEEP");
+                                       lbs_set_ps_mode(priv,
+                                                       PS_MODE_ACTION_ENTER_PS,
+                                                       false);
+                               }
+                       } else {
+                               lbs_deb_host(
+                                      "EXEC_NEXT_CMD: cmdpendingq empty, "
+                                      "go back to PS_SLEEP");
+                               lbs_set_ps_mode(priv, PS_MODE_ACTION_ENTER_PS,
+                                               false);
+                       }
+               }
+#endif
+       }
+
+       ret = 0;
+done:
+       lbs_deb_leave(LBS_DEB_THREAD);
+       return ret;
+}
+
+static void lbs_send_confirmsleep(struct lbs_private *priv)
+{
+       unsigned long flags;
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_HOST);
+       lbs_deb_hex(LBS_DEB_HOST, "sleep confirm", (u8 *) &confirm_sleep,
+               sizeof(confirm_sleep));
+
+       ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &confirm_sleep,
+               sizeof(confirm_sleep));
+       if (ret) {
+               netdev_alert(priv->dev, "confirm_sleep failed\n");
+               goto out;
+       }
+
+       spin_lock_irqsave(&priv->driver_lock, flags);
+
+       /* We don't get a response on the sleep-confirmation */
+       priv->dnld_sent = DNLD_RES_RECEIVED;
+
+       if (priv->is_host_sleep_configured) {
+               priv->is_host_sleep_activated = 1;
+               wake_up_interruptible(&priv->host_sleep_q);
+       }
+
+       /* If nothing to do, go back to sleep (?) */
+       if (!kfifo_len(&priv->event_fifo) && !priv->resp_len[priv->resp_idx])
+               priv->psstate = PS_STATE_SLEEP;
+
+       spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+out:
+       lbs_deb_leave(LBS_DEB_HOST);
+}
+
+/**
+ * lbs_ps_confirm_sleep - checks condition and prepares to
+ * send sleep confirm command to firmware if ok
+ *
+ * @priv:      A pointer to &struct lbs_private structure
+ *
+ * returns:    n/a
+ */
+void lbs_ps_confirm_sleep(struct lbs_private *priv)
+{
+       unsigned long flags =0;
+       int allowed = 1;
+
+       lbs_deb_enter(LBS_DEB_HOST);
+
+       spin_lock_irqsave(&priv->driver_lock, flags);
+       if (priv->dnld_sent) {
+               allowed = 0;
+               lbs_deb_host("dnld_sent was set\n");
+       }
+
+       /* In-progress command? */
+       if (priv->cur_cmd) {
+               allowed = 0;
+               lbs_deb_host("cur_cmd was set\n");
+       }
+
+       /* Pending events or command responses? */
+       if (kfifo_len(&priv->event_fifo) || priv->resp_len[priv->resp_idx]) {
+               allowed = 0;
+               lbs_deb_host("pending events or command responses\n");
+       }
+       spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+       if (allowed) {
+               lbs_deb_host("sending lbs_ps_confirm_sleep\n");
+               lbs_send_confirmsleep(priv);
+       } else {
+               lbs_deb_host("sleep confirm has been delayed\n");
+       }
+
+       lbs_deb_leave(LBS_DEB_HOST);
+}
+
+
+/**
+ * lbs_set_tpc_cfg - Configures the transmission power control functionality
+ *
+ * @priv:      A pointer to &struct lbs_private structure
+ * @enable:    Transmission power control enable
+ * @p0:                Power level when link quality is good (dBm).
+ * @p1:                Power level when link quality is fair (dBm).
+ * @p2:                Power level when link quality is poor (dBm).
+ * @usesnr:    Use Signal to Noise Ratio in TPC
+ *
+ * returns:    0 on success
+ */
+int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1,
+               int8_t p2, int usesnr)
+{
+       struct cmd_ds_802_11_tpc_cfg cmd;
+       int ret;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       cmd.action = cpu_to_le16(CMD_ACT_SET);
+       cmd.enable = !!enable;
+       cmd.usesnr = !!usesnr;
+       cmd.P0 = p0;
+       cmd.P1 = p1;
+       cmd.P2 = p2;
+
+       ret = lbs_cmd_with_response(priv, CMD_802_11_TPC_CFG, &cmd);
+
+       return ret;
+}
+
+/**
+ * lbs_set_power_adapt_cfg - Configures the power adaptation settings
+ *
+ * @priv:      A pointer to &struct lbs_private structure
+ * @enable:    Power adaptation enable
+ * @p0:                Power level for 1, 2, 5.5 and 11 Mbps (dBm).
+ * @p1:                Power level for 6, 9, 12, 18, 22, 24 and 36 Mbps (dBm).
+ * @p2:                Power level for 48 and 54 Mbps (dBm).
+ *
+ * returns:    0 on Success
+ */
+
+int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
+               int8_t p1, int8_t p2)
+{
+       struct cmd_ds_802_11_pa_cfg cmd;
+       int ret;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       cmd.action = cpu_to_le16(CMD_ACT_SET);
+       cmd.enable = !!enable;
+       cmd.P0 = p0;
+       cmd.P1 = p1;
+       cmd.P2 = p2;
+
+       ret = lbs_cmd_with_response(priv, CMD_802_11_PA_CFG , &cmd);
+
+       return ret;
+}
+
+
+struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
+       uint16_t command, struct cmd_header *in_cmd, int in_cmd_size,
+       int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
+       unsigned long callback_arg)
+{
+       struct cmd_ctrl_node *cmdnode;
+
+       lbs_deb_enter(LBS_DEB_HOST);
+
+       if (priv->surpriseremoved) {
+               lbs_deb_host("PREP_CMD: card removed\n");
+               cmdnode = ERR_PTR(-ENOENT);
+               goto done;
+       }
+
+       /* No commands are allowed in Deep Sleep until we toggle the GPIO
+        * to wake up the card and it has signaled that it's ready.
+        */
+       if (!priv->is_auto_deep_sleep_enabled) {
+               if (priv->is_deep_sleep) {
+                       lbs_deb_cmd("command not allowed in deep sleep\n");
+                       cmdnode = ERR_PTR(-EBUSY);
+                       goto done;
+               }
+       }
+
+       cmdnode = lbs_get_free_cmd_node(priv);
+       if (cmdnode == NULL) {
+               lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
+
+               /* Wake up main thread to execute next command */
+               wake_up(&priv->waitq);
+               cmdnode = ERR_PTR(-ENOBUFS);
+               goto done;
+       }
+
+       cmdnode->callback = callback;
+       cmdnode->callback_arg = callback_arg;
+
+       /* Copy the incoming command to the buffer */
+       memcpy(cmdnode->cmdbuf, in_cmd, in_cmd_size);
+
+       /* Set command, clean result, move to buffer */
+       cmdnode->cmdbuf->command = cpu_to_le16(command);
+       cmdnode->cmdbuf->size    = cpu_to_le16(in_cmd_size);
+       cmdnode->cmdbuf->result  = 0;
+
+       lbs_deb_host("PREP_CMD: command 0x%04x\n", command);
+
+       cmdnode->cmdwaitqwoken = 0;
+       lbs_queue_cmd(priv, cmdnode);
+       wake_up(&priv->waitq);
+
+ done:
+       lbs_deb_leave_args(LBS_DEB_HOST, "ret %p", cmdnode);
+       return cmdnode;
+}
+
+void lbs_cmd_async(struct lbs_private *priv, uint16_t command,
+       struct cmd_header *in_cmd, int in_cmd_size)
+{
+       lbs_deb_enter(LBS_DEB_CMD);
+       __lbs_cmd_async(priv, command, in_cmd, in_cmd_size,
+               lbs_cmd_async_callback, 0);
+       lbs_deb_leave(LBS_DEB_CMD);
+}
+
+int __lbs_cmd(struct lbs_private *priv, uint16_t command,
+             struct cmd_header *in_cmd, int in_cmd_size,
+             int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
+             unsigned long callback_arg)
+{
+       struct cmd_ctrl_node *cmdnode;
+       unsigned long flags;
+       int ret = 0;
+
+       lbs_deb_enter(LBS_DEB_HOST);
+
+       cmdnode = __lbs_cmd_async(priv, command, in_cmd, in_cmd_size,
+                                 callback, callback_arg);
+       if (IS_ERR(cmdnode)) {
+               ret = PTR_ERR(cmdnode);
+               goto done;
+       }
+
+       might_sleep();
+
+       /*
+        * Be careful with signals here. A signal may be received as the system
+        * goes into suspend or resume. We do not want this to interrupt the
+        * command, so we perform an uninterruptible sleep.
+        */
+       wait_event(cmdnode->cmdwait_q, cmdnode->cmdwaitqwoken);
+
+       spin_lock_irqsave(&priv->driver_lock, flags);
+       ret = cmdnode->result;
+       if (ret)
+               netdev_info(priv->dev, "PREP_CMD: command 0x%04x failed: %d\n",
+                           command, ret);
+
+       __lbs_cleanup_and_insert_cmd(priv, cmdnode);
+       spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+done:
+       lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(__lbs_cmd);
diff --git a/drivers/net/wireless/marvell/libertas/cmd.h b/drivers/net/wireless/marvell/libertas/cmd.h
new file mode 100644 (file)
index 0000000..0c5444b
--- /dev/null
@@ -0,0 +1,141 @@
+/* Copyright (C) 2007, Red Hat, Inc. */
+
+#ifndef _LBS_CMD_H_
+#define _LBS_CMD_H_
+
+#include <net/cfg80211.h>
+
+#include "host.h"
+#include "dev.h"
+
+
+/* Command & response transfer between host and card */
+
+struct cmd_ctrl_node {
+       struct list_head list;
+       int result;
+       /* command response */
+       int (*callback)(struct lbs_private *,
+                       unsigned long,
+                       struct cmd_header *);
+       unsigned long callback_arg;
+       /* command data */
+       struct cmd_header *cmdbuf;
+       /* wait queue */
+       u16 cmdwaitqwoken;
+       wait_queue_head_t cmdwait_q;
+};
+
+
+/* lbs_cmd() infers the size of the buffer to copy data back into, from
+   the size of the target of the pointer. Since the command to be sent
+   may often be smaller, that size is set in cmd->size by the caller.*/
+#define lbs_cmd(priv, cmdnr, cmd, cb, cb_arg)  ({              \
+       uint16_t __sz = le16_to_cpu((cmd)->hdr.size);           \
+       (cmd)->hdr.size = cpu_to_le16(sizeof(*(cmd)));          \
+       __lbs_cmd(priv, cmdnr, &(cmd)->hdr, __sz, cb, cb_arg);  \
+})
+
+#define lbs_cmd_with_response(priv, cmdnr, cmd)        \
+       lbs_cmd(priv, cmdnr, cmd, lbs_cmd_copyback, (unsigned long) (cmd))
+
+void lbs_cmd_async(struct lbs_private *priv, uint16_t command,
+       struct cmd_header *in_cmd, int in_cmd_size);
+
+int __lbs_cmd(struct lbs_private *priv, uint16_t command,
+             struct cmd_header *in_cmd, int in_cmd_size,
+             int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
+             unsigned long callback_arg);
+
+struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
+       uint16_t command, struct cmd_header *in_cmd, int in_cmd_size,
+       int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
+       unsigned long callback_arg);
+
+int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra,
+                    struct cmd_header *resp);
+
+int lbs_allocate_cmd_buffer(struct lbs_private *priv);
+int lbs_free_cmd_buffer(struct lbs_private *priv);
+
+int lbs_execute_next_command(struct lbs_private *priv);
+void __lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
+                           int result);
+void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
+                         int result);
+int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len);
+
+
+/* From cmdresp.c */
+
+void lbs_mac_event_disconnected(struct lbs_private *priv,
+                               bool locally_generated);
+
+
+
+/* Events */
+
+int lbs_process_event(struct lbs_private *priv, u32 event);
+
+
+/* Actual commands */
+
+int lbs_update_hw_spec(struct lbs_private *priv);
+
+int lbs_set_channel(struct lbs_private *priv, u8 channel);
+
+int lbs_update_channel(struct lbs_private *priv);
+
+int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
+               struct wol_config *p_wol_config);
+
+int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
+                               struct sleep_params *sp);
+
+void lbs_ps_confirm_sleep(struct lbs_private *priv);
+
+int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on);
+
+void lbs_set_mac_control(struct lbs_private *priv);
+int lbs_set_mac_control_sync(struct lbs_private *priv);
+
+int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel,
+                    s16 *maxlevel);
+
+int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val);
+
+int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val);
+
+
+/* Commands only used in wext.c, assoc. and scan.c */
+
+int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
+               int8_t p1, int8_t p2);
+
+int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1,
+               int8_t p2, int usesnr);
+
+int lbs_set_data_rate(struct lbs_private *priv, u8 rate);
+
+int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
+                                     uint16_t cmd_action);
+
+int lbs_set_tx_power(struct lbs_private *priv, s16 dbm);
+
+int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep);
+
+int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep);
+
+int lbs_set_monitor_mode(struct lbs_private *priv, int enable);
+
+int lbs_get_rssi(struct lbs_private *priv, s8 *snr, s8 *nf);
+
+int lbs_set_11d_domain_info(struct lbs_private *priv);
+
+int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value);
+
+int lbs_set_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 value);
+
+int lbs_set_ps_mode(struct lbs_private *priv, u16 cmd_action, bool block);
+
+#endif /* _LBS_CMD_H */
diff --git a/drivers/net/wireless/marvell/libertas/cmdresp.c b/drivers/net/wireless/marvell/libertas/cmdresp.c
new file mode 100644 (file)
index 0000000..e5442e8
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * This file contains the handling of command
+ * responses as well as events generated by firmware.
+ */
+
+#include <linux/hardirq.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <asm/unaligned.h>
+#include <net/cfg80211.h>
+
+#include "cfg.h"
+#include "cmd.h"
+
+/**
+ * lbs_mac_event_disconnected - handles disconnect event. It
+ * reports disconnect to upper layer, clean tx/rx packets,
+ * reset link state etc.
+ *
+ * @priv:      A pointer to struct lbs_private structure
+ * @locally_generated: indicates disconnect was requested locally
+ *             (usually by userspace)
+ *
+ * returns:    n/a
+ */
+void lbs_mac_event_disconnected(struct lbs_private *priv,
+                               bool locally_generated)
+{
+       if (priv->connect_status != LBS_CONNECTED)
+               return;
+
+       lbs_deb_enter(LBS_DEB_ASSOC);
+
+       /*
+        * Cisco AP sends EAP failure and de-auth in less than 0.5 ms.
+        * It causes problem in the Supplicant
+        */
+       msleep_interruptible(1000);
+
+       if (priv->wdev->iftype == NL80211_IFTYPE_STATION)
+               lbs_send_disconnect_notification(priv, locally_generated);
+
+       /* report disconnect to upper layer */
+       netif_stop_queue(priv->dev);
+       netif_carrier_off(priv->dev);
+
+       /* Free Tx and Rx packets */
+       kfree_skb(priv->currenttxskb);
+       priv->currenttxskb = NULL;
+       priv->tx_pending_len = 0;
+
+       priv->connect_status = LBS_DISCONNECTED;
+
+       if (priv->psstate != PS_STATE_FULL_POWER) {
+               /* make firmware to exit PS mode */
+               lbs_deb_cmd("disconnected, so exit PS mode\n");
+               lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS, false);
+       }
+       lbs_deb_leave(LBS_DEB_ASSOC);
+}
+
+int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
+{
+       uint16_t respcmd, curcmd;
+       struct cmd_header *resp;
+       int ret = 0;
+       unsigned long flags;
+       uint16_t result;
+
+       lbs_deb_enter(LBS_DEB_HOST);
+
+       mutex_lock(&priv->lock);
+       spin_lock_irqsave(&priv->driver_lock, flags);
+
+       if (!priv->cur_cmd) {
+               lbs_deb_host("CMD_RESP: cur_cmd is NULL\n");
+               ret = -1;
+               spin_unlock_irqrestore(&priv->driver_lock, flags);
+               goto done;
+       }
+
+       resp = (void *)data;
+       curcmd = le16_to_cpu(priv->cur_cmd->cmdbuf->command);
+       respcmd = le16_to_cpu(resp->command);
+       result = le16_to_cpu(resp->result);
+
+       lbs_deb_cmd("CMD_RESP: response 0x%04x, seq %d, size %d\n",
+                    respcmd, le16_to_cpu(resp->seqnum), len);
+       lbs_deb_hex(LBS_DEB_CMD, "CMD_RESP", (void *) resp, len);
+
+       if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) {
+               netdev_info(priv->dev,
+                           "Received CMD_RESP with invalid sequence %d (expected %d)\n",
+                           le16_to_cpu(resp->seqnum),
+                           le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum));
+               spin_unlock_irqrestore(&priv->driver_lock, flags);
+               ret = -1;
+               goto done;
+       }
+       if (respcmd != CMD_RET(curcmd) &&
+           respcmd != CMD_RET_802_11_ASSOCIATE && curcmd != CMD_802_11_ASSOCIATE) {
+               netdev_info(priv->dev, "Invalid CMD_RESP %x to command %x!\n",
+                           respcmd, curcmd);
+               spin_unlock_irqrestore(&priv->driver_lock, flags);
+               ret = -1;
+               goto done;
+       }
+
+       if (resp->result == cpu_to_le16(0x0004)) {
+               /* 0x0004 means -EAGAIN. Drop the response, let it time out
+                  and be resubmitted */
+               netdev_info(priv->dev,
+                           "Firmware returns DEFER to command %x. Will let it time out...\n",
+                           le16_to_cpu(resp->command));
+               spin_unlock_irqrestore(&priv->driver_lock, flags);
+               ret = -1;
+               goto done;
+       }
+
+       /* Now we got response from FW, cancel the command timer */
+       del_timer(&priv->command_timer);
+       priv->cmd_timed_out = 0;
+
+       if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) {
+               struct cmd_ds_802_11_ps_mode *psmode = (void *) &resp[1];
+               u16 action = le16_to_cpu(psmode->action);
+
+               lbs_deb_host(
+                      "CMD_RESP: PS_MODE cmd reply result 0x%x, action 0x%x\n",
+                      result, action);
+
+               if (result) {
+                       lbs_deb_host("CMD_RESP: PS command failed with 0x%x\n",
+                                   result);
+                       /*
+                        * We should not re-try enter-ps command in
+                        * ad-hoc mode. It takes place in
+                        * lbs_execute_next_command().
+                        */
+                       if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR &&
+                           action == PS_MODE_ACTION_ENTER_PS)
+                               priv->psmode = LBS802_11POWERMODECAM;
+               } else if (action == PS_MODE_ACTION_ENTER_PS) {
+                       priv->needtowakeup = 0;
+                       priv->psstate = PS_STATE_AWAKE;
+
+                       lbs_deb_host("CMD_RESP: ENTER_PS command response\n");
+                       if (priv->connect_status != LBS_CONNECTED) {
+                               /*
+                                * When Deauth Event received before Enter_PS command
+                                * response, We need to wake up the firmware.
+                                */
+                               lbs_deb_host(
+                                      "disconnected, invoking lbs_ps_wakeup\n");
+
+                               spin_unlock_irqrestore(&priv->driver_lock, flags);
+                               mutex_unlock(&priv->lock);
+                               lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS,
+                                               false);
+                               mutex_lock(&priv->lock);
+                               spin_lock_irqsave(&priv->driver_lock, flags);
+                       }
+               } else if (action == PS_MODE_ACTION_EXIT_PS) {
+                       priv->needtowakeup = 0;
+                       priv->psstate = PS_STATE_FULL_POWER;
+                       lbs_deb_host("CMD_RESP: EXIT_PS command response\n");
+               } else {
+                       lbs_deb_host("CMD_RESP: PS action 0x%X\n", action);
+               }
+
+               __lbs_complete_command(priv, priv->cur_cmd, result);
+               spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+               ret = 0;
+               goto done;
+       }
+
+       /* If the command is not successful, cleanup and return failure */
+       if ((result != 0 || !(respcmd & 0x8000))) {
+               lbs_deb_host("CMD_RESP: error 0x%04x in command reply 0x%04x\n",
+                      result, respcmd);
+               /*
+                * Handling errors here
+                */
+               switch (respcmd) {
+               case CMD_RET(CMD_GET_HW_SPEC):
+               case CMD_RET(CMD_802_11_RESET):
+                       lbs_deb_host("CMD_RESP: reset failed\n");
+                       break;
+
+               }
+               __lbs_complete_command(priv, priv->cur_cmd, result);
+               spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+               ret = -1;
+               goto done;
+       }
+
+       spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+       if (priv->cur_cmd && priv->cur_cmd->callback) {
+               ret = priv->cur_cmd->callback(priv, priv->cur_cmd->callback_arg,
+                               resp);
+       }
+
+       spin_lock_irqsave(&priv->driver_lock, flags);
+
+       if (priv->cur_cmd) {
+               /* Clean up and Put current command back to cmdfreeq */
+               __lbs_complete_command(priv, priv->cur_cmd, result);
+       }
+       spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+done:
+       mutex_unlock(&priv->lock);
+       lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
+       return ret;
+}
+
+int lbs_process_event(struct lbs_private *priv, u32 event)
+{
+       int ret = 0;
+       struct cmd_header cmd;
+
+       lbs_deb_enter(LBS_DEB_CMD);
+
+       switch (event) {
+       case MACREG_INT_CODE_LINK_SENSED:
+               lbs_deb_cmd("EVENT: link sensed\n");
+               break;
+
+       case MACREG_INT_CODE_DEAUTHENTICATED:
+               lbs_deb_cmd("EVENT: deauthenticated\n");
+               lbs_mac_event_disconnected(priv, false);
+               break;
+
+       case MACREG_INT_CODE_DISASSOCIATED:
+               lbs_deb_cmd("EVENT: disassociated\n");
+               lbs_mac_event_disconnected(priv, false);
+               break;
+
+       case MACREG_INT_CODE_LINK_LOST_NO_SCAN:
+               lbs_deb_cmd("EVENT: link lost\n");
+               lbs_mac_event_disconnected(priv, true);
+               break;
+
+       case MACREG_INT_CODE_PS_SLEEP:
+               lbs_deb_cmd("EVENT: ps sleep\n");
+
+               /* handle unexpected PS SLEEP event */
+               if (priv->psstate == PS_STATE_FULL_POWER) {
+                       lbs_deb_cmd(
+                              "EVENT: in FULL POWER mode, ignoring PS_SLEEP\n");
+                       break;
+               }
+               priv->psstate = PS_STATE_PRE_SLEEP;
+
+               lbs_ps_confirm_sleep(priv);
+
+               break;
+
+       case MACREG_INT_CODE_HOST_AWAKE:
+               lbs_deb_cmd("EVENT: host awake\n");
+               if (priv->reset_deep_sleep_wakeup)
+                       priv->reset_deep_sleep_wakeup(priv);
+               priv->is_deep_sleep = 0;
+               lbs_cmd_async(priv, CMD_802_11_WAKEUP_CONFIRM, &cmd,
+                               sizeof(cmd));
+               priv->is_host_sleep_activated = 0;
+               wake_up_interruptible(&priv->host_sleep_q);
+               break;
+
+       case MACREG_INT_CODE_DEEP_SLEEP_AWAKE:
+               if (priv->reset_deep_sleep_wakeup)
+                       priv->reset_deep_sleep_wakeup(priv);
+               lbs_deb_cmd("EVENT: ds awake\n");
+               priv->is_deep_sleep = 0;
+               priv->wakeup_dev_required = 0;
+               wake_up_interruptible(&priv->ds_awake_q);
+               break;
+
+       case MACREG_INT_CODE_PS_AWAKE:
+               lbs_deb_cmd("EVENT: ps awake\n");
+               /* handle unexpected PS AWAKE event */
+               if (priv->psstate == PS_STATE_FULL_POWER) {
+                       lbs_deb_cmd(
+                              "EVENT: In FULL POWER mode - ignore PS AWAKE\n");
+                       break;
+               }
+
+               priv->psstate = PS_STATE_AWAKE;
+
+               if (priv->needtowakeup) {
+                       /*
+                        * wait for the command processing to finish
+                        * before resuming sending
+                        * priv->needtowakeup will be set to FALSE
+                        * in lbs_ps_wakeup()
+                        */
+                       lbs_deb_cmd("waking up ...\n");
+                       lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS, false);
+               }
+               break;
+
+       case MACREG_INT_CODE_MIC_ERR_UNICAST:
+               lbs_deb_cmd("EVENT: UNICAST MIC ERROR\n");
+               lbs_send_mic_failureevent(priv, event);
+               break;
+
+       case MACREG_INT_CODE_MIC_ERR_MULTICAST:
+               lbs_deb_cmd("EVENT: MULTICAST MIC ERROR\n");
+               lbs_send_mic_failureevent(priv, event);
+               break;
+
+       case MACREG_INT_CODE_MIB_CHANGED:
+               lbs_deb_cmd("EVENT: MIB CHANGED\n");
+               break;
+       case MACREG_INT_CODE_INIT_DONE:
+               lbs_deb_cmd("EVENT: INIT DONE\n");
+               break;
+       case MACREG_INT_CODE_ADHOC_BCN_LOST:
+               lbs_deb_cmd("EVENT: ADHOC beacon lost\n");
+               break;
+       case MACREG_INT_CODE_RSSI_LOW:
+               netdev_alert(priv->dev, "EVENT: rssi low\n");
+               break;
+       case MACREG_INT_CODE_SNR_LOW:
+               netdev_alert(priv->dev, "EVENT: snr low\n");
+               break;
+       case MACREG_INT_CODE_MAX_FAIL:
+               netdev_alert(priv->dev, "EVENT: max fail\n");
+               break;
+       case MACREG_INT_CODE_RSSI_HIGH:
+               netdev_alert(priv->dev, "EVENT: rssi high\n");
+               break;
+       case MACREG_INT_CODE_SNR_HIGH:
+               netdev_alert(priv->dev, "EVENT: snr high\n");
+               break;
+
+       case MACREG_INT_CODE_MESH_AUTO_STARTED:
+               /* Ignore spurious autostart events */
+               netdev_info(priv->dev, "EVENT: MESH_AUTO_STARTED (ignoring)\n");
+               break;
+
+       default:
+               netdev_alert(priv->dev, "EVENT: unknown event id %d\n", event);
+               break;
+       }
+
+       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+       return ret;
+}
diff --git a/drivers/net/wireless/marvell/libertas/debugfs.c b/drivers/net/wireless/marvell/libertas/debugfs.c
new file mode 100644 (file)
index 0000000..26cbf1d
--- /dev/null
@@ -0,0 +1,989 @@
+#include <linux/dcache.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/hardirq.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+
+#include "decl.h"
+#include "cmd.h"
+#include "debugfs.h"
+
+static struct dentry *lbs_dir;
+static char *szStates[] = {
+       "Connected",
+       "Disconnected"
+};
+
+#ifdef PROC_DEBUG
+static void lbs_debug_init(struct lbs_private *priv);
+#endif
+
+static ssize_t write_file_dummy(struct file *file, const char __user *buf,
+                                size_t count, loff_t *ppos)
+{
+        return -EINVAL;
+}
+
+static const size_t len = PAGE_SIZE;
+
+static ssize_t lbs_dev_info(struct file *file, char __user *userbuf,
+                                 size_t count, loff_t *ppos)
+{
+       struct lbs_private *priv = file->private_data;
+       size_t pos = 0;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+       ssize_t res;
+       if (!buf)
+               return -ENOMEM;
+
+       pos += snprintf(buf+pos, len-pos, "state = %s\n",
+                               szStates[priv->connect_status]);
+       pos += snprintf(buf+pos, len-pos, "region_code = %02x\n",
+                               (u32) priv->regioncode);
+
+       res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+
+       free_page(addr);
+       return res;
+}
+
+static ssize_t lbs_sleepparams_write(struct file *file,
+                               const char __user *user_buf, size_t count,
+                               loff_t *ppos)
+{
+       struct lbs_private *priv = file->private_data;
+       ssize_t buf_size, ret;
+       struct sleep_params sp;
+       int p1, p2, p3, p4, p5, p6;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+       if (!buf)
+               return -ENOMEM;
+
+       buf_size = min(count, len - 1);
+       if (copy_from_user(buf, user_buf, buf_size)) {
+               ret = -EFAULT;
+               goto out_unlock;
+       }
+       ret = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6);
+       if (ret != 6) {
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+       sp.sp_error = p1;
+       sp.sp_offset = p2;
+       sp.sp_stabletime = p3;
+       sp.sp_calcontrol = p4;
+       sp.sp_extsleepclk = p5;
+       sp.sp_reserved = p6;
+
+       ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_SET, &sp);
+       if (!ret)
+               ret = count;
+       else if (ret > 0)
+               ret = -EINVAL;
+
+out_unlock:
+       free_page(addr);
+       return ret;
+}
+
+static ssize_t lbs_sleepparams_read(struct file *file, char __user *userbuf,
+                                 size_t count, loff_t *ppos)
+{
+       struct lbs_private *priv = file->private_data;
+       ssize_t ret;
+       size_t pos = 0;
+       struct sleep_params sp;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+       if (!buf)
+               return -ENOMEM;
+
+       ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_GET, &sp);
+       if (ret)
+               goto out_unlock;
+
+       pos += snprintf(buf, len, "%d %d %d %d %d %d\n", sp.sp_error,
+                       sp.sp_offset, sp.sp_stabletime,
+                       sp.sp_calcontrol, sp.sp_extsleepclk,
+                       sp.sp_reserved);
+
+       ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+
+out_unlock:
+       free_page(addr);
+       return ret;
+}
+
+static ssize_t lbs_host_sleep_write(struct file *file,
+                               const char __user *user_buf, size_t count,
+                               loff_t *ppos)
+{
+       struct lbs_private *priv = file->private_data;
+       ssize_t buf_size, ret;
+       int host_sleep;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+       if (!buf)
+               return -ENOMEM;
+
+       buf_size = min(count, len - 1);
+       if (copy_from_user(buf, user_buf, buf_size)) {
+               ret = -EFAULT;
+               goto out_unlock;
+       }
+       ret = sscanf(buf, "%d", &host_sleep);
+       if (ret != 1) {
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+
+       if (host_sleep == 0)
+               ret = lbs_set_host_sleep(priv, 0);
+       else if (host_sleep == 1) {
+               if (priv->wol_criteria == EHS_REMOVE_WAKEUP) {
+                       netdev_info(priv->dev,
+                                   "wake parameters not configured\n");
+                       ret = -EINVAL;
+                       goto out_unlock;
+               }
+               ret = lbs_set_host_sleep(priv, 1);
+       } else {
+               netdev_err(priv->dev, "invalid option\n");
+               ret = -EINVAL;
+       }
+
+       if (!ret)
+               ret = count;
+
+out_unlock:
+       free_page(addr);
+       return ret;
+}
+
+static ssize_t lbs_host_sleep_read(struct file *file, char __user *userbuf,
+                                 size_t count, loff_t *ppos)
+{
+       struct lbs_private *priv = file->private_data;
+       ssize_t ret;
+       size_t pos = 0;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+       if (!buf)
+               return -ENOMEM;
+
+       pos += snprintf(buf, len, "%d\n", priv->is_host_sleep_activated);
+
+       ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+
+       free_page(addr);
+       return ret;
+}
+
+/*
+ * When calling CMD_802_11_SUBSCRIBE_EVENT with CMD_ACT_GET, me might
+ * get a bunch of vendor-specific TLVs (a.k.a. IEs) back from the
+ * firmware. Here's an example:
+ *     04 01 02 00 00 00 05 01 02 00 00 00 06 01 02 00
+ *     00 00 07 01 02 00 3c 00 00 00 00 00 00 00 03 03
+ *     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ *
+ * The 04 01 is the TLV type (here TLV_TYPE_RSSI_LOW), 02 00 is the length,
+ * 00 00 are the data bytes of this TLV. For this TLV, their meaning is
+ * defined in mrvlietypes_thresholds
+ *
+ * This function searches in this TLV data chunk for a given TLV type
+ * and returns a pointer to the first data byte of the TLV, or to NULL
+ * if the TLV hasn't been found.
+ */
+static void *lbs_tlv_find(uint16_t tlv_type, const uint8_t *tlv, uint16_t size)
+{
+       struct mrvl_ie_header *tlv_h;
+       uint16_t length;
+       ssize_t pos = 0;
+
+       while (pos < size) {
+               tlv_h = (struct mrvl_ie_header *) tlv;
+               if (!tlv_h->len)
+                       return NULL;
+               if (tlv_h->type == cpu_to_le16(tlv_type))
+                       return tlv_h;
+               length = le16_to_cpu(tlv_h->len) + sizeof(*tlv_h);
+               pos += length;
+               tlv += length;
+       }
+       return NULL;
+}
+
+
+static ssize_t lbs_threshold_read(uint16_t tlv_type, uint16_t event_mask,
+                                 struct file *file, char __user *userbuf,
+                                 size_t count, loff_t *ppos)
+{
+       struct cmd_ds_802_11_subscribe_event *subscribed;
+       struct mrvl_ie_thresholds *got;
+       struct lbs_private *priv = file->private_data;
+       ssize_t ret = 0;
+       size_t pos = 0;
+       char *buf;
+       u8 value;
+       u8 freq;
+       int events = 0;
+
+       buf = (char *)get_zeroed_page(GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       subscribed = kzalloc(sizeof(*subscribed), GFP_KERNEL);
+       if (!subscribed) {
+               ret = -ENOMEM;
+               goto out_page;
+       }
+
+       subscribed->hdr.size = cpu_to_le16(sizeof(*subscribed));
+       subscribed->action = cpu_to_le16(CMD_ACT_GET);
+
+       ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, subscribed);
+       if (ret)
+               goto out_cmd;
+
+       got = lbs_tlv_find(tlv_type, subscribed->tlv, sizeof(subscribed->tlv));
+       if (got) {
+               value = got->value;
+               freq  = got->freq;
+               events = le16_to_cpu(subscribed->events);
+
+               pos += snprintf(buf, len, "%d %d %d\n", value, freq,
+                               !!(events & event_mask));
+       }
+
+       ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+
+ out_cmd:
+       kfree(subscribed);
+
+ out_page:
+       free_page((unsigned long)buf);
+       return ret;
+}
+
+
+static ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask,
+                                  struct file *file,
+                                  const char __user *userbuf, size_t count,
+                                  loff_t *ppos)
+{
+       struct cmd_ds_802_11_subscribe_event *events;
+       struct mrvl_ie_thresholds *tlv;
+       struct lbs_private *priv = file->private_data;
+       ssize_t buf_size;
+       int value, freq, new_mask;
+       uint16_t curr_mask;
+       char *buf;
+       int ret;
+
+       buf = (char *)get_zeroed_page(GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       buf_size = min(count, len - 1);
+       if (copy_from_user(buf, userbuf, buf_size)) {
+               ret = -EFAULT;
+               goto out_page;
+       }
+       ret = sscanf(buf, "%d %d %d", &value, &freq, &new_mask);
+       if (ret != 3) {
+               ret = -EINVAL;
+               goto out_page;
+       }
+       events = kzalloc(sizeof(*events), GFP_KERNEL);
+       if (!events) {
+               ret = -ENOMEM;
+               goto out_page;
+       }
+
+       events->hdr.size = cpu_to_le16(sizeof(*events));
+       events->action = cpu_to_le16(CMD_ACT_GET);
+
+       ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events);
+       if (ret)
+               goto out_events;
+
+       curr_mask = le16_to_cpu(events->events);
+
+       if (new_mask)
+               new_mask = curr_mask | event_mask;
+       else
+               new_mask = curr_mask & ~event_mask;
+
+       /* Now everything is set and we can send stuff down to the firmware */
+
+       tlv = (void *)events->tlv;
+
+       events->action = cpu_to_le16(CMD_ACT_SET);
+       events->events = cpu_to_le16(new_mask);
+       tlv->header.type = cpu_to_le16(tlv_type);
+       tlv->header.len = cpu_to_le16(sizeof(*tlv) - sizeof(tlv->header));
+       tlv->value = value;
+       if (tlv_type != TLV_TYPE_BCNMISS)
+               tlv->freq = freq;
+
+       /* The command header, the action, the event mask, and one TLV */
+       events->hdr.size = cpu_to_le16(sizeof(events->hdr) + 4 + sizeof(*tlv));
+
+       ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events);
+
+       if (!ret)
+               ret = count;
+ out_events:
+       kfree(events);
+ out_page:
+       free_page((unsigned long)buf);
+       return ret;
+}
+
+
+static ssize_t lbs_lowrssi_read(struct file *file, char __user *userbuf,
+                               size_t count, loff_t *ppos)
+{
+       return lbs_threshold_read(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
+                                 file, userbuf, count, ppos);
+}
+
+
+static ssize_t lbs_lowrssi_write(struct file *file, const char __user *userbuf,
+                                size_t count, loff_t *ppos)
+{
+       return lbs_threshold_write(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
+                                  file, userbuf, count, ppos);
+}
+
+
+static ssize_t lbs_lowsnr_read(struct file *file, char __user *userbuf,
+                              size_t count, loff_t *ppos)
+{
+       return lbs_threshold_read(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW,
+                                 file, userbuf, count, ppos);
+}
+
+
+static ssize_t lbs_lowsnr_write(struct file *file, const char __user *userbuf,
+                               size_t count, loff_t *ppos)
+{
+       return lbs_threshold_write(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW,
+                                  file, userbuf, count, ppos);
+}
+
+
+static ssize_t lbs_failcount_read(struct file *file, char __user *userbuf,
+                                 size_t count, loff_t *ppos)
+{
+       return lbs_threshold_read(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
+                                 file, userbuf, count, ppos);
+}
+
+
+static ssize_t lbs_failcount_write(struct file *file, const char __user *userbuf,
+                                  size_t count, loff_t *ppos)
+{
+       return lbs_threshold_write(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
+                                  file, userbuf, count, ppos);
+}
+
+
+static ssize_t lbs_highrssi_read(struct file *file, char __user *userbuf,
+                                size_t count, loff_t *ppos)
+{
+       return lbs_threshold_read(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH,
+                                 file, userbuf, count, ppos);
+}
+
+
+static ssize_t lbs_highrssi_write(struct file *file, const char __user *userbuf,
+                                 size_t count, loff_t *ppos)
+{
+       return lbs_threshold_write(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH,
+                                  file, userbuf, count, ppos);
+}
+
+
+static ssize_t lbs_highsnr_read(struct file *file, char __user *userbuf,
+                               size_t count, loff_t *ppos)
+{
+       return lbs_threshold_read(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH,
+                                 file, userbuf, count, ppos);
+}
+
+
+static ssize_t lbs_highsnr_write(struct file *file, const char __user *userbuf,
+                                size_t count, loff_t *ppos)
+{
+       return lbs_threshold_write(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH,
+                                  file, userbuf, count, ppos);
+}
+
+static ssize_t lbs_bcnmiss_read(struct file *file, char __user *userbuf,
+                               size_t count, loff_t *ppos)
+{
+       return lbs_threshold_read(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
+                                 file, userbuf, count, ppos);
+}
+
+
+static ssize_t lbs_bcnmiss_write(struct file *file, const char __user *userbuf,
+                                size_t count, loff_t *ppos)
+{
+       return lbs_threshold_write(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
+                                  file, userbuf, count, ppos);
+}
+
+
+static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf,
+                                 size_t count, loff_t *ppos)
+{
+       struct lbs_private *priv = file->private_data;
+       ssize_t pos = 0;
+       int ret;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+       u32 val = 0;
+
+       if (!buf)
+               return -ENOMEM;
+
+       ret = lbs_get_reg(priv, CMD_MAC_REG_ACCESS, priv->mac_offset, &val);
+       mdelay(10);
+       if (!ret) {
+               pos = snprintf(buf, len, "MAC[0x%x] = 0x%08x\n",
+                               priv->mac_offset, val);
+               ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+       }
+       free_page(addr);
+       return ret;
+}
+
+static ssize_t lbs_rdmac_write(struct file *file,
+                                   const char __user *userbuf,
+                                   size_t count, loff_t *ppos)
+{
+       struct lbs_private *priv = file->private_data;
+       ssize_t res, buf_size;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+       if (!buf)
+               return -ENOMEM;
+
+       buf_size = min(count, len - 1);
+       if (copy_from_user(buf, userbuf, buf_size)) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+       priv->mac_offset = simple_strtoul(buf, NULL, 16);
+       res = count;
+out_unlock:
+       free_page(addr);
+       return res;
+}
+
+static ssize_t lbs_wrmac_write(struct file *file,
+                                   const char __user *userbuf,
+                                   size_t count, loff_t *ppos)
+{
+
+       struct lbs_private *priv = file->private_data;
+       ssize_t res, buf_size;
+       u32 offset, value;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+       if (!buf)
+               return -ENOMEM;
+
+       buf_size = min(count, len - 1);
+       if (copy_from_user(buf, userbuf, buf_size)) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+       res = sscanf(buf, "%x %x", &offset, &value);
+       if (res != 2) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+
+       res = lbs_set_reg(priv, CMD_MAC_REG_ACCESS, offset, value);
+       mdelay(10);
+
+       if (!res)
+               res = count;
+out_unlock:
+       free_page(addr);
+       return res;
+}
+
+static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf,
+                                 size_t count, loff_t *ppos)
+{
+       struct lbs_private *priv = file->private_data;
+       ssize_t pos = 0;
+       int ret;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+       u32 val;
+
+       if (!buf)
+               return -ENOMEM;
+
+       ret = lbs_get_reg(priv, CMD_BBP_REG_ACCESS, priv->bbp_offset, &val);
+       mdelay(10);
+       if (!ret) {
+               pos = snprintf(buf, len, "BBP[0x%x] = 0x%08x\n",
+                               priv->bbp_offset, val);
+               ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+       }
+       free_page(addr);
+
+       return ret;
+}
+
+static ssize_t lbs_rdbbp_write(struct file *file,
+                                   const char __user *userbuf,
+                                   size_t count, loff_t *ppos)
+{
+       struct lbs_private *priv = file->private_data;
+       ssize_t res, buf_size;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+       if (!buf)
+               return -ENOMEM;
+
+       buf_size = min(count, len - 1);
+       if (copy_from_user(buf, userbuf, buf_size)) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+       priv->bbp_offset = simple_strtoul(buf, NULL, 16);
+       res = count;
+out_unlock:
+       free_page(addr);
+       return res;
+}
+
+static ssize_t lbs_wrbbp_write(struct file *file,
+                                   const char __user *userbuf,
+                                   size_t count, loff_t *ppos)
+{
+
+       struct lbs_private *priv = file->private_data;
+       ssize_t res, buf_size;
+       u32 offset, value;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+       if (!buf)
+               return -ENOMEM;
+
+       buf_size = min(count, len - 1);
+       if (copy_from_user(buf, userbuf, buf_size)) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+       res = sscanf(buf, "%x %x", &offset, &value);
+       if (res != 2) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+
+       res = lbs_set_reg(priv, CMD_BBP_REG_ACCESS, offset, value);
+       mdelay(10);
+
+       if (!res)
+               res = count;
+out_unlock:
+       free_page(addr);
+       return res;
+}
+
+static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf,
+                                 size_t count, loff_t *ppos)
+{
+       struct lbs_private *priv = file->private_data;
+       ssize_t pos = 0;
+       int ret;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+       u32 val;
+
+       if (!buf)
+               return -ENOMEM;
+
+       ret = lbs_get_reg(priv, CMD_RF_REG_ACCESS, priv->rf_offset, &val);
+       mdelay(10);
+       if (!ret) {
+               pos = snprintf(buf, len, "RF[0x%x] = 0x%08x\n",
+                               priv->rf_offset, val);
+               ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+       }
+       free_page(addr);
+
+       return ret;
+}
+
+static ssize_t lbs_rdrf_write(struct file *file,
+                                   const char __user *userbuf,
+                                   size_t count, loff_t *ppos)
+{
+       struct lbs_private *priv = file->private_data;
+       ssize_t res, buf_size;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+       if (!buf)
+               return -ENOMEM;
+
+       buf_size = min(count, len - 1);
+       if (copy_from_user(buf, userbuf, buf_size)) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+       priv->rf_offset = simple_strtoul(buf, NULL, 16);
+       res = count;
+out_unlock:
+       free_page(addr);
+       return res;
+}
+
+static ssize_t lbs_wrrf_write(struct file *file,
+                                   const char __user *userbuf,
+                                   size_t count, loff_t *ppos)
+{
+
+       struct lbs_private *priv = file->private_data;
+       ssize_t res, buf_size;
+       u32 offset, value;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+       if (!buf)
+               return -ENOMEM;
+
+       buf_size = min(count, len - 1);
+       if (copy_from_user(buf, userbuf, buf_size)) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+       res = sscanf(buf, "%x %x", &offset, &value);
+       if (res != 2) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+
+       res = lbs_set_reg(priv, CMD_RF_REG_ACCESS, offset, value);
+       mdelay(10);
+
+       if (!res)
+               res = count;
+out_unlock:
+       free_page(addr);
+       return res;
+}
+
+#define FOPS(fread, fwrite) { \
+       .owner = THIS_MODULE, \
+       .open = simple_open, \
+       .read = (fread), \
+       .write = (fwrite), \
+       .llseek = generic_file_llseek, \
+}
+
+struct lbs_debugfs_files {
+       const char *name;
+       umode_t perm;
+       struct file_operations fops;
+};
+
+static const struct lbs_debugfs_files debugfs_files[] = {
+       { "info", 0444, FOPS(lbs_dev_info, write_file_dummy), },
+       { "sleepparams", 0644, FOPS(lbs_sleepparams_read,
+                               lbs_sleepparams_write), },
+       { "hostsleep", 0644, FOPS(lbs_host_sleep_read,
+                               lbs_host_sleep_write), },
+};
+
+static const struct lbs_debugfs_files debugfs_events_files[] = {
+       {"low_rssi", 0644, FOPS(lbs_lowrssi_read,
+                               lbs_lowrssi_write), },
+       {"low_snr", 0644, FOPS(lbs_lowsnr_read,
+                               lbs_lowsnr_write), },
+       {"failure_count", 0644, FOPS(lbs_failcount_read,
+                               lbs_failcount_write), },
+       {"beacon_missed", 0644, FOPS(lbs_bcnmiss_read,
+                               lbs_bcnmiss_write), },
+       {"high_rssi", 0644, FOPS(lbs_highrssi_read,
+                               lbs_highrssi_write), },
+       {"high_snr", 0644, FOPS(lbs_highsnr_read,
+                               lbs_highsnr_write), },
+};
+
+static const struct lbs_debugfs_files debugfs_regs_files[] = {
+       {"rdmac", 0644, FOPS(lbs_rdmac_read, lbs_rdmac_write), },
+       {"wrmac", 0600, FOPS(NULL, lbs_wrmac_write), },
+       {"rdbbp", 0644, FOPS(lbs_rdbbp_read, lbs_rdbbp_write), },
+       {"wrbbp", 0600, FOPS(NULL, lbs_wrbbp_write), },
+       {"rdrf", 0644, FOPS(lbs_rdrf_read, lbs_rdrf_write), },
+       {"wrrf", 0600, FOPS(NULL, lbs_wrrf_write), },
+};
+
+void lbs_debugfs_init(void)
+{
+       if (!lbs_dir)
+               lbs_dir = debugfs_create_dir("lbs_wireless", NULL);
+}
+
+void lbs_debugfs_remove(void)
+{
+       debugfs_remove(lbs_dir);
+}
+
+void lbs_debugfs_init_one(struct lbs_private *priv, struct net_device *dev)
+{
+       int i;
+       const struct lbs_debugfs_files *files;
+       if (!lbs_dir)
+               goto exit;
+
+       priv->debugfs_dir = debugfs_create_dir(dev->name, lbs_dir);
+       if (!priv->debugfs_dir)
+               goto exit;
+
+       for (i=0; i<ARRAY_SIZE(debugfs_files); i++) {
+               files = &debugfs_files[i];
+               priv->debugfs_files[i] = debugfs_create_file(files->name,
+                                                            files->perm,
+                                                            priv->debugfs_dir,
+                                                            priv,
+                                                            &files->fops);
+       }
+
+       priv->events_dir = debugfs_create_dir("subscribed_events", priv->debugfs_dir);
+       if (!priv->events_dir)
+               goto exit;
+
+       for (i=0; i<ARRAY_SIZE(debugfs_events_files); i++) {
+               files = &debugfs_events_files[i];
+               priv->debugfs_events_files[i] = debugfs_create_file(files->name,
+                                                            files->perm,
+                                                            priv->events_dir,
+                                                            priv,
+                                                            &files->fops);
+       }
+
+       priv->regs_dir = debugfs_create_dir("registers", priv->debugfs_dir);
+       if (!priv->regs_dir)
+               goto exit;
+
+       for (i=0; i<ARRAY_SIZE(debugfs_regs_files); i++) {
+               files = &debugfs_regs_files[i];
+               priv->debugfs_regs_files[i] = debugfs_create_file(files->name,
+                                                            files->perm,
+                                                            priv->regs_dir,
+                                                            priv,
+                                                            &files->fops);
+       }
+
+#ifdef PROC_DEBUG
+       lbs_debug_init(priv);
+#endif
+exit:
+       return;
+}
+
+void lbs_debugfs_remove_one(struct lbs_private *priv)
+{
+       int i;
+
+       for(i=0; i<ARRAY_SIZE(debugfs_regs_files); i++)
+               debugfs_remove(priv->debugfs_regs_files[i]);
+
+       debugfs_remove(priv->regs_dir);
+
+       for(i=0; i<ARRAY_SIZE(debugfs_events_files); i++)
+               debugfs_remove(priv->debugfs_events_files[i]);
+
+       debugfs_remove(priv->events_dir);
+#ifdef PROC_DEBUG
+       debugfs_remove(priv->debugfs_debug);
+#endif
+       for(i=0; i<ARRAY_SIZE(debugfs_files); i++)
+               debugfs_remove(priv->debugfs_files[i]);
+       debugfs_remove(priv->debugfs_dir);
+}
+
+
+
+/* debug entry */
+
+#ifdef PROC_DEBUG
+
+#define item_size(n)   (FIELD_SIZEOF(struct lbs_private, n))
+#define item_addr(n)   (offsetof(struct lbs_private, n))
+
+
+struct debug_data {
+       char name[32];
+       u32 size;
+       size_t addr;
+};
+
+/* To debug any member of struct lbs_private, simply add one line here.
+ */
+static struct debug_data items[] = {
+       {"psmode", item_size(psmode), item_addr(psmode)},
+       {"psstate", item_size(psstate), item_addr(psstate)},
+};
+
+static int num_of_items = ARRAY_SIZE(items);
+
+/**
+ * lbs_debugfs_read - proc read function
+ *
+ * @file:      file to read
+ * @userbuf:   pointer to buffer
+ * @count:     number of bytes to read
+ * @ppos:      read data starting position
+ *
+ * returns:    amount of data read or negative error code
+ */
+static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf,
+                       size_t count, loff_t *ppos)
+{
+       int val = 0;
+       size_t pos = 0;
+       ssize_t res;
+       char *p;
+       int i;
+       struct debug_data *d;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+       if (!buf)
+               return -ENOMEM;
+
+       p = buf;
+
+       d = file->private_data;
+
+       for (i = 0; i < num_of_items; i++) {
+               if (d[i].size == 1)
+                       val = *((u8 *) d[i].addr);
+               else if (d[i].size == 2)
+                       val = *((u16 *) d[i].addr);
+               else if (d[i].size == 4)
+                       val = *((u32 *) d[i].addr);
+               else if (d[i].size == 8)
+                       val = *((u64 *) d[i].addr);
+
+               pos += sprintf(p + pos, "%s=%d\n", d[i].name, val);
+       }
+
+       res = simple_read_from_buffer(userbuf, count, ppos, p, pos);
+
+       free_page(addr);
+       return res;
+}
+
+/**
+ * lbs_debugfs_write - proc write function
+ *
+ * @f:         file pointer
+ * @buf:       pointer to data buffer
+ * @cnt:       data number to write
+ * @ppos:      file position
+ *
+ * returns:    amount of data written
+ */
+static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf,
+                           size_t cnt, loff_t *ppos)
+{
+       int r, i;
+       char *pdata;
+       char *p;
+       char *p0;
+       char *p1;
+       char *p2;
+       struct debug_data *d = f->private_data;
+
+       if (cnt == 0)
+               return 0;
+
+       pdata = kmalloc(cnt + 1, GFP_KERNEL);
+       if (pdata == NULL)
+               return 0;
+
+       if (copy_from_user(pdata, buf, cnt)) {
+               lbs_deb_debugfs("Copy from user failed\n");
+               kfree(pdata);
+               return 0;
+       }
+       pdata[cnt] = '\0';
+
+       p0 = pdata;
+       for (i = 0; i < num_of_items; i++) {
+               do {
+                       p = strstr(p0, d[i].name);
+                       if (p == NULL)
+                               break;
+                       p1 = strchr(p, '\n');
+                       if (p1 == NULL)
+                               break;
+                       p0 = p1++;
+                       p2 = strchr(p, '=');
+                       if (!p2)
+                               break;
+                       p2++;
+                       r = simple_strtoul(p2, NULL, 0);
+                       if (d[i].size == 1)
+                               *((u8 *) d[i].addr) = (u8) r;
+                       else if (d[i].size == 2)
+                               *((u16 *) d[i].addr) = (u16) r;
+                       else if (d[i].size == 4)
+                               *((u32 *) d[i].addr) = (u32) r;
+                       else if (d[i].size == 8)
+                               *((u64 *) d[i].addr) = (u64) r;
+                       break;
+               } while (1);
+       }
+       kfree(pdata);
+
+       return (ssize_t)cnt;
+}
+
+static const struct file_operations lbs_debug_fops = {
+       .owner = THIS_MODULE,
+       .open = simple_open,
+       .write = lbs_debugfs_write,
+       .read = lbs_debugfs_read,
+       .llseek = default_llseek,
+};
+
+/**
+ * lbs_debug_init - create debug proc file
+ *
+ * @priv:      pointer to &struct lbs_private
+ *
+ * returns:    N/A
+ */
+static void lbs_debug_init(struct lbs_private *priv)
+{
+       int i;
+
+       if (!priv->debugfs_dir)
+               return;
+
+       for (i = 0; i < num_of_items; i++)
+               items[i].addr += (size_t) priv;
+
+       priv->debugfs_debug = debugfs_create_file("debug", 0644,
+                                                 priv->debugfs_dir, &items[0],
+                                                 &lbs_debug_fops);
+}
+#endif
diff --git a/drivers/net/wireless/marvell/libertas/debugfs.h b/drivers/net/wireless/marvell/libertas/debugfs.h
new file mode 100644 (file)
index 0000000..f2b9c7f
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef _LBS_DEBUGFS_H_
+#define _LBS_DEBUGFS_H_
+
+void lbs_debugfs_init(void);
+void lbs_debugfs_remove(void);
+
+void lbs_debugfs_init_one(struct lbs_private *priv, struct net_device *dev);
+void lbs_debugfs_remove_one(struct lbs_private *priv);
+
+#endif
diff --git a/drivers/net/wireless/marvell/libertas/decl.h b/drivers/net/wireless/marvell/libertas/decl.h
new file mode 100644 (file)
index 0000000..84a3aa7
--- /dev/null
@@ -0,0 +1,82 @@
+
+/*
+ *  This file contains declaration referring to
+ *  functions defined in other source files
+ */
+
+#ifndef _LBS_DECL_H_
+#define _LBS_DECL_H_
+
+#include <linux/netdevice.h>
+#include <linux/firmware.h>
+#include <linux/nl80211.h>
+
+/* Should be terminated by a NULL entry */
+struct lbs_fw_table {
+       int model;
+       const char *helper;
+       const char *fwname;
+};
+
+struct lbs_private;
+typedef void (*lbs_fw_cb)(struct lbs_private *priv, int ret,
+               const struct firmware *helper, const struct firmware *mainfw);
+
+struct lbs_private;
+struct sk_buff;
+struct net_device;
+struct cmd_ds_command;
+
+
+/* ethtool.c */
+extern const struct ethtool_ops lbs_ethtool_ops;
+
+
+/* tx.c */
+void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count);
+netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb,
+                               struct net_device *dev);
+
+/* rx.c */
+int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *);
+
+
+/* main.c */
+struct lbs_private *lbs_add_card(void *card, struct device *dmdev);
+void lbs_remove_card(struct lbs_private *priv);
+int lbs_start_card(struct lbs_private *priv);
+void lbs_stop_card(struct lbs_private *priv);
+void lbs_host_to_card_done(struct lbs_private *priv);
+
+int lbs_start_iface(struct lbs_private *priv);
+int lbs_stop_iface(struct lbs_private *priv);
+int lbs_set_iface_type(struct lbs_private *priv, enum nl80211_iftype type);
+
+int lbs_rtap_supported(struct lbs_private *priv);
+
+int lbs_set_mac_address(struct net_device *dev, void *addr);
+void lbs_set_multicast_list(struct net_device *dev);
+void lbs_update_mcast(struct lbs_private *priv);
+
+int lbs_suspend(struct lbs_private *priv);
+int lbs_resume(struct lbs_private *priv);
+
+void lbs_queue_event(struct lbs_private *priv, u32 event);
+void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx);
+
+int lbs_enter_auto_deep_sleep(struct lbs_private *priv);
+int lbs_exit_auto_deep_sleep(struct lbs_private *priv);
+
+u32 lbs_fw_index_to_data_rate(u8 index);
+u8 lbs_data_rate_to_fw_index(u32 rate);
+
+int lbs_get_firmware(struct device *dev, u32 card_model,
+                       const struct lbs_fw_table *fw_table,
+                       const struct firmware **helper,
+                       const struct firmware **mainfw);
+int lbs_get_firmware_async(struct lbs_private *priv, struct device *device,
+                          u32 card_model, const struct lbs_fw_table *fw_table,
+                          lbs_fw_cb callback);
+void lbs_wait_for_firmware_load(struct lbs_private *priv);
+
+#endif
diff --git a/drivers/net/wireless/marvell/libertas/defs.h b/drivers/net/wireless/marvell/libertas/defs.h
new file mode 100644 (file)
index 0000000..407784a
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+ * This header file contains global constant/enum definitions,
+ * global variable declaration.
+ */
+#ifndef _LBS_DEFS_H_
+#define _LBS_DEFS_H_
+
+#include <linux/spinlock.h>
+
+#ifdef CONFIG_LIBERTAS_DEBUG
+#define DEBUG
+#define PROC_DEBUG
+#endif
+
+#ifndef DRV_NAME
+#define DRV_NAME "libertas"
+#endif
+
+
+#define LBS_DEB_ENTER  0x00000001
+#define LBS_DEB_LEAVE  0x00000002
+#define LBS_DEB_MAIN   0x00000004
+#define LBS_DEB_NET    0x00000008
+#define LBS_DEB_MESH   0x00000010
+#define LBS_DEB_WEXT   0x00000020
+#define LBS_DEB_IOCTL  0x00000040
+#define LBS_DEB_SCAN   0x00000080
+#define LBS_DEB_ASSOC  0x00000100
+#define LBS_DEB_JOIN   0x00000200
+#define LBS_DEB_11D    0x00000400
+#define LBS_DEB_DEBUGFS        0x00000800
+#define LBS_DEB_ETHTOOL        0x00001000
+#define LBS_DEB_HOST   0x00002000
+#define LBS_DEB_CMD    0x00004000
+#define LBS_DEB_RX     0x00008000
+#define LBS_DEB_TX     0x00010000
+#define LBS_DEB_USB    0x00020000
+#define LBS_DEB_CS     0x00040000
+#define LBS_DEB_FW     0x00080000
+#define LBS_DEB_THREAD 0x00100000
+#define LBS_DEB_HEX    0x00200000
+#define LBS_DEB_SDIO   0x00400000
+#define LBS_DEB_SYSFS  0x00800000
+#define LBS_DEB_SPI    0x01000000
+#define LBS_DEB_CFG80211 0x02000000
+
+extern unsigned int lbs_debug;
+
+#ifdef DEBUG
+#define LBS_DEB_LL(grp, grpnam, fmt, args...) \
+do { if ((lbs_debug & (grp)) == (grp)) \
+  printk(KERN_DEBUG DRV_NAME grpnam "%s: " fmt, \
+         in_interrupt() ? " (INT)" : "", ## args); } while (0)
+#else
+#define LBS_DEB_LL(grp, grpnam, fmt, args...) do {} while (0)
+#endif
+
+#define lbs_deb_enter(grp) \
+  LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s()\n", __func__);
+#define lbs_deb_enter_args(grp, fmt, args...) \
+  LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s(" fmt ")\n", __func__, ## args);
+#define lbs_deb_leave(grp) \
+  LBS_DEB_LL(grp | LBS_DEB_LEAVE, " leave", "%s()\n", __func__);
+#define lbs_deb_leave_args(grp, fmt, args...) \
+  LBS_DEB_LL(grp | LBS_DEB_LEAVE, " leave", "%s(), " fmt "\n", \
+  __func__, ##args);
+#define lbs_deb_main(fmt, args...)      LBS_DEB_LL(LBS_DEB_MAIN, " main", fmt, ##args)
+#define lbs_deb_net(fmt, args...)       LBS_DEB_LL(LBS_DEB_NET, " net", fmt, ##args)
+#define lbs_deb_mesh(fmt, args...)      LBS_DEB_LL(LBS_DEB_MESH, " mesh", fmt, ##args)
+#define lbs_deb_wext(fmt, args...)      LBS_DEB_LL(LBS_DEB_WEXT, " wext", fmt, ##args)
+#define lbs_deb_ioctl(fmt, args...)     LBS_DEB_LL(LBS_DEB_IOCTL, " ioctl", fmt, ##args)
+#define lbs_deb_scan(fmt, args...)      LBS_DEB_LL(LBS_DEB_SCAN, " scan", fmt, ##args)
+#define lbs_deb_assoc(fmt, args...)     LBS_DEB_LL(LBS_DEB_ASSOC, " assoc", fmt, ##args)
+#define lbs_deb_join(fmt, args...)      LBS_DEB_LL(LBS_DEB_JOIN, " join", fmt, ##args)
+#define lbs_deb_11d(fmt, args...)       LBS_DEB_LL(LBS_DEB_11D, " 11d", fmt, ##args)
+#define lbs_deb_debugfs(fmt, args...)   LBS_DEB_LL(LBS_DEB_DEBUGFS, " debugfs", fmt, ##args)
+#define lbs_deb_ethtool(fmt, args...)   LBS_DEB_LL(LBS_DEB_ETHTOOL, " ethtool", fmt, ##args)
+#define lbs_deb_host(fmt, args...)      LBS_DEB_LL(LBS_DEB_HOST, " host", fmt, ##args)
+#define lbs_deb_cmd(fmt, args...)       LBS_DEB_LL(LBS_DEB_CMD, " cmd", fmt, ##args)
+#define lbs_deb_rx(fmt, args...)        LBS_DEB_LL(LBS_DEB_RX, " rx", fmt, ##args)
+#define lbs_deb_tx(fmt, args...)        LBS_DEB_LL(LBS_DEB_TX, " tx", fmt, ##args)
+#define lbs_deb_fw(fmt, args...)        LBS_DEB_LL(LBS_DEB_FW, " fw", fmt, ##args)
+#define lbs_deb_usb(fmt, args...)       LBS_DEB_LL(LBS_DEB_USB, " usb", fmt, ##args)
+#define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usbd", "%s:" fmt, dev_name(dev), ##args)
+#define lbs_deb_cs(fmt, args...)        LBS_DEB_LL(LBS_DEB_CS, " cs", fmt, ##args)
+#define lbs_deb_thread(fmt, args...)    LBS_DEB_LL(LBS_DEB_THREAD, " thread", fmt, ##args)
+#define lbs_deb_sdio(fmt, args...)      LBS_DEB_LL(LBS_DEB_SDIO, " sdio", fmt, ##args)
+#define lbs_deb_sysfs(fmt, args...)     LBS_DEB_LL(LBS_DEB_SYSFS, " sysfs", fmt, ##args)
+#define lbs_deb_spi(fmt, args...)       LBS_DEB_LL(LBS_DEB_SPI, " spi", fmt, ##args)
+#define lbs_deb_cfg80211(fmt, args...)  LBS_DEB_LL(LBS_DEB_CFG80211, " cfg80211", fmt, ##args)
+
+#ifdef DEBUG
+static inline void lbs_deb_hex(unsigned int grp, const char *prompt,
+                              const u8 *buf, int len)
+{
+       int i = 0;
+
+       if (len &&
+           (lbs_debug & LBS_DEB_HEX) &&
+           (lbs_debug & grp))
+       {
+               for (i = 1; i <= len; i++) {
+                       if ((i & 0xf) == 1) {
+                               if (i != 1)
+                                       printk("\n");
+                               printk(DRV_NAME " %s: ", prompt);
+                       }
+                       printk("%02x ", (u8) * buf);
+                       buf++;
+               }
+               printk("\n");
+       }
+}
+#else
+#define lbs_deb_hex(grp,prompt,buf,len)        do {} while (0)
+#endif
+
+
+
+/* Buffer Constants */
+
+/*     The size of SQ memory PPA, DPA are 8 DWORDs, that keep the physical
+ *     addresses of TxPD buffers. Station has only 8 TxPD available, Whereas
+ *     driver has more local TxPDs. Each TxPD on the host memory is associated
+ *     with a Tx control node. The driver maintains 8 RxPD descriptors for
+ *     station firmware to store Rx packet information.
+ *
+ *     Current version of MAC has a 32x6 multicast address buffer.
+ *
+ *     802.11b can have up to  14 channels, the driver keeps the
+ *     BSSID(MAC address) of each APs or Ad hoc stations it has sensed.
+ */
+
+#define MRVDRV_MAX_MULTICAST_LIST_SIZE 32
+#define LBS_NUM_CMD_BUFFERS             10
+#define LBS_CMD_BUFFER_SIZE             (2 * 1024)
+#define MRVDRV_MAX_CHANNEL_SIZE                14
+#define MRVDRV_ASSOCIATION_TIME_OUT    255
+#define MRVDRV_SNAP_HEADER_LEN          8
+
+#define        LBS_UPLD_SIZE                   2312
+#define DEV_NAME_LEN                   32
+
+/* Wake criteria for HOST_SLEEP_CFG command */
+#define EHS_WAKE_ON_BROADCAST_DATA     0x0001
+#define EHS_WAKE_ON_UNICAST_DATA       0x0002
+#define EHS_WAKE_ON_MAC_EVENT          0x0004
+#define EHS_WAKE_ON_MULTICAST_DATA     0x0008
+#define EHS_REMOVE_WAKEUP              0xFFFFFFFF
+/* Wake rules for Host_Sleep_CFG command */
+#define WOL_RULE_NET_TYPE_INFRA_OR_IBSS        0x00
+#define WOL_RULE_NET_TYPE_MESH         0x10
+#define WOL_RULE_ADDR_TYPE_BCAST       0x01
+#define WOL_RULE_ADDR_TYPE_MCAST       0x08
+#define WOL_RULE_ADDR_TYPE_UCAST       0x02
+#define WOL_RULE_OP_AND                        0x01
+#define WOL_RULE_OP_OR                 0x02
+#define WOL_RULE_OP_INVALID            0xFF
+#define WOL_RESULT_VALID_CMD           0
+#define WOL_RESULT_NOSPC_ERR           1
+#define WOL_RESULT_EEXIST_ERR          2
+
+/* Misc constants */
+/* This section defines 802.11 specific contants */
+
+#define MRVDRV_MAX_BSS_DESCRIPTS               16
+#define MRVDRV_MAX_REGION_CODE                 6
+
+#define MRVDRV_DEFAULT_LISTEN_INTERVAL         10
+
+#define        MRVDRV_CHANNELS_PER_SCAN                4
+#define        MRVDRV_MAX_CHANNELS_PER_SCAN            14
+
+#define MRVDRV_MIN_BEACON_INTERVAL             20
+#define MRVDRV_MAX_BEACON_INTERVAL             1000
+#define MRVDRV_BEACON_INTERVAL                 100
+
+#define MARVELL_MESH_IE_LENGTH         9
+
+/*
+ * Values used to populate the struct mrvl_mesh_ie.  The only time you need this
+ * is when enabling the mesh using CMD_MESH_CONFIG.
+ */
+#define MARVELL_MESH_IE_TYPE           4
+#define MARVELL_MESH_IE_SUBTYPE                0
+#define MARVELL_MESH_IE_VERSION                0
+#define MARVELL_MESH_PROTO_ID_HWMP     0
+#define MARVELL_MESH_METRIC_ID         0
+#define MARVELL_MESH_CAPABILITY                0
+
+/* INT status Bit Definition */
+#define MRVDRV_TX_DNLD_RDY             0x0001
+#define MRVDRV_RX_UPLD_RDY             0x0002
+#define MRVDRV_CMD_DNLD_RDY            0x0004
+#define MRVDRV_CMD_UPLD_RDY            0x0008
+#define MRVDRV_CARDEVENT               0x0010
+
+/* Automatic TX control default levels */
+#define POW_ADAPT_DEFAULT_P0 13
+#define POW_ADAPT_DEFAULT_P1 15
+#define POW_ADAPT_DEFAULT_P2 18
+#define TPC_DEFAULT_P0 5
+#define TPC_DEFAULT_P1 10
+#define TPC_DEFAULT_P2 13
+
+/* TxPD status */
+
+/*
+ *     Station firmware use TxPD status field to report final Tx transmit
+ *     result, Bit masks are used to present combined situations.
+ */
+
+#define MRVDRV_TxPD_POWER_MGMT_NULL_PACKET 0x01
+#define MRVDRV_TxPD_POWER_MGMT_LAST_PACKET 0x08
+
+/* Tx mesh flag */
+/*
+ * Currently we are using normal WDS flag as mesh flag.
+ * TODO: change to proper mesh flag when MAC understands it.
+ */
+#define TxPD_CONTROL_WDS_FRAME (1<<17)
+#define TxPD_MESH_FRAME TxPD_CONTROL_WDS_FRAME
+
+/* Mesh interface ID */
+#define MESH_IFACE_ID                                  0x0001
+/* Mesh id should be in bits 14-13-12 */
+#define MESH_IFACE_BIT_OFFSET                          0x000c
+/* Mesh enable bit in FW capability */
+#define MESH_CAPINFO_ENABLE_MASK                       (1<<16)
+
+/* FW definition from Marvell v4 */
+#define MRVL_FW_V4                                     (0x04)
+/* FW definition from Marvell v5 */
+#define MRVL_FW_V5                                     (0x05)
+/* FW definition from Marvell v10 */
+#define MRVL_FW_V10                                    (0x0a)
+/* FW major revision definition */
+#define MRVL_FW_MAJOR_REV(x)                           ((x)>>24)
+
+/* RxPD status */
+
+#define MRVDRV_RXPD_STATUS_OK                0x0001
+
+/* RxPD status - Received packet types */
+/* Rx mesh flag */
+/*
+ * Currently we are using normal WDS flag as mesh flag.
+ * TODO: change to proper mesh flag when MAC understands it.
+ */
+#define RxPD_CONTROL_WDS_FRAME (0x40)
+#define RxPD_MESH_FRAME RxPD_CONTROL_WDS_FRAME
+
+/* RSSI-related defines */
+/*
+ *     RSSI constants are used to implement 802.11 RSSI threshold
+ *     indication. if the Rx packet signal got too weak for 5 consecutive
+ *     times, miniport driver (driver) will report this event to wrapper
+ */
+
+#define MRVDRV_NF_DEFAULT_SCAN_VALUE           (-96)
+
+/* RTS/FRAG related defines */
+#define MRVDRV_RTS_MIN_VALUE           0
+#define MRVDRV_RTS_MAX_VALUE           2347
+#define MRVDRV_FRAG_MIN_VALUE          256
+#define MRVDRV_FRAG_MAX_VALUE          2346
+
+/* This is for firmware specific length */
+#define EXTRA_LEN      36
+
+#define MRVDRV_ETH_TX_PACKET_BUFFER_SIZE \
+       (ETH_FRAME_LEN + sizeof(struct txpd) + EXTRA_LEN)
+
+#define MRVDRV_ETH_RX_PACKET_BUFFER_SIZE \
+       (ETH_FRAME_LEN + sizeof(struct rxpd) \
+        + MRVDRV_SNAP_HEADER_LEN + EXTRA_LEN)
+
+#define        CMD_F_HOSTCMD           (1 << 0)
+#define FW_CAPINFO_WPA         (1 << 0)
+#define FW_CAPINFO_PS                  (1 << 1)
+#define FW_CAPINFO_FIRMWARE_UPGRADE    (1 << 13)
+#define FW_CAPINFO_BOOT2_UPGRADE       (1<<14)
+#define FW_CAPINFO_PERSISTENT_CONFIG   (1<<15)
+
+#define KEY_LEN_WPA_AES                        16
+#define KEY_LEN_WPA_TKIP               32
+#define KEY_LEN_WEP_104                        13
+#define KEY_LEN_WEP_40                 5
+
+#define RF_ANTENNA_1           0x1
+#define RF_ANTENNA_2           0x2
+#define RF_ANTENNA_AUTO                0xFFFF
+
+#define        BAND_B                  (0x01)
+#define        BAND_G                  (0x02)
+#define ALL_802_11_BANDS       (BAND_B | BAND_G)
+
+#define MAX_RATES                      14
+
+#define        MAX_LEDS                        8
+
+/* Global Variable Declaration */
+extern const char lbs_driver_version[];
+extern u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE];
+
+
+/* ENUM definition */
+/* SNRNF_TYPE */
+enum SNRNF_TYPE {
+       TYPE_BEACON = 0,
+       TYPE_RXPD,
+       MAX_TYPE_B
+};
+
+/* SNRNF_DATA */
+enum SNRNF_DATA {
+       TYPE_NOAVG = 0,
+       TYPE_AVG,
+       MAX_TYPE_AVG
+};
+
+/* LBS_802_11_POWER_MODE */
+enum LBS_802_11_POWER_MODE {
+       LBS802_11POWERMODECAM,
+       LBS802_11POWERMODEMAX_PSP,
+       LBS802_11POWERMODEFAST_PSP,
+       /* not a real mode, defined as an upper bound */
+       LBS802_11POWEMODEMAX
+};
+
+/* PS_STATE */
+enum PS_STATE {
+       PS_STATE_FULL_POWER,
+       PS_STATE_AWAKE,
+       PS_STATE_PRE_SLEEP,
+       PS_STATE_SLEEP
+};
+
+/* DNLD_STATE */
+enum DNLD_STATE {
+       DNLD_RES_RECEIVED,
+       DNLD_DATA_SENT,
+       DNLD_CMD_SENT,
+       DNLD_BOOTCMD_SENT,
+};
+
+/* LBS_MEDIA_STATE */
+enum LBS_MEDIA_STATE {
+       LBS_CONNECTED,
+       LBS_DISCONNECTED
+};
+
+/* LBS_802_11_PRIVACY_FILTER */
+enum LBS_802_11_PRIVACY_FILTER {
+       LBS802_11PRIVFILTERACCEPTALL,
+       LBS802_11PRIVFILTER8021XWEP
+};
+
+/* mv_ms_type */
+enum mv_ms_type {
+       MVMS_DAT = 0,
+       MVMS_CMD = 1,
+       MVMS_TXDONE = 2,
+       MVMS_EVENT
+};
+
+/* KEY_TYPE_ID */
+enum KEY_TYPE_ID {
+       KEY_TYPE_ID_WEP = 0,
+       KEY_TYPE_ID_TKIP,
+       KEY_TYPE_ID_AES
+};
+
+/* KEY_INFO_WPA (applies to both TKIP and AES/CCMP) */
+enum KEY_INFO_WPA {
+       KEY_INFO_WPA_MCAST = 0x01,
+       KEY_INFO_WPA_UNICAST = 0x02,
+       KEY_INFO_WPA_ENABLED = 0x04
+};
+
+/* Default values for fwt commands. */
+#define FWT_DEFAULT_METRIC 0
+#define FWT_DEFAULT_DIR 1
+/* Default Rate, 11Mbps */
+#define FWT_DEFAULT_RATE 3
+#define FWT_DEFAULT_SSN 0xffffffff
+#define FWT_DEFAULT_DSN 0
+#define FWT_DEFAULT_HOPCOUNT 0
+#define FWT_DEFAULT_TTL 0
+#define FWT_DEFAULT_EXPIRATION 0
+#define FWT_DEFAULT_SLEEPMODE 0
+#define FWT_DEFAULT_SNR 0
+
+#endif
diff --git a/drivers/net/wireless/marvell/libertas/dev.h b/drivers/net/wireless/marvell/libertas/dev.h
new file mode 100644 (file)
index 0000000..6bd1608
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * This file contains definitions and data structures specific
+ * to Marvell 802.11 NIC. It contains the Device Information
+ * structure struct lbs_private..
+ */
+#ifndef _LBS_DEV_H_
+#define _LBS_DEV_H_
+
+#include "defs.h"
+#include "decl.h"
+#include "host.h"
+
+#include <linux/kfifo.h>
+
+/* sleep_params */
+struct sleep_params {
+       uint16_t sp_error;
+       uint16_t sp_offset;
+       uint16_t sp_stabletime;
+       uint8_t  sp_calcontrol;
+       uint8_t  sp_extsleepclk;
+       uint16_t sp_reserved;
+};
+
+/* Mesh statistics */
+struct lbs_mesh_stats {
+       u32     fwd_bcast_cnt;          /* Fwd: Broadcast counter */
+       u32     fwd_unicast_cnt;        /* Fwd: Unicast counter */
+       u32     fwd_drop_ttl;           /* Fwd: TTL zero */
+       u32     fwd_drop_rbt;           /* Fwd: Recently Broadcasted */
+       u32     fwd_drop_noroute;       /* Fwd: No route to Destination */
+       u32     fwd_drop_nobuf;         /* Fwd: Run out of internal buffers */
+       u32     drop_blind;             /* Rx:  Dropped by blinding table */
+       u32     tx_failed_cnt;          /* Tx:  Failed transmissions */
+};
+
+/* Private structure for the MV device */
+struct lbs_private {
+
+       /* Basic networking */
+       struct net_device *dev;
+       u32 connect_status;
+       struct work_struct mcast_work;
+       u32 nr_of_multicastmacaddr;
+       u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN];
+
+       /* CFG80211 */
+       struct wireless_dev *wdev;
+       bool wiphy_registered;
+       struct cfg80211_scan_request *scan_req;
+       u8 assoc_bss[ETH_ALEN];
+       u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
+       u8 disassoc_reason;
+
+       /* Mesh */
+       struct net_device *mesh_dev; /* Virtual device */
+#ifdef CONFIG_LIBERTAS_MESH
+       struct lbs_mesh_stats mstats;
+       uint16_t mesh_tlv;
+       u8 mesh_ssid[IEEE80211_MAX_SSID_LEN + 1];
+       u8 mesh_ssid_len;
+       u8 mesh_channel;
+#endif
+
+       /* Debugfs */
+       struct dentry *debugfs_dir;
+       struct dentry *debugfs_debug;
+       struct dentry *debugfs_files[6];
+       struct dentry *events_dir;
+       struct dentry *debugfs_events_files[6];
+       struct dentry *regs_dir;
+       struct dentry *debugfs_regs_files[6];
+
+       /* Hardware debugging */
+       u32 mac_offset;
+       u32 bbp_offset;
+       u32 rf_offset;
+
+       /* Power management */
+       u16 psmode;
+       u32 psstate;
+       u8 needtowakeup;
+
+       /* Deep sleep */
+       int is_deep_sleep;
+       int deep_sleep_required;
+       int is_auto_deep_sleep_enabled;
+       int wakeup_dev_required;
+       int is_activity_detected;
+       int auto_deep_sleep_timeout; /* in ms */
+       wait_queue_head_t ds_awake_q;
+       struct timer_list auto_deepsleep_timer;
+
+       /* Host sleep*/
+       int is_host_sleep_configured;
+       int is_host_sleep_activated;
+       wait_queue_head_t host_sleep_q;
+
+       /* Hardware access */
+       void *card;
+       bool iface_running;
+       u8 fw_ready;
+       u8 surpriseremoved;
+       u8 setup_fw_on_resume;
+       int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb);
+       void (*reset_card) (struct lbs_private *priv);
+       int (*power_save) (struct lbs_private *priv);
+       int (*power_restore) (struct lbs_private *priv);
+       int (*enter_deep_sleep) (struct lbs_private *priv);
+       int (*exit_deep_sleep) (struct lbs_private *priv);
+       int (*reset_deep_sleep_wakeup) (struct lbs_private *priv);
+
+       /* Adapter info (from EEPROM) */
+       u32 fwrelease;
+       u32 fwcapinfo;
+       u16 regioncode;
+       u8 current_addr[ETH_ALEN];
+       u8 copied_hwaddr;
+
+       /* Command download */
+       u8 dnld_sent;
+       /* bit0 1/0=data_sent/data_tx_done,
+          bit1 1/0=cmd_sent/cmd_tx_done,
+          all other bits reserved 0 */
+       u16 seqnum;
+       struct cmd_ctrl_node *cmd_array;
+       struct cmd_ctrl_node *cur_cmd;
+       struct list_head cmdfreeq;    /* free command buffers */
+       struct list_head cmdpendingq; /* pending command buffers */
+       struct timer_list command_timer;
+       int cmd_timed_out;
+
+       /* Command responses sent from the hardware to the driver */
+       u8 resp_idx;
+       u8 resp_buf[2][LBS_UPLD_SIZE];
+       u32 resp_len[2];
+
+       /* Events sent from hardware to driver */
+       struct kfifo event_fifo;
+
+       /* thread to service interrupts */
+       struct task_struct *main_thread;
+       wait_queue_head_t waitq;
+       struct workqueue_struct *work_thread;
+
+       /* Encryption stuff */
+       u8 authtype_auto;
+       u8 wep_tx_key;
+       u8 wep_key[4][WLAN_KEY_LEN_WEP104];
+       u8 wep_key_len[4];
+
+       /* Wake On LAN */
+       uint32_t wol_criteria;
+       uint8_t wol_gpio;
+       uint8_t wol_gap;
+       bool ehs_remove_supported;
+
+       /* Transmitting */
+       int tx_pending_len;             /* -1 while building packet */
+       u8 tx_pending_buf[LBS_UPLD_SIZE];
+       /* protected by hard_start_xmit serialization */
+       u8 txretrycount;
+       struct sk_buff *currenttxskb;
+       struct timer_list tx_lockup_timer;
+
+       /* Locks */
+       struct mutex lock;
+       spinlock_t driver_lock;
+
+       /* NIC/link operation characteristics */
+       u16 mac_control;
+       u8 radio_on;
+       u8 cur_rate;
+       u8 channel;
+       s16 txpower_cur;
+       s16 txpower_min;
+       s16 txpower_max;
+
+       /* Scanning */
+       struct delayed_work scan_work;
+       int scan_channel;
+       /* Queue of things waiting for scan completion */
+       wait_queue_head_t scan_q;
+       /* Whether the scan was initiated internally and not by cfg80211 */
+       bool internal_scan;
+
+       /* Firmware load */
+       u32 fw_model;
+       wait_queue_head_t fw_waitq;
+       struct device *fw_device;
+       const struct firmware *helper_fw;
+       const struct lbs_fw_table *fw_table;
+       const struct lbs_fw_table *fw_iter;
+       lbs_fw_cb fw_callback;
+};
+
+extern struct cmd_confirm_sleep confirm_sleep;
+
+/* Check if there is an interface active. */
+static inline int lbs_iface_active(struct lbs_private *priv)
+{
+       int r;
+
+       r = netif_running(priv->dev);
+       if (priv->mesh_dev)
+               r |= netif_running(priv->mesh_dev);
+
+       return r;
+}
+
+#endif
diff --git a/drivers/net/wireless/marvell/libertas/ethtool.c b/drivers/net/wireless/marvell/libertas/ethtool.c
new file mode 100644 (file)
index 0000000..f955b2d
--- /dev/null
@@ -0,0 +1,120 @@
+#include <linux/hardirq.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+
+#include "decl.h"
+#include "cmd.h"
+#include "mesh.h"
+
+
+static void lbs_ethtool_get_drvinfo(struct net_device *dev,
+                                        struct ethtool_drvinfo *info)
+{
+       struct lbs_private *priv = dev->ml_priv;
+
+       snprintf(info->fw_version, sizeof(info->fw_version),
+               "%u.%u.%u.p%u",
+               priv->fwrelease >> 24 & 0xff,
+               priv->fwrelease >> 16 & 0xff,
+               priv->fwrelease >>  8 & 0xff,
+               priv->fwrelease       & 0xff);
+       strlcpy(info->driver, "libertas", sizeof(info->driver));
+       strlcpy(info->version, lbs_driver_version, sizeof(info->version));
+}
+
+/*
+ * All 8388 parts have 16KiB EEPROM size at the time of writing.
+ * In case that changes this needs fixing.
+ */
+#define LBS_EEPROM_LEN 16384
+
+static int lbs_ethtool_get_eeprom_len(struct net_device *dev)
+{
+       return LBS_EEPROM_LEN;
+}
+
+static int lbs_ethtool_get_eeprom(struct net_device *dev,
+                                  struct ethtool_eeprom *eeprom, u8 * bytes)
+{
+       struct lbs_private *priv = dev->ml_priv;
+       struct cmd_ds_802_11_eeprom_access cmd;
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_ETHTOOL);
+
+       if (eeprom->offset + eeprom->len > LBS_EEPROM_LEN ||
+           eeprom->len > LBS_EEPROM_READ_LEN) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       cmd.hdr.size = cpu_to_le16(sizeof(struct cmd_ds_802_11_eeprom_access) -
+               LBS_EEPROM_READ_LEN + eeprom->len);
+       cmd.action = cpu_to_le16(CMD_ACT_GET);
+       cmd.offset = cpu_to_le16(eeprom->offset);
+       cmd.len    = cpu_to_le16(eeprom->len);
+       ret = lbs_cmd_with_response(priv, CMD_802_11_EEPROM_ACCESS, &cmd);
+       if (!ret)
+               memcpy(bytes, cmd.value, eeprom->len);
+
+out:
+       lbs_deb_leave_args(LBS_DEB_ETHTOOL, "ret %d", ret);
+        return ret;
+}
+
+static void lbs_ethtool_get_wol(struct net_device *dev,
+                               struct ethtool_wolinfo *wol)
+{
+       struct lbs_private *priv = dev->ml_priv;
+
+       wol->supported = WAKE_UCAST|WAKE_MCAST|WAKE_BCAST|WAKE_PHY;
+
+       if (priv->wol_criteria == EHS_REMOVE_WAKEUP)
+               return;
+
+       if (priv->wol_criteria & EHS_WAKE_ON_UNICAST_DATA)
+               wol->wolopts |= WAKE_UCAST;
+       if (priv->wol_criteria & EHS_WAKE_ON_MULTICAST_DATA)
+               wol->wolopts |= WAKE_MCAST;
+       if (priv->wol_criteria & EHS_WAKE_ON_BROADCAST_DATA)
+               wol->wolopts |= WAKE_BCAST;
+       if (priv->wol_criteria & EHS_WAKE_ON_MAC_EVENT)
+               wol->wolopts |= WAKE_PHY;
+}
+
+static int lbs_ethtool_set_wol(struct net_device *dev,
+                              struct ethtool_wolinfo *wol)
+{
+       struct lbs_private *priv = dev->ml_priv;
+
+       if (wol->wolopts & ~(WAKE_UCAST|WAKE_MCAST|WAKE_BCAST|WAKE_PHY))
+               return -EOPNOTSUPP;
+
+       priv->wol_criteria = 0;
+       if (wol->wolopts & WAKE_UCAST)
+               priv->wol_criteria |= EHS_WAKE_ON_UNICAST_DATA;
+       if (wol->wolopts & WAKE_MCAST)
+               priv->wol_criteria |= EHS_WAKE_ON_MULTICAST_DATA;
+       if (wol->wolopts & WAKE_BCAST)
+               priv->wol_criteria |= EHS_WAKE_ON_BROADCAST_DATA;
+       if (wol->wolopts & WAKE_PHY)
+               priv->wol_criteria |= EHS_WAKE_ON_MAC_EVENT;
+       if (wol->wolopts == 0)
+               priv->wol_criteria |= EHS_REMOVE_WAKEUP;
+       return 0;
+}
+
+const struct ethtool_ops lbs_ethtool_ops = {
+       .get_drvinfo = lbs_ethtool_get_drvinfo,
+       .get_eeprom =  lbs_ethtool_get_eeprom,
+       .get_eeprom_len = lbs_ethtool_get_eeprom_len,
+#ifdef CONFIG_LIBERTAS_MESH
+       .get_sset_count = lbs_mesh_ethtool_get_sset_count,
+       .get_ethtool_stats = lbs_mesh_ethtool_get_stats,
+       .get_strings = lbs_mesh_ethtool_get_strings,
+#endif
+       .get_wol = lbs_ethtool_get_wol,
+       .set_wol = lbs_ethtool_set_wol,
+};
+
diff --git a/drivers/net/wireless/marvell/libertas/firmware.c b/drivers/net/wireless/marvell/libertas/firmware.c
new file mode 100644 (file)
index 0000000..51b92b5
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Firmware loading and handling functions.
+ */
+
+#include <linux/sched.h>
+#include <linux/firmware.h>
+#include <linux/module.h>
+
+#include "dev.h"
+#include "decl.h"
+
+static void load_next_firmware_from_table(struct lbs_private *private);
+
+static void lbs_fw_loaded(struct lbs_private *priv, int ret,
+       const struct firmware *helper, const struct firmware *mainfw)
+{
+       unsigned long flags;
+
+       lbs_deb_fw("firmware load complete, code %d\n", ret);
+
+       /* User must free helper/mainfw */
+       priv->fw_callback(priv, ret, helper, mainfw);
+
+       spin_lock_irqsave(&priv->driver_lock, flags);
+       priv->fw_callback = NULL;
+       wake_up(&priv->fw_waitq);
+       spin_unlock_irqrestore(&priv->driver_lock, flags);
+}
+
+static void do_load_firmware(struct lbs_private *priv, const char *name,
+       void (*cb)(const struct firmware *fw, void *context))
+{
+       int ret;
+
+       lbs_deb_fw("Requesting %s\n", name);
+       ret = request_firmware_nowait(THIS_MODULE, true, name,
+                       priv->fw_device, GFP_KERNEL, priv, cb);
+       if (ret) {
+               lbs_deb_fw("request_firmware_nowait error %d\n", ret);
+               lbs_fw_loaded(priv, ret, NULL, NULL);
+       }
+}
+
+static void main_firmware_cb(const struct firmware *firmware, void *context)
+{
+       struct lbs_private *priv = context;
+
+       if (!firmware) {
+               /* Failed to find firmware: try next table entry */
+               load_next_firmware_from_table(priv);
+               return;
+       }
+
+       /* Firmware found! */
+       lbs_fw_loaded(priv, 0, priv->helper_fw, firmware);
+       if (priv->helper_fw) {
+               release_firmware (priv->helper_fw);
+               priv->helper_fw = NULL;
+       }
+       release_firmware (firmware);
+}
+
+static void helper_firmware_cb(const struct firmware *firmware, void *context)
+{
+       struct lbs_private *priv = context;
+
+       if (!firmware) {
+               /* Failed to find firmware: try next table entry */
+               load_next_firmware_from_table(priv);
+               return;
+       }
+
+       /* Firmware found! */
+       if (priv->fw_iter->fwname) {
+               priv->helper_fw = firmware;
+               do_load_firmware(priv, priv->fw_iter->fwname, main_firmware_cb);
+       } else {
+               /* No main firmware needed for this helper --> success! */
+               lbs_fw_loaded(priv, 0, firmware, NULL);
+       }
+}
+
+static void load_next_firmware_from_table(struct lbs_private *priv)
+{
+       const struct lbs_fw_table *iter;
+
+       if (!priv->fw_iter)
+               iter = priv->fw_table;
+       else
+               iter = ++priv->fw_iter;
+
+       if (priv->helper_fw) {
+               release_firmware(priv->helper_fw);
+               priv->helper_fw = NULL;
+       }
+
+next:
+       if (!iter->helper) {
+               /* End of table hit. */
+               lbs_fw_loaded(priv, -ENOENT, NULL, NULL);
+               return;
+       }
+
+       if (iter->model != priv->fw_model) {
+               iter++;
+               goto next;
+       }
+
+       priv->fw_iter = iter;
+       do_load_firmware(priv, iter->helper, helper_firmware_cb);
+}
+
+void lbs_wait_for_firmware_load(struct lbs_private *priv)
+{
+       wait_event(priv->fw_waitq, priv->fw_callback == NULL);
+}
+
+/**
+ *  lbs_get_firmware_async - Retrieves firmware asynchronously. Can load
+ *  either a helper firmware and a main firmware (2-stage), or just the helper.
+ *
+ *  @priv:      Pointer to lbs_private instance
+ *  @dev:      A pointer to &device structure
+ *  @card_model: Bus-specific card model ID used to filter firmware table
+ *             elements
+ *  @fw_table: Table of firmware file names and device model numbers
+ *             terminated by an entry with a NULL helper name
+ *     @callback: User callback to invoke when firmware load succeeds or fails.
+ */
+int lbs_get_firmware_async(struct lbs_private *priv, struct device *device,
+                           u32 card_model, const struct lbs_fw_table *fw_table,
+                           lbs_fw_cb callback)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->driver_lock, flags);
+       if (priv->fw_callback) {
+               lbs_deb_fw("firmware load already in progress\n");
+               spin_unlock_irqrestore(&priv->driver_lock, flags);
+               return -EBUSY;
+       }
+
+       priv->fw_device = device;
+       priv->fw_callback = callback;
+       priv->fw_table = fw_table;
+       priv->fw_iter = NULL;
+       priv->fw_model = card_model;
+       spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+       lbs_deb_fw("Starting async firmware load\n");
+       load_next_firmware_from_table(priv);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(lbs_get_firmware_async);
+
+/**
+ *  lbs_get_firmware - Retrieves two-stage firmware
+ *
+ *  @dev:      A pointer to &device structure
+ *  @card_model: Bus-specific card model ID used to filter firmware table
+ *             elements
+ *  @fw_table: Table of firmware file names and device model numbers
+ *             terminated by an entry with a NULL helper name
+ *  @helper:   On success, the helper firmware; caller must free
+ *  @mainfw:   On success, the main firmware; caller must free
+ *
+ * Deprecated: use lbs_get_firmware_async() instead.
+ *
+ *  returns:           0 on success, non-zero on failure
+ */
+int lbs_get_firmware(struct device *dev, u32 card_model,
+                       const struct lbs_fw_table *fw_table,
+                       const struct firmware **helper,
+                       const struct firmware **mainfw)
+{
+       const struct lbs_fw_table *iter;
+       int ret;
+
+       BUG_ON(helper == NULL);
+       BUG_ON(mainfw == NULL);
+
+       /* Search for firmware to use from the table. */
+       iter = fw_table;
+       while (iter && iter->helper) {
+               if (iter->model != card_model)
+                       goto next;
+
+               if (*helper == NULL) {
+                       ret = request_firmware(helper, iter->helper, dev);
+                       if (ret)
+                               goto next;
+
+                       /* If the device has one-stage firmware (ie cf8305) and
+                        * we've got it then we don't need to bother with the
+                        * main firmware.
+                        */
+                       if (iter->fwname == NULL)
+                               return 0;
+               }
+
+               if (*mainfw == NULL) {
+                       ret = request_firmware(mainfw, iter->fwname, dev);
+                       if (ret) {
+                               /* Clear the helper to ensure we don't have
+                                * mismatched firmware pairs.
+                                */
+                               release_firmware(*helper);
+                               *helper = NULL;
+                       }
+               }
+
+               if (*helper && *mainfw)
+                       return 0;
+
+  next:
+               iter++;
+       }
+
+       /* Failed */
+       release_firmware(*helper);
+       *helper = NULL;
+       release_firmware(*mainfw);
+       *mainfw = NULL;
+
+       return -ENOENT;
+}
+EXPORT_SYMBOL_GPL(lbs_get_firmware);
diff --git a/drivers/net/wireless/marvell/libertas/host.h b/drivers/net/wireless/marvell/libertas/host.h
new file mode 100644 (file)
index 0000000..96726f7
--- /dev/null
@@ -0,0 +1,978 @@
+/*
+ * This file function prototypes, data structure
+ * and  definitions for all the host/station commands
+ */
+
+#ifndef _LBS_HOST_H_
+#define _LBS_HOST_H_
+
+#include "types.h"
+#include "defs.h"
+
+#define DEFAULT_AD_HOC_CHANNEL                  6
+
+#define CMD_OPTION_WAITFORRSP                   0x0002
+
+/* Host command IDs */
+
+/*
+ * Return command are almost always the same as the host command, but with
+ * bit 15 set high.  There are a few exceptions, though...
+ */
+#define CMD_RET(cmd)                            (0x8000 | cmd)
+
+/* Return command convention exceptions: */
+#define CMD_RET_802_11_ASSOCIATE                0x8012
+
+/* Command codes */
+#define CMD_GET_HW_SPEC                         0x0003
+#define CMD_EEPROM_UPDATE                       0x0004
+#define CMD_802_11_RESET                        0x0005
+#define CMD_802_11_SCAN                         0x0006
+#define CMD_802_11_GET_LOG                      0x000b
+#define CMD_MAC_MULTICAST_ADR                   0x0010
+#define CMD_802_11_AUTHENTICATE                 0x0011
+#define CMD_802_11_EEPROM_ACCESS                0x0059
+#define CMD_802_11_ASSOCIATE                    0x0050
+#define CMD_802_11_SET_WEP                      0x0013
+#define CMD_802_11_GET_STAT                     0x0014
+#define CMD_802_3_GET_STAT                      0x0015
+#define CMD_802_11_SNMP_MIB                     0x0016
+#define CMD_MAC_REG_MAP                         0x0017
+#define CMD_BBP_REG_MAP                         0x0018
+#define CMD_MAC_REG_ACCESS                      0x0019
+#define CMD_BBP_REG_ACCESS                      0x001a
+#define CMD_RF_REG_ACCESS                       0x001b
+#define CMD_802_11_RADIO_CONTROL                0x001c
+#define CMD_802_11_RF_CHANNEL                   0x001d
+#define CMD_802_11_RF_TX_POWER                  0x001e
+#define CMD_802_11_RSSI                         0x001f
+#define CMD_802_11_RF_ANTENNA                   0x0020
+#define CMD_802_11_PS_MODE                      0x0021
+#define CMD_802_11_DATA_RATE                    0x0022
+#define CMD_RF_REG_MAP                          0x0023
+#define CMD_802_11_DEAUTHENTICATE               0x0024
+#define CMD_802_11_REASSOCIATE                  0x0025
+#define CMD_MAC_CONTROL                         0x0028
+#define CMD_802_11_AD_HOC_START                 0x002b
+#define CMD_802_11_AD_HOC_JOIN                  0x002c
+#define CMD_802_11_QUERY_TKIP_REPLY_CNTRS       0x002e
+#define CMD_802_11_ENABLE_RSN                   0x002f
+#define CMD_802_11_SET_AFC                      0x003c
+#define CMD_802_11_GET_AFC                      0x003d
+#define CMD_802_11_DEEP_SLEEP                   0x003e
+#define CMD_802_11_AD_HOC_STOP                  0x0040
+#define CMD_802_11_HOST_SLEEP_CFG               0x0043
+#define CMD_802_11_WAKEUP_CONFIRM               0x0044
+#define CMD_802_11_HOST_SLEEP_ACTIVATE          0x0045
+#define CMD_802_11_BEACON_STOP                  0x0049
+#define CMD_802_11_MAC_ADDRESS                  0x004d
+#define CMD_802_11_LED_GPIO_CTRL                0x004e
+#define CMD_802_11_BAND_CONFIG                  0x0058
+#define CMD_GSPI_BUS_CONFIG                     0x005a
+#define CMD_802_11D_DOMAIN_INFO                 0x005b
+#define CMD_802_11_KEY_MATERIAL                 0x005e
+#define CMD_802_11_SLEEP_PARAMS                 0x0066
+#define CMD_802_11_INACTIVITY_TIMEOUT           0x0067
+#define CMD_802_11_SLEEP_PERIOD                 0x0068
+#define CMD_802_11_TPC_CFG                      0x0072
+#define CMD_802_11_PA_CFG                       0x0073
+#define CMD_802_11_FW_WAKE_METHOD               0x0074
+#define CMD_802_11_SUBSCRIBE_EVENT              0x0075
+#define CMD_802_11_RATE_ADAPT_RATESET           0x0076
+#define CMD_802_11_TX_RATE_QUERY                0x007f
+#define CMD_GET_TSF                             0x0080
+#define CMD_BT_ACCESS                           0x0087
+#define CMD_FWT_ACCESS                          0x0095
+#define CMD_802_11_MONITOR_MODE                 0x0098
+#define CMD_MESH_ACCESS                         0x009b
+#define CMD_MESH_CONFIG_OLD                     0x00a3
+#define CMD_MESH_CONFIG                         0x00ac
+#define CMD_SET_BOOT2_VER                       0x00a5
+#define CMD_FUNC_INIT                           0x00a9
+#define CMD_FUNC_SHUTDOWN                       0x00aa
+#define CMD_802_11_BEACON_CTRL                  0x00b0
+
+/* For the IEEE Power Save */
+#define PS_MODE_ACTION_ENTER_PS                 0x0030
+#define PS_MODE_ACTION_EXIT_PS                  0x0031
+#define PS_MODE_ACTION_SLEEP_CONFIRMED          0x0034
+
+#define CMD_ENABLE_RSN                          0x0001
+#define CMD_DISABLE_RSN                         0x0000
+
+#define CMD_ACT_GET                             0x0000
+#define CMD_ACT_SET                             0x0001
+
+/* Define action or option for CMD_802_11_SET_WEP */
+#define CMD_ACT_ADD                             0x0002
+#define CMD_ACT_REMOVE                          0x0004
+
+#define CMD_TYPE_WEP_40_BIT                     0x01
+#define CMD_TYPE_WEP_104_BIT                    0x02
+
+#define CMD_NUM_OF_WEP_KEYS                     4
+
+#define CMD_WEP_KEY_INDEX_MASK                  0x3fff
+
+/* Define action or option for CMD_802_11_SCAN */
+#define CMD_BSS_TYPE_BSS                        0x0001
+#define CMD_BSS_TYPE_IBSS                       0x0002
+#define CMD_BSS_TYPE_ANY                        0x0003
+
+/* Define action or option for CMD_802_11_SCAN */
+#define CMD_SCAN_TYPE_ACTIVE                    0x0000
+#define CMD_SCAN_TYPE_PASSIVE                   0x0001
+
+#define CMD_SCAN_RADIO_TYPE_BG                  0
+
+#define CMD_SCAN_PROBE_DELAY_TIME               0
+
+/* Define action or option for CMD_MAC_CONTROL */
+#define CMD_ACT_MAC_RX_ON                       0x0001
+#define CMD_ACT_MAC_TX_ON                       0x0002
+#define CMD_ACT_MAC_LOOPBACK_ON                 0x0004
+#define CMD_ACT_MAC_WEP_ENABLE                  0x0008
+#define CMD_ACT_MAC_INT_ENABLE                  0x0010
+#define CMD_ACT_MAC_MULTICAST_ENABLE            0x0020
+#define CMD_ACT_MAC_BROADCAST_ENABLE            0x0040
+#define CMD_ACT_MAC_PROMISCUOUS_ENABLE          0x0080
+#define CMD_ACT_MAC_ALL_MULTICAST_ENABLE        0x0100
+#define CMD_ACT_MAC_STRICT_PROTECTION_ENABLE    0x0400
+
+/* Event flags for CMD_802_11_SUBSCRIBE_EVENT */
+#define CMD_SUBSCRIBE_RSSI_LOW                  0x0001
+#define CMD_SUBSCRIBE_SNR_LOW                   0x0002
+#define CMD_SUBSCRIBE_FAILCOUNT                 0x0004
+#define CMD_SUBSCRIBE_BCNMISS                   0x0008
+#define CMD_SUBSCRIBE_RSSI_HIGH                 0x0010
+#define CMD_SUBSCRIBE_SNR_HIGH                  0x0020
+
+#define RADIO_PREAMBLE_LONG                     0x00
+#define RADIO_PREAMBLE_SHORT                    0x02
+#define RADIO_PREAMBLE_AUTO                     0x04
+
+/* Define action or option for CMD_802_11_RF_CHANNEL */
+#define CMD_OPT_802_11_RF_CHANNEL_GET           0x00
+#define CMD_OPT_802_11_RF_CHANNEL_SET           0x01
+
+/* Define action or option for CMD_802_11_DATA_RATE */
+#define CMD_ACT_SET_TX_AUTO                     0x0000
+#define CMD_ACT_SET_TX_FIX_RATE                 0x0001
+#define CMD_ACT_GET_TX_RATE                     0x0002
+
+/* Options for CMD_802_11_FW_WAKE_METHOD */
+#define CMD_WAKE_METHOD_UNCHANGED               0x0000
+#define CMD_WAKE_METHOD_COMMAND_INT             0x0001
+#define CMD_WAKE_METHOD_GPIO                    0x0002
+
+/* Object IDs for CMD_802_11_SNMP_MIB */
+#define SNMP_MIB_OID_BSS_TYPE                   0x0000
+#define SNMP_MIB_OID_OP_RATE_SET                0x0001
+#define SNMP_MIB_OID_BEACON_PERIOD              0x0002  /* Reserved on v9+ */
+#define SNMP_MIB_OID_DTIM_PERIOD                0x0003  /* Reserved on v9+ */
+#define SNMP_MIB_OID_ASSOC_TIMEOUT              0x0004  /* Reserved on v9+ */
+#define SNMP_MIB_OID_RTS_THRESHOLD              0x0005
+#define SNMP_MIB_OID_SHORT_RETRY_LIMIT          0x0006
+#define SNMP_MIB_OID_LONG_RETRY_LIMIT           0x0007
+#define SNMP_MIB_OID_FRAG_THRESHOLD             0x0008
+#define SNMP_MIB_OID_11D_ENABLE                 0x0009
+#define SNMP_MIB_OID_11H_ENABLE                 0x000A
+
+/* Define action or option for CMD_BT_ACCESS */
+enum cmd_bt_access_opts {
+       /* The bt commands start at 5 instead of 1 because the old dft commands
+        * are mapped to 1-4.  These old commands are no longer maintained and
+        * should not be called.
+        */
+       CMD_ACT_BT_ACCESS_ADD = 5,
+       CMD_ACT_BT_ACCESS_DEL,
+       CMD_ACT_BT_ACCESS_LIST,
+       CMD_ACT_BT_ACCESS_RESET,
+       CMD_ACT_BT_ACCESS_SET_INVERT,
+       CMD_ACT_BT_ACCESS_GET_INVERT
+};
+
+/* Define action or option for CMD_FWT_ACCESS */
+enum cmd_fwt_access_opts {
+       CMD_ACT_FWT_ACCESS_ADD = 1,
+       CMD_ACT_FWT_ACCESS_DEL,
+       CMD_ACT_FWT_ACCESS_LOOKUP,
+       CMD_ACT_FWT_ACCESS_LIST,
+       CMD_ACT_FWT_ACCESS_LIST_ROUTE,
+       CMD_ACT_FWT_ACCESS_LIST_NEIGHBOR,
+       CMD_ACT_FWT_ACCESS_RESET,
+       CMD_ACT_FWT_ACCESS_CLEANUP,
+       CMD_ACT_FWT_ACCESS_TIME,
+};
+
+/* Define action or option for CMD_802_11_HOST_SLEEP_CFG */
+enum cmd_wol_cfg_opts {
+       CMD_ACT_ACTION_NONE = 0,
+       CMD_ACT_SET_WOL_RULE,
+       CMD_ACT_GET_WOL_RULE,
+       CMD_ACT_RESET_WOL_RULE,
+};
+
+/* Define action or option for CMD_MESH_ACCESS */
+enum cmd_mesh_access_opts {
+       CMD_ACT_MESH_GET_TTL = 1,
+       CMD_ACT_MESH_SET_TTL,
+       CMD_ACT_MESH_GET_STATS,
+       CMD_ACT_MESH_GET_ANYCAST,
+       CMD_ACT_MESH_SET_ANYCAST,
+       CMD_ACT_MESH_SET_LINK_COSTS,
+       CMD_ACT_MESH_GET_LINK_COSTS,
+       CMD_ACT_MESH_SET_BCAST_RATE,
+       CMD_ACT_MESH_GET_BCAST_RATE,
+       CMD_ACT_MESH_SET_RREQ_DELAY,
+       CMD_ACT_MESH_GET_RREQ_DELAY,
+       CMD_ACT_MESH_SET_ROUTE_EXP,
+       CMD_ACT_MESH_GET_ROUTE_EXP,
+       CMD_ACT_MESH_SET_AUTOSTART_ENABLED,
+       CMD_ACT_MESH_GET_AUTOSTART_ENABLED,
+       CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT = 17,
+};
+
+/* Define actions and types for CMD_MESH_CONFIG */
+enum cmd_mesh_config_actions {
+       CMD_ACT_MESH_CONFIG_STOP = 0,
+       CMD_ACT_MESH_CONFIG_START,
+       CMD_ACT_MESH_CONFIG_SET,
+       CMD_ACT_MESH_CONFIG_GET,
+};
+
+enum cmd_mesh_config_types {
+       CMD_TYPE_MESH_SET_BOOTFLAG = 1,
+       CMD_TYPE_MESH_SET_BOOTTIME,
+       CMD_TYPE_MESH_SET_DEF_CHANNEL,
+       CMD_TYPE_MESH_SET_MESH_IE,
+       CMD_TYPE_MESH_GET_DEFAULTS,
+       CMD_TYPE_MESH_GET_MESH_IE, /* GET_DEFAULTS is superset of GET_MESHIE */
+};
+
+/* Card Event definition */
+#define MACREG_INT_CODE_TX_PPA_FREE            0
+#define MACREG_INT_CODE_TX_DMA_DONE            1
+#define MACREG_INT_CODE_LINK_LOST_W_SCAN       2
+#define MACREG_INT_CODE_LINK_LOST_NO_SCAN      3
+#define MACREG_INT_CODE_LINK_SENSED            4
+#define MACREG_INT_CODE_CMD_FINISHED           5
+#define MACREG_INT_CODE_MIB_CHANGED            6
+#define MACREG_INT_CODE_INIT_DONE              7
+#define MACREG_INT_CODE_DEAUTHENTICATED                8
+#define MACREG_INT_CODE_DISASSOCIATED          9
+#define MACREG_INT_CODE_PS_AWAKE               10
+#define MACREG_INT_CODE_PS_SLEEP               11
+#define MACREG_INT_CODE_MIC_ERR_MULTICAST      13
+#define MACREG_INT_CODE_MIC_ERR_UNICAST                14
+#define MACREG_INT_CODE_WM_AWAKE               15
+#define MACREG_INT_CODE_DEEP_SLEEP_AWAKE       16
+#define MACREG_INT_CODE_ADHOC_BCN_LOST         17
+#define MACREG_INT_CODE_HOST_AWAKE             18
+#define MACREG_INT_CODE_STOP_TX                        19
+#define MACREG_INT_CODE_START_TX               20
+#define MACREG_INT_CODE_CHANNEL_SWITCH         21
+#define MACREG_INT_CODE_MEASUREMENT_RDY                22
+#define MACREG_INT_CODE_WMM_CHANGE             23
+#define MACREG_INT_CODE_BG_SCAN_REPORT         24
+#define MACREG_INT_CODE_RSSI_LOW               25
+#define MACREG_INT_CODE_SNR_LOW                        26
+#define MACREG_INT_CODE_MAX_FAIL               27
+#define MACREG_INT_CODE_RSSI_HIGH              28
+#define MACREG_INT_CODE_SNR_HIGH               29
+#define MACREG_INT_CODE_MESH_AUTO_STARTED      35
+#define MACREG_INT_CODE_FIRMWARE_READY         48
+
+
+/* 802.11-related definitions */
+
+/* TxPD descriptor */
+struct txpd {
+       /* union to cope up with later FW revisions */
+       union {
+               /* Current Tx packet status */
+               __le32 tx_status;
+               struct {
+                       /* BSS type: client, AP, etc. */
+                       u8 bss_type;
+                       /* BSS number */
+                       u8 bss_num;
+                       /* Reserved */
+                       __le16 reserved;
+               } bss;
+       } u;
+       /* Tx control */
+       __le32 tx_control;
+       __le32 tx_packet_location;
+       /* Tx packet length */
+       __le16 tx_packet_length;
+       /* First 2 byte of destination MAC address */
+       u8 tx_dest_addr_high[2];
+       /* Last 4 byte of destination MAC address */
+       u8 tx_dest_addr_low[4];
+       /* Pkt Priority */
+       u8 priority;
+       /* Pkt Trasnit Power control */
+       u8 powermgmt;
+       /* Amount of time the packet has been queued (units = 2ms) */
+       u8 pktdelay_2ms;
+       /* reserved */
+       u8 reserved1;
+} __packed;
+
+/* RxPD Descriptor */
+struct rxpd {
+       /* union to cope up with later FW revisions */
+       union {
+               /* Current Rx packet status */
+               __le16 status;
+               struct {
+                       /* BSS type: client, AP, etc. */
+                       u8 bss_type;
+                       /* BSS number */
+                       u8 bss_num;
+               } __packed bss;
+       } __packed u;
+
+       /* SNR */
+       u8 snr;
+
+       /* Tx control */
+       u8 rx_control;
+
+       /* Pkt length */
+       __le16 pkt_len;
+
+       /* Noise Floor */
+       u8 nf;
+
+       /* Rx Packet Rate */
+       u8 rx_rate;
+
+       /* Pkt addr */
+       __le32 pkt_ptr;
+
+       /* Next Rx RxPD addr */
+       __le32 next_rxpd_ptr;
+
+       /* Pkt Priority */
+       u8 priority;
+       u8 reserved[3];
+} __packed;
+
+struct cmd_header {
+       __le16 command;
+       __le16 size;
+       __le16 seqnum;
+       __le16 result;
+} __packed;
+
+/* Generic structure to hold all key types. */
+struct enc_key {
+       u16 len;
+       u16 flags;  /* KEY_INFO_* from defs.h */
+       u16 type; /* KEY_TYPE_* from defs.h */
+       u8 key[32];
+};
+
+/* lbs_offset_value */
+struct lbs_offset_value {
+       u32 offset;
+       u32 value;
+} __packed;
+
+#define MAX_11D_TRIPLETS       83
+
+struct mrvl_ie_domain_param_set {
+       struct mrvl_ie_header header;
+
+       u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
+       struct ieee80211_country_ie_triplet triplet[MAX_11D_TRIPLETS];
+} __packed;
+
+struct cmd_ds_802_11d_domain_info {
+       struct cmd_header hdr;
+
+       __le16 action;
+       struct mrvl_ie_domain_param_set domain;
+} __packed;
+
+/*
+ * Define data structure for CMD_GET_HW_SPEC
+ * This structure defines the response for the GET_HW_SPEC command
+ */
+struct cmd_ds_get_hw_spec {
+       struct cmd_header hdr;
+
+       /* HW Interface version number */
+       __le16 hwifversion;
+       /* HW version number */
+       __le16 version;
+       /* Max number of TxPD FW can handle */
+       __le16 nr_txpd;
+       /* Max no of Multicast address */
+       __le16 nr_mcast_adr;
+       /* MAC address */
+       u8 permanentaddr[6];
+
+       /* region Code */
+       __le16 regioncode;
+
+       /* Number of antenna used */
+       __le16 nr_antenna;
+
+       /* FW release number, example 0x01030304 = 2.3.4p1 */
+       __le32 fwrelease;
+
+       /* Base Address of TxPD queue */
+       __le32 wcb_base;
+       /* Read Pointer of RxPd queue */
+       __le32 rxpd_rdptr;
+
+       /* Write Pointer of RxPd queue */
+       __le32 rxpd_wrptr;
+
+       /*FW/HW capability */
+       __le32 fwcapinfo;
+} __packed;
+
+struct cmd_ds_802_11_subscribe_event {
+       struct cmd_header hdr;
+
+       __le16 action;
+       __le16 events;
+
+       /* A TLV to the CMD_802_11_SUBSCRIBE_EVENT command can contain a
+        * number of TLVs. From the v5.1 manual, those TLVs would add up to
+        * 40 bytes. However, future firmware might add additional TLVs, so I
+        * bump this up a bit.
+        */
+       uint8_t tlv[128];
+} __packed;
+
+/*
+ * This scan handle Country Information IE(802.11d compliant)
+ * Define data structure for CMD_802_11_SCAN
+ */
+struct cmd_ds_802_11_scan {
+       struct cmd_header hdr;
+
+       uint8_t bsstype;
+       uint8_t bssid[ETH_ALEN];
+       uint8_t tlvbuffer[0];
+} __packed;
+
+struct cmd_ds_802_11_scan_rsp {
+       struct cmd_header hdr;
+
+       __le16 bssdescriptsize;
+       uint8_t nr_sets;
+       uint8_t bssdesc_and_tlvbuffer[0];
+} __packed;
+
+struct cmd_ds_802_11_get_log {
+       struct cmd_header hdr;
+
+       __le32 mcasttxframe;
+       __le32 failed;
+       __le32 retry;
+       __le32 multiretry;
+       __le32 framedup;
+       __le32 rtssuccess;
+       __le32 rtsfailure;
+       __le32 ackfailure;
+       __le32 rxfrag;
+       __le32 mcastrxframe;
+       __le32 fcserror;
+       __le32 txframe;
+       __le32 wepundecryptable;
+} __packed;
+
+struct cmd_ds_mac_control {
+       struct cmd_header hdr;
+       __le16 action;
+       u16 reserved;
+} __packed;
+
+struct cmd_ds_mac_multicast_adr {
+       struct cmd_header hdr;
+       __le16 action;
+       __le16 nr_of_adrs;
+       u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE];
+} __packed;
+
+struct cmd_ds_802_11_authenticate {
+       struct cmd_header hdr;
+
+       u8 bssid[ETH_ALEN];
+       u8 authtype;
+       u8 reserved[10];
+} __packed;
+
+struct cmd_ds_802_11_deauthenticate {
+       struct cmd_header hdr;
+
+       u8 macaddr[ETH_ALEN];
+       __le16 reasoncode;
+} __packed;
+
+struct cmd_ds_802_11_associate {
+       struct cmd_header hdr;
+
+       u8 bssid[6];
+       __le16 capability;
+       __le16 listeninterval;
+       __le16 bcnperiod;
+       u8 dtimperiod;
+       u8 iebuf[512];    /* Enough for required and most optional IEs */
+} __packed;
+
+struct cmd_ds_802_11_associate_response {
+       struct cmd_header hdr;
+
+       __le16 capability;
+       __le16 statuscode;
+       __le16 aid;
+       u8 iebuf[512];
+} __packed;
+
+struct cmd_ds_802_11_set_wep {
+       struct cmd_header hdr;
+
+       /* ACT_ADD, ACT_REMOVE or ACT_ENABLE */
+       __le16 action;
+
+       /* key Index selected for Tx */
+       __le16 keyindex;
+
+       /* 40, 128bit or TXWEP */
+       uint8_t keytype[4];
+       uint8_t keymaterial[4][16];
+} __packed;
+
+struct cmd_ds_802_11_snmp_mib {
+       struct cmd_header hdr;
+
+       __le16 action;
+       __le16 oid;
+       __le16 bufsize;
+       u8 value[128];
+} __packed;
+
+struct cmd_ds_reg_access {
+       struct cmd_header hdr;
+
+       __le16 action;
+       __le16 offset;
+       union {
+               u8 bbp_rf;  /* for BBP and RF registers */
+               __le32 mac; /* for MAC registers */
+       } value;
+} __packed;
+
+struct cmd_ds_802_11_radio_control {
+       struct cmd_header hdr;
+
+       __le16 action;
+       __le16 control;
+} __packed;
+
+struct cmd_ds_802_11_beacon_control {
+       struct cmd_header hdr;
+
+       __le16 action;
+       __le16 beacon_enable;
+       __le16 beacon_period;
+} __packed;
+
+struct cmd_ds_802_11_sleep_params {
+       struct cmd_header hdr;
+
+       /* ACT_GET/ACT_SET */
+       __le16 action;
+
+       /* Sleep clock error in ppm */
+       __le16 error;
+
+       /* Wakeup offset in usec */
+       __le16 offset;
+
+       /* Clock stabilization time in usec */
+       __le16 stabletime;
+
+       /* control periodic calibration */
+       uint8_t calcontrol;
+
+       /* control the use of external sleep clock */
+       uint8_t externalsleepclk;
+
+       /* reserved field, should be set to zero */
+       __le16 reserved;
+} __packed;
+
+struct cmd_ds_802_11_rf_channel {
+       struct cmd_header hdr;
+
+       __le16 action;
+       __le16 channel;
+       __le16 rftype;      /* unused */
+       __le16 reserved;    /* unused */
+       u8 channellist[32]; /* unused */
+} __packed;
+
+struct cmd_ds_802_11_rssi {
+       struct cmd_header hdr;
+
+       /*
+        * request:  number of beacons (N) to average the SNR and NF over
+        * response: SNR of most recent beacon
+        */
+       __le16 n_or_snr;
+
+       /*
+        * The following fields are only set in the response.
+        * In the request these are reserved and should be set to 0.
+        */
+       __le16 nf;       /* most recent beacon noise floor */
+       __le16 avg_snr;  /* average SNR weighted by N from request */
+       __le16 avg_nf;   /* average noise floor weighted by N from request */
+} __packed;
+
+struct cmd_ds_802_11_mac_address {
+       struct cmd_header hdr;
+
+       __le16 action;
+       u8 macadd[ETH_ALEN];
+} __packed;
+
+struct cmd_ds_802_11_rf_tx_power {
+       struct cmd_header hdr;
+
+       __le16 action;
+       __le16 curlevel;
+       s8 maxlevel;
+       s8 minlevel;
+} __packed;
+
+/* MONITOR_MODE only exists in OLPC v5 firmware */
+struct cmd_ds_802_11_monitor_mode {
+       struct cmd_header hdr;
+
+       __le16 action;
+       __le16 mode;
+} __packed;
+
+struct cmd_ds_set_boot2_ver {
+       struct cmd_header hdr;
+
+       __le16 action;
+       __le16 version;
+} __packed;
+
+struct cmd_ds_802_11_fw_wake_method {
+       struct cmd_header hdr;
+
+       __le16 action;
+       __le16 method;
+} __packed;
+
+struct cmd_ds_802_11_ps_mode {
+       struct cmd_header hdr;
+
+       __le16 action;
+
+       /*
+        * Interval for keepalive in PS mode:
+        * 0x0000 = don't change
+        * 0x001E = firmware default
+        * 0xFFFF = disable
+        */
+       __le16 nullpktinterval;
+
+       /*
+        * Number of DTIM intervals to wake up for:
+        * 0 = don't change
+        * 1 = firmware default
+        * 5 = max
+        */
+       __le16 multipledtim;
+
+       __le16 reserved;
+       __le16 locallisteninterval;
+
+       /*
+        * AdHoc awake period (FW v9+ only):
+        * 0 = don't change
+        * 1 = always awake (IEEE standard behavior)
+        * 2 - 31 = sleep for (n - 1) periods and awake for 1 period
+        * 32 - 254 = invalid
+        * 255 = sleep at each ATIM
+        */
+       __le16 adhoc_awake_period;
+} __packed;
+
+struct cmd_confirm_sleep {
+       struct cmd_header hdr;
+
+       __le16 action;
+       __le16 nullpktinterval;
+       __le16 multipledtim;
+       __le16 reserved;
+       __le16 locallisteninterval;
+} __packed;
+
+struct cmd_ds_802_11_data_rate {
+       struct cmd_header hdr;
+
+       __le16 action;
+       __le16 reserved;
+       u8 rates[MAX_RATES];
+} __packed;
+
+struct cmd_ds_802_11_rate_adapt_rateset {
+       struct cmd_header hdr;
+       __le16 action;
+       __le16 enablehwauto;
+       __le16 bitmap;
+} __packed;
+
+struct cmd_ds_802_11_ad_hoc_start {
+       struct cmd_header hdr;
+
+       u8 ssid[IEEE80211_MAX_SSID_LEN];
+       u8 bsstype;
+       __le16 beaconperiod;
+       u8 dtimperiod;   /* Reserved on v9 and later */
+       struct ieee_ie_ibss_param_set ibss;
+       u8 reserved1[4];
+       struct ieee_ie_ds_param_set ds;
+       u8 reserved2[4];
+       __le16 probedelay;  /* Reserved on v9 and later */
+       __le16 capability;
+       u8 rates[MAX_RATES];
+       u8 tlv_memory_size_pad[100];
+} __packed;
+
+struct cmd_ds_802_11_ad_hoc_result {
+       struct cmd_header hdr;
+
+       u8 pad[3];
+       u8 bssid[ETH_ALEN];
+} __packed;
+
+struct adhoc_bssdesc {
+       u8 bssid[ETH_ALEN];
+       u8 ssid[IEEE80211_MAX_SSID_LEN];
+       u8 type;
+       __le16 beaconperiod;
+       u8 dtimperiod;
+       __le64 timestamp;
+       __le64 localtime;
+       struct ieee_ie_ds_param_set ds;
+       u8 reserved1[4];
+       struct ieee_ie_ibss_param_set ibss;
+       u8 reserved2[4];
+       __le16 capability;
+       u8 rates[MAX_RATES];
+
+       /*
+        * DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the
+        * Adhoc join command and will cause a binary layout mismatch with
+        * the firmware
+        */
+} __packed;
+
+struct cmd_ds_802_11_ad_hoc_join {
+       struct cmd_header hdr;
+
+       struct adhoc_bssdesc bss;
+       __le16 failtimeout;   /* Reserved on v9 and later */
+       __le16 probedelay;    /* Reserved on v9 and later */
+} __packed;
+
+struct cmd_ds_802_11_ad_hoc_stop {
+       struct cmd_header hdr;
+} __packed;
+
+struct cmd_ds_802_11_enable_rsn {
+       struct cmd_header hdr;
+
+       __le16 action;
+       __le16 enable;
+} __packed;
+
+struct MrvlIEtype_keyParamSet {
+       /* type ID */
+       __le16 type;
+
+       /* length of Payload */
+       __le16 length;
+
+       /* type of key: WEP=0, TKIP=1, AES=2 */
+       __le16 keytypeid;
+
+       /* key control Info specific to a keytypeid */
+       __le16 keyinfo;
+
+       /* length of key */
+       __le16 keylen;
+
+       /* key material of size keylen */
+       u8 key[32];
+} __packed;
+
+#define MAX_WOL_RULES          16
+
+struct host_wol_rule {
+       uint8_t rule_no;
+       uint8_t rule_ops;
+       __le16 sig_offset;
+       __le16 sig_length;
+       __le16 reserve;
+       __be32 sig_mask;
+       __be32 signature;
+} __packed;
+
+struct wol_config {
+       uint8_t action;
+       uint8_t pattern;
+       uint8_t no_rules_in_cmd;
+       uint8_t result;
+       struct host_wol_rule rule[MAX_WOL_RULES];
+} __packed;
+
+struct cmd_ds_host_sleep {
+       struct cmd_header hdr;
+       __le32 criteria;
+       uint8_t gpio;
+       uint16_t gap;
+       struct wol_config wol_conf;
+} __packed;
+
+
+
+struct cmd_ds_802_11_key_material {
+       struct cmd_header hdr;
+
+       __le16 action;
+       struct MrvlIEtype_keyParamSet keyParamSet[2];
+} __packed;
+
+struct cmd_ds_802_11_eeprom_access {
+       struct cmd_header hdr;
+       __le16 action;
+       __le16 offset;
+       __le16 len;
+       /* firmware says it returns a maximum of 20 bytes */
+#define LBS_EEPROM_READ_LEN 20
+       u8 value[LBS_EEPROM_READ_LEN];
+} __packed;
+
+struct cmd_ds_802_11_tpc_cfg {
+       struct cmd_header hdr;
+
+       __le16 action;
+       uint8_t enable;
+       int8_t P0;
+       int8_t P1;
+       int8_t P2;
+       uint8_t usesnr;
+} __packed;
+
+
+struct cmd_ds_802_11_pa_cfg {
+       struct cmd_header hdr;
+
+       __le16 action;
+       uint8_t enable;
+       int8_t P0;
+       int8_t P1;
+       int8_t P2;
+} __packed;
+
+
+struct cmd_ds_802_11_led_ctrl {
+       struct cmd_header hdr;
+
+       __le16 action;
+       __le16 numled;
+       u8 data[256];
+} __packed;
+
+/* Automatic Frequency Control */
+struct cmd_ds_802_11_afc {
+       struct cmd_header hdr;
+
+       __le16 afc_auto;
+       union {
+               struct {
+                       __le16 threshold;
+                       __le16 period;
+               };
+               struct {
+                       __le16 timing_offset; /* signed */
+                       __le16 carrier_offset; /* signed */
+               };
+       };
+} __packed;
+
+struct cmd_tx_rate_query {
+       __le16 txrate;
+} __packed;
+
+struct cmd_ds_get_tsf {
+       __le64 tsfvalue;
+} __packed;
+
+struct cmd_ds_bt_access {
+       struct cmd_header hdr;
+
+       __le16 action;
+       __le32 id;
+       u8 addr1[ETH_ALEN];
+       u8 addr2[ETH_ALEN];
+} __packed;
+
+struct cmd_ds_fwt_access {
+       struct cmd_header hdr;
+
+       __le16 action;
+       __le32 id;
+       u8 valid;
+       u8 da[ETH_ALEN];
+       u8 dir;
+       u8 ra[ETH_ALEN];
+       __le32 ssn;
+       __le32 dsn;
+       __le32 metric;
+       u8 rate;
+       u8 hopcount;
+       u8 ttl;
+       __le32 expiration;
+       u8 sleepmode;
+       __le32 snr;
+       __le32 references;
+       u8 prec[ETH_ALEN];
+} __packed;
+
+struct cmd_ds_mesh_config {
+       struct cmd_header hdr;
+
+       __le16 action;
+       __le16 channel;
+       __le16 type;
+       __le16 length;
+       u8 data[128];   /* last position reserved */
+} __packed;
+
+struct cmd_ds_mesh_access {
+       struct cmd_header hdr;
+
+       __le16 action;
+       __le32 data[32];        /* last position reserved */
+} __packed;
+
+/* Number of stats counters returned by the firmware */
+#define MESH_STATS_NUM 8
+#endif
diff --git a/drivers/net/wireless/marvell/libertas/if_cs.c b/drivers/net/wireless/marvell/libertas/if_cs.c
new file mode 100644 (file)
index 0000000..f499efc
--- /dev/null
@@ -0,0 +1,1006 @@
+/*
+
+  Driver for the Marvell 8385 based compact flash WLAN cards.
+
+  (C) 2007 by Holger Schurig <hs4233@mail.mn-solutions.de>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#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)
+{
+       lbs_deb_enter(LBS_DEB_CS);
+       if_cs_write16(card, IF_CS_HOST_INT_MASK, 0);
+}
+
+static inline void if_cs_disable_ints(struct if_cs_card *card)
+{
+       lbs_deb_enter(LBS_DEB_CS);
+       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;
+
+       lbs_deb_enter(LBS_DEB_CS);
+       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);
+       lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
+       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;
+
+       lbs_deb_enter(LBS_DEB_CS);
+       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);
+
+       lbs_deb_leave(LBS_DEB_CS);
+}
+
+/*
+ * 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;
+
+       lbs_deb_enter(LBS_DEB_CS);
+
+       /* 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:
+       lbs_deb_leave_args(LBS_DEB_CS, "ret %d, len %d", ret, *len);
+       return ret;
+}
+
+static struct sk_buff *if_cs_receive_data(struct lbs_private *priv)
+{
+       struct sk_buff *skb = NULL;
+       u16 len;
+       u8 *data;
+
+       lbs_deb_enter(LBS_DEB_CS);
+
+       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:
+       lbs_deb_leave_args(LBS_DEB_CS, "ret %p", skb);
+       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;
+
+       lbs_deb_enter(LBS_DEB_CS);
+
+       /* 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);
+
+       lbs_deb_leave(LBS_DEB_CS);
+       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;
+
+       lbs_deb_enter(LBS_DEB_CS);
+
+       /*
+        * 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:
+       lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
+       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_enter(LBS_DEB_CS);
+
+       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:
+       lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
+       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;
+
+       lbs_deb_enter_args(LBS_DEB_CS, "type %d, bytes %d", type, nb);
+
+       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);
+       }
+
+       lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
+       return ret;
+}
+
+
+static void if_cs_release(struct pcmcia_device *p_dev)
+{
+       struct if_cs_card *card = p_dev->priv;
+
+       lbs_deb_enter(LBS_DEB_CS);
+
+       free_irq(p_dev->irq, card);
+       pcmcia_disable_device(p_dev);
+       if (card->iobase)
+               ioport_unmap(card->iobase);
+
+       lbs_deb_leave(LBS_DEB_CS);
+}
+
+
+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;
+
+       lbs_deb_enter(LBS_DEB_CS);
+
+       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 (!priv) {
+               ret = -ENOMEM;
+               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:
+       lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
+       return ret;
+}
+
+
+static void if_cs_detach(struct pcmcia_device *p_dev)
+{
+       struct if_cs_card *card = p_dev->priv;
+
+       lbs_deb_enter(LBS_DEB_CS);
+
+       lbs_stop_card(card->priv);
+       lbs_remove_card(card->priv);
+       if_cs_disable_ints(card);
+       if_cs_release(p_dev);
+       kfree(card);
+
+       lbs_deb_leave(LBS_DEB_CS);
+}
+
+
+
+/********************************************************************/
+/* Module initialization                                            */
+/********************************************************************/
+
+static const struct pcmcia_device_id if_cs_ids[] = {
+       PCMCIA_DEVICE_MANF_CARD(CF8305_MANFID, CF8305_CARDID),
+       PCMCIA_DEVICE_MANF_CARD(CF8381_MANFID, CF8381_CARDID),
+       PCMCIA_DEVICE_MANF_CARD(CF8385_MANFID, CF8385_CARDID),
+       /* NOTE: keep in sync with get_model() */
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, if_cs_ids);
+
+static struct pcmcia_driver lbs_driver = {
+       .owner          = THIS_MODULE,
+       .name           = DRV_NAME,
+       .probe          = if_cs_probe,
+       .remove         = if_cs_detach,
+       .id_table       = if_cs_ids,
+};
+module_pcmcia_driver(lbs_driver);
diff --git a/drivers/net/wireless/marvell/libertas/if_sdio.c b/drivers/net/wireless/marvell/libertas/if_sdio.c
new file mode 100644 (file)
index 0000000..33ceda2
--- /dev/null
@@ -0,0 +1,1453 @@
+/*
+ *  linux/drivers/net/wireless/libertas/if_sdio.c
+ *
+ *  Copyright 2007-2008 Pierre Ossman
+ *
+ * Inspired by if_cs.c, Copyright 2007 Holger Schurig
+ *
+ * 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 hardware has more or less no CMD53 support, so all registers
+ * must be accessed using sdio_readb()/sdio_writeb().
+ *
+ * Transfers must be in one transaction or the firmware goes bonkers.
+ * This means that the transfer must either be small enough to do a
+ * byte based transfer or it must be padded to a multiple of the
+ * current block size.
+ *
+ * As SDIO is still new to the kernel, it is unfortunately common with
+ * bugs in the host controllers related to that. One such bug is that
+ * controllers cannot do transfers that aren't a multiple of 4 bytes.
+ * If you don't have time to fix the host controller driver, you can
+ * work around the problem by modifying if_sdio_host_to_card() and
+ * if_sdio_card_to_host() to pad the data.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/firmware.h>
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/host.h>
+#include <linux/pm_runtime.h>
+
+#include "host.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "cmd.h"
+#include "if_sdio.h"
+
+static void if_sdio_interrupt(struct sdio_func *func);
+
+/* The if_sdio_remove() callback function is called when
+ * user removes this module from kernel space or ejects
+ * the card from the slot. The driver handles these 2 cases
+ * differently for SD8688 combo chip.
+ * If the user is removing the module, the FUNC_SHUTDOWN
+ * command for SD8688 is sent to the firmware.
+ * If the card is removed, there is no need to send this command.
+ *
+ * The variable 'user_rmmod' is used to distinguish these two
+ * scenarios. This flag is initialized as FALSE in case the card
+ * is removed, and will be set to TRUE for module removal when
+ * module_exit function is called.
+ */
+static u8 user_rmmod;
+
+static const struct sdio_device_id if_sdio_ids[] = {
+       { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL,
+                       SDIO_DEVICE_ID_MARVELL_LIBERTAS) },
+       { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL,
+                       SDIO_DEVICE_ID_MARVELL_8688WLAN) },
+       { /* end: all zeroes */                         },
+};
+
+MODULE_DEVICE_TABLE(sdio, if_sdio_ids);
+
+#define MODEL_8385     0x04
+#define MODEL_8686     0x0b
+#define MODEL_8688     0x10
+
+static const struct lbs_fw_table fw_table[] = {
+       { MODEL_8385, "libertas/sd8385_helper.bin", "libertas/sd8385.bin" },
+       { MODEL_8385, "sd8385_helper.bin", "sd8385.bin" },
+       { MODEL_8686, "libertas/sd8686_v9_helper.bin", "libertas/sd8686_v9.bin" },
+       { MODEL_8686, "libertas/sd8686_v8_helper.bin", "libertas/sd8686_v8.bin" },
+       { MODEL_8686, "sd8686_helper.bin", "sd8686.bin" },
+       { MODEL_8688, "libertas/sd8688_helper.bin", "libertas/sd8688.bin" },
+       { MODEL_8688, "sd8688_helper.bin", "sd8688.bin" },
+       { 0, NULL, NULL }
+};
+MODULE_FIRMWARE("libertas/sd8385_helper.bin");
+MODULE_FIRMWARE("libertas/sd8385.bin");
+MODULE_FIRMWARE("sd8385_helper.bin");
+MODULE_FIRMWARE("sd8385.bin");
+MODULE_FIRMWARE("libertas/sd8686_v9_helper.bin");
+MODULE_FIRMWARE("libertas/sd8686_v9.bin");
+MODULE_FIRMWARE("libertas/sd8686_v8_helper.bin");
+MODULE_FIRMWARE("libertas/sd8686_v8.bin");
+MODULE_FIRMWARE("sd8686_helper.bin");
+MODULE_FIRMWARE("sd8686.bin");
+MODULE_FIRMWARE("libertas/sd8688_helper.bin");
+MODULE_FIRMWARE("libertas/sd8688.bin");
+MODULE_FIRMWARE("sd8688_helper.bin");
+MODULE_FIRMWARE("sd8688.bin");
+
+struct if_sdio_packet {
+       struct if_sdio_packet   *next;
+       u16                     nb;
+       u8                      buffer[0] __attribute__((aligned(4)));
+};
+
+struct if_sdio_card {
+       struct sdio_func        *func;
+       struct lbs_private      *priv;
+
+       int                     model;
+       unsigned long           ioport;
+       unsigned int            scratch_reg;
+       bool                    started;
+       wait_queue_head_t       pwron_waitq;
+
+       u8                      buffer[65536] __attribute__((aligned(4)));
+
+       spinlock_t              lock;
+       struct if_sdio_packet   *packets;
+
+       struct workqueue_struct *workqueue;
+       struct work_struct      packet_worker;
+
+       u8                      rx_unit;
+};
+
+static void if_sdio_finish_power_on(struct if_sdio_card *card);
+static int if_sdio_power_off(struct if_sdio_card *card);
+
+/********************************************************************/
+/* I/O                                                              */
+/********************************************************************/
+
+/*
+ *  For SD8385/SD8686, this function reads firmware status after
+ *  the image is downloaded, or reads RX packet length when
+ *  interrupt (with IF_SDIO_H_INT_UPLD bit set) is received.
+ *  For SD8688, this function reads firmware status only.
+ */
+static u16 if_sdio_read_scratch(struct if_sdio_card *card, int *err)
+{
+       int ret;
+       u16 scratch;
+
+       scratch = sdio_readb(card->func, card->scratch_reg, &ret);
+       if (!ret)
+               scratch |= sdio_readb(card->func, card->scratch_reg + 1,
+                                       &ret) << 8;
+
+       if (err)
+               *err = ret;
+
+       if (ret)
+               return 0xffff;
+
+       return scratch;
+}
+
+static u8 if_sdio_read_rx_unit(struct if_sdio_card *card)
+{
+       int ret;
+       u8 rx_unit;
+
+       rx_unit = sdio_readb(card->func, IF_SDIO_RX_UNIT, &ret);
+
+       if (ret)
+               rx_unit = 0;
+
+       return rx_unit;
+}
+
+static u16 if_sdio_read_rx_len(struct if_sdio_card *card, int *err)
+{
+       int ret;
+       u16 rx_len;
+
+       switch (card->model) {
+       case MODEL_8385:
+       case MODEL_8686:
+               rx_len = if_sdio_read_scratch(card, &ret);
+               break;
+       case MODEL_8688:
+       default: /* for newer chipsets */
+               rx_len = sdio_readb(card->func, IF_SDIO_RX_LEN, &ret);
+               if (!ret)
+                       rx_len <<= card->rx_unit;
+               else
+                       rx_len = 0xffff;        /* invalid length */
+
+               break;
+       }
+
+       if (err)
+               *err = ret;
+
+       return rx_len;
+}
+
+static int if_sdio_handle_cmd(struct if_sdio_card *card,
+               u8 *buffer, unsigned size)
+{
+       struct lbs_private *priv = card->priv;
+       int ret;
+       unsigned long flags;
+       u8 i;
+
+       lbs_deb_enter(LBS_DEB_SDIO);
+
+       if (size > LBS_CMD_BUFFER_SIZE) {
+               lbs_deb_sdio("response packet too large (%d bytes)\n",
+                       (int)size);
+               ret = -E2BIG;
+               goto out;
+       }
+
+       spin_lock_irqsave(&priv->driver_lock, flags);
+
+       i = (priv->resp_idx == 0) ? 1 : 0;
+       BUG_ON(priv->resp_len[i]);
+       priv->resp_len[i] = size;
+       memcpy(priv->resp_buf[i], buffer, size);
+       lbs_notify_command_response(priv, i);
+
+       spin_unlock_irqrestore(&card->priv->driver_lock, flags);
+
+       ret = 0;
+
+out:
+       lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+       return ret;
+}
+
+static int if_sdio_handle_data(struct if_sdio_card *card,
+               u8 *buffer, unsigned size)
+{
+       int ret;
+       struct sk_buff *skb;
+       char *data;
+
+       lbs_deb_enter(LBS_DEB_SDIO);
+
+       if (size > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
+               lbs_deb_sdio("response packet too large (%d bytes)\n",
+                       (int)size);
+               ret = -E2BIG;
+               goto out;
+       }
+
+       skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + NET_IP_ALIGN);
+       if (!skb) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       skb_reserve(skb, NET_IP_ALIGN);
+
+       data = skb_put(skb, size);
+
+       memcpy(data, buffer, size);
+
+       lbs_process_rxed_packet(card->priv, skb);
+
+       ret = 0;
+
+out:
+       lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+
+       return ret;
+}
+
+static int if_sdio_handle_event(struct if_sdio_card *card,
+               u8 *buffer, unsigned size)
+{
+       int ret;
+       u32 event;
+
+       lbs_deb_enter(LBS_DEB_SDIO);
+
+       if (card->model == MODEL_8385) {
+               event = sdio_readb(card->func, IF_SDIO_EVENT, &ret);
+               if (ret)
+                       goto out;
+
+               /* right shift 3 bits to get the event id */
+               event >>= 3;
+       } else {
+               if (size < 4) {
+                       lbs_deb_sdio("event packet too small (%d bytes)\n",
+                               (int)size);
+                       ret = -EINVAL;
+                       goto out;
+               }
+               event = buffer[3] << 24;
+               event |= buffer[2] << 16;
+               event |= buffer[1] << 8;
+               event |= buffer[0] << 0;
+       }
+
+       lbs_queue_event(card->priv, event & 0xFF);
+       ret = 0;
+
+out:
+       lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+
+       return ret;
+}
+
+static int if_sdio_wait_status(struct if_sdio_card *card, const u8 condition)
+{
+       u8 status;
+       unsigned long timeout;
+       int ret = 0;
+
+       timeout = jiffies + HZ;
+       while (1) {
+               status = sdio_readb(card->func, IF_SDIO_STATUS, &ret);
+               if (ret)
+                       return ret;
+               if ((status & condition) == condition)
+                       break;
+               if (time_after(jiffies, timeout))
+                       return -ETIMEDOUT;
+               mdelay(1);
+       }
+       return ret;
+}
+
+static int if_sdio_card_to_host(struct if_sdio_card *card)
+{
+       int ret;
+       u16 size, type, chunk;
+
+       lbs_deb_enter(LBS_DEB_SDIO);
+
+       size = if_sdio_read_rx_len(card, &ret);
+       if (ret)
+               goto out;
+
+       if (size < 4) {
+               lbs_deb_sdio("invalid packet size (%d bytes) from firmware\n",
+                       (int)size);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ret = if_sdio_wait_status(card, IF_SDIO_IO_RDY);
+       if (ret)
+               goto out;
+
+       /*
+        * The transfer must be in one transaction or the firmware
+        * goes suicidal. There's no way to guarantee that for all
+        * controllers, but we can at least try.
+        */
+       chunk = sdio_align_size(card->func, size);
+
+       ret = sdio_readsb(card->func, card->buffer, card->ioport, chunk);
+       if (ret)
+               goto out;
+
+       chunk = card->buffer[0] | (card->buffer[1] << 8);
+       type = card->buffer[2] | (card->buffer[3] << 8);
+
+       lbs_deb_sdio("packet of type %d and size %d bytes\n",
+               (int)type, (int)chunk);
+
+       if (chunk > size) {
+               lbs_deb_sdio("packet fragment (%d > %d)\n",
+                       (int)chunk, (int)size);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (chunk < size) {
+               lbs_deb_sdio("packet fragment (%d < %d)\n",
+                       (int)chunk, (int)size);
+       }
+
+       switch (type) {
+       case MVMS_CMD:
+               ret = if_sdio_handle_cmd(card, card->buffer + 4, chunk - 4);
+               if (ret)
+                       goto out;
+               break;
+       case MVMS_DAT:
+               ret = if_sdio_handle_data(card, card->buffer + 4, chunk - 4);
+               if (ret)
+                       goto out;
+               break;
+       case MVMS_EVENT:
+               ret = if_sdio_handle_event(card, card->buffer + 4, chunk - 4);
+               if (ret)
+                       goto out;
+               break;
+       default:
+               lbs_deb_sdio("invalid type (%d) from firmware\n",
+                               (int)type);
+               ret = -EINVAL;
+               goto out;
+       }
+
+out:
+       if (ret)
+               pr_err("problem fetching packet from firmware\n");
+
+       lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+
+       return ret;
+}
+
+static void if_sdio_host_to_card_worker(struct work_struct *work)
+{
+       struct if_sdio_card *card;
+       struct if_sdio_packet *packet;
+       int ret;
+       unsigned long flags;
+
+       lbs_deb_enter(LBS_DEB_SDIO);
+
+       card = container_of(work, struct if_sdio_card, packet_worker);
+
+       while (1) {
+               spin_lock_irqsave(&card->lock, flags);
+               packet = card->packets;
+               if (packet)
+                       card->packets = packet->next;
+               spin_unlock_irqrestore(&card->lock, flags);
+
+               if (!packet)
+                       break;
+
+               sdio_claim_host(card->func);
+
+               ret = if_sdio_wait_status(card, IF_SDIO_IO_RDY);
+               if (ret == 0) {
+                       ret = sdio_writesb(card->func, card->ioport,
+                                          packet->buffer, packet->nb);
+               }
+
+               if (ret)
+                       pr_err("error %d sending packet to firmware\n", ret);
+
+               sdio_release_host(card->func);
+
+               kfree(packet);
+       }
+
+       lbs_deb_leave(LBS_DEB_SDIO);
+}
+
+/********************************************************************/
+/* Firmware                                                         */
+/********************************************************************/
+
+#define FW_DL_READY_STATUS (IF_SDIO_IO_RDY | IF_SDIO_DL_RDY)
+
+static int if_sdio_prog_helper(struct if_sdio_card *card,
+                               const struct firmware *fw)
+{
+       int ret;
+       unsigned long timeout;
+       u8 *chunk_buffer;
+       u32 chunk_size;
+       const u8 *firmware;
+       size_t size;
+
+       lbs_deb_enter(LBS_DEB_SDIO);
+
+       chunk_buffer = kzalloc(64, GFP_KERNEL);
+       if (!chunk_buffer) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       sdio_claim_host(card->func);
+
+       ret = sdio_set_block_size(card->func, 32);
+       if (ret)
+               goto release;
+
+       firmware = fw->data;
+       size = fw->size;
+
+       while (size) {
+               ret = if_sdio_wait_status(card, FW_DL_READY_STATUS);
+               if (ret)
+                       goto release;
+
+               /* On some platforms (like Davinci) the chip needs more time
+                * between helper blocks.
+                */
+               mdelay(2);
+
+               chunk_size = min_t(size_t, size, 60);
+
+               *((__le32*)chunk_buffer) = cpu_to_le32(chunk_size);
+               memcpy(chunk_buffer + 4, firmware, chunk_size);
+/*
+               lbs_deb_sdio("sending %d bytes chunk\n", chunk_size);
+*/
+               ret = sdio_writesb(card->func, card->ioport,
+                               chunk_buffer, 64);
+               if (ret)
+                       goto release;
+
+               firmware += chunk_size;
+               size -= chunk_size;
+       }
+
+       /* an empty block marks the end of the transfer */
+       memset(chunk_buffer, 0, 4);
+       ret = sdio_writesb(card->func, card->ioport, chunk_buffer, 64);
+       if (ret)
+               goto release;
+
+       lbs_deb_sdio("waiting for helper to boot...\n");
+
+       /* wait for the helper to boot by looking at the size register */
+       timeout = jiffies + HZ;
+       while (1) {
+               u16 req_size;
+
+               req_size = sdio_readb(card->func, IF_SDIO_RD_BASE, &ret);
+               if (ret)
+                       goto release;
+
+               req_size |= sdio_readb(card->func, IF_SDIO_RD_BASE + 1, &ret) << 8;
+               if (ret)
+                       goto release;
+
+               if (req_size != 0)
+                       break;
+
+               if (time_after(jiffies, timeout)) {
+                       ret = -ETIMEDOUT;
+                       goto release;
+               }
+
+               msleep(10);
+       }
+
+       ret = 0;
+
+release:
+       sdio_release_host(card->func);
+       kfree(chunk_buffer);
+
+out:
+       if (ret)
+               pr_err("failed to load helper firmware\n");
+
+       lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+       return ret;
+}
+
+static int if_sdio_prog_real(struct if_sdio_card *card,
+                               const struct firmware *fw)
+{
+       int ret;
+       unsigned long timeout;
+       u8 *chunk_buffer;
+       u32 chunk_size;
+       const u8 *firmware;
+       size_t size, req_size;
+
+       lbs_deb_enter(LBS_DEB_SDIO);
+
+       chunk_buffer = kzalloc(512, GFP_KERNEL);
+       if (!chunk_buffer) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       sdio_claim_host(card->func);
+
+       ret = sdio_set_block_size(card->func, 32);
+       if (ret)
+               goto release;
+
+       firmware = fw->data;
+       size = fw->size;
+
+       while (size) {
+               timeout = jiffies + HZ;
+               while (1) {
+                       ret = if_sdio_wait_status(card, FW_DL_READY_STATUS);
+                       if (ret)
+                               goto release;
+
+                       req_size = sdio_readb(card->func, IF_SDIO_RD_BASE,
+                                       &ret);
+                       if (ret)
+                               goto release;
+
+                       req_size |= sdio_readb(card->func, IF_SDIO_RD_BASE + 1,
+                                       &ret) << 8;
+                       if (ret)
+                               goto release;
+
+                       /*
+                        * For SD8688 wait until the length is not 0, 1 or 2
+                        * before downloading the first FW block,
+                        * since BOOT code writes the register to indicate the
+                        * helper/FW download winner,
+                        * the value could be 1 or 2 (Func1 or Func2).
+                        */
+                       if ((size != fw->size) || (req_size > 2))
+                               break;
+                       if (time_after(jiffies, timeout)) {
+                               ret = -ETIMEDOUT;
+                               goto release;
+                       }
+                       mdelay(1);
+               }
+
+/*
+               lbs_deb_sdio("firmware wants %d bytes\n", (int)req_size);
+*/
+               if (req_size == 0) {
+                       lbs_deb_sdio("firmware helper gave up early\n");
+                       ret = -EIO;
+                       goto release;
+               }
+
+               if (req_size & 0x01) {
+                       lbs_deb_sdio("firmware helper signalled error\n");
+                       ret = -EIO;
+                       goto release;
+               }
+
+               if (req_size > size)
+                       req_size = size;
+
+               while (req_size) {
+                       chunk_size = min_t(size_t, req_size, 512);
+
+                       memcpy(chunk_buffer, firmware, chunk_size);
+/*
+                       lbs_deb_sdio("sending %d bytes (%d bytes) chunk\n",
+                               chunk_size, (chunk_size + 31) / 32 * 32);
+*/
+                       ret = sdio_writesb(card->func, card->ioport,
+                               chunk_buffer, roundup(chunk_size, 32));
+                       if (ret)
+                               goto release;
+
+                       firmware += chunk_size;
+                       size -= chunk_size;
+                       req_size -= chunk_size;
+               }
+       }
+
+       ret = 0;
+
+       lbs_deb_sdio("waiting for firmware to boot...\n");
+
+       /* wait for the firmware to boot */
+       timeout = jiffies + HZ;
+       while (1) {
+               u16 scratch;
+
+               scratch = if_sdio_read_scratch(card, &ret);
+               if (ret)
+                       goto release;
+
+               if (scratch == IF_SDIO_FIRMWARE_OK)
+                       break;
+
+               if (time_after(jiffies, timeout)) {
+                       ret = -ETIMEDOUT;
+                       goto release;
+               }
+
+               msleep(10);
+       }
+
+       ret = 0;
+
+release:
+       sdio_release_host(card->func);
+       kfree(chunk_buffer);
+
+out:
+       if (ret)
+               pr_err("failed to load firmware\n");
+
+       lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+       return ret;
+}
+
+static void if_sdio_do_prog_firmware(struct lbs_private *priv, int ret,
+                                    const struct firmware *helper,
+                                    const struct firmware *mainfw)
+{
+       struct if_sdio_card *card = priv->card;
+
+       if (ret) {
+               pr_err("failed to find firmware (%d)\n", ret);
+               return;
+       }
+
+       ret = if_sdio_prog_helper(card, helper);
+       if (ret)
+               return;
+
+       lbs_deb_sdio("Helper firmware loaded\n");
+
+       ret = if_sdio_prog_real(card, mainfw);
+       if (ret)
+               return;
+
+       lbs_deb_sdio("Firmware loaded\n");
+       if_sdio_finish_power_on(card);
+}
+
+static int if_sdio_prog_firmware(struct if_sdio_card *card)
+{
+       int ret;
+       u16 scratch;
+
+       lbs_deb_enter(LBS_DEB_SDIO);
+
+       /*
+        * Disable interrupts
+        */
+       sdio_claim_host(card->func);
+       sdio_writeb(card->func, 0x00, IF_SDIO_H_INT_MASK, &ret);
+       sdio_release_host(card->func);
+
+       sdio_claim_host(card->func);
+       scratch = if_sdio_read_scratch(card, &ret);
+       sdio_release_host(card->func);
+
+       lbs_deb_sdio("firmware status = %#x\n", scratch);
+       lbs_deb_sdio("scratch ret = %d\n", ret);
+
+       if (ret)
+               goto out;
+
+
+       /*
+        * The manual clearly describes that FEDC is the right code to use
+        * to detect firmware presence, but for SD8686 it is not that simple.
+        * Scratch is also used to store the RX packet length, so we lose
+        * the FEDC value early on. So we use a non-zero check in order
+        * to validate firmware presence.
+        * Additionally, the SD8686 in the Gumstix always has the high scratch
+        * bit set, even when the firmware is not loaded. So we have to
+        * exclude that from the test.
+        */
+       if (scratch == IF_SDIO_FIRMWARE_OK) {
+               lbs_deb_sdio("firmware already loaded\n");
+               if_sdio_finish_power_on(card);
+               return 0;
+       } else if ((card->model == MODEL_8686) && (scratch & 0x7fff)) {
+               lbs_deb_sdio("firmware may be running\n");
+               if_sdio_finish_power_on(card);
+               return 0;
+       }
+
+       ret = lbs_get_firmware_async(card->priv, &card->func->dev, card->model,
+                                    fw_table, if_sdio_do_prog_firmware);
+
+out:
+       lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+       return ret;
+}
+
+/********************************************************************/
+/* Power management                                                 */
+/********************************************************************/
+
+/* Finish power on sequence (after firmware is loaded) */
+static void if_sdio_finish_power_on(struct if_sdio_card *card)
+{
+       struct sdio_func *func = card->func;
+       struct lbs_private *priv = card->priv;
+       int ret;
+
+       sdio_claim_host(func);
+       sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE);
+
+       /*
+        * Get rx_unit if the chip is SD8688 or newer.
+        * SD8385 & SD8686 do not have rx_unit.
+        */
+       if ((card->model != MODEL_8385)
+                       && (card->model != MODEL_8686))
+               card->rx_unit = if_sdio_read_rx_unit(card);
+       else
+               card->rx_unit = 0;
+
+       /*
+        * Set up the interrupt handler late.
+        *
+        * If we set it up earlier, the (buggy) hardware generates a spurious
+        * interrupt, even before the interrupt has been enabled, with
+        * CCCR_INTx = 0.
+        *
+        * We register the interrupt handler late so that we can handle any
+        * spurious interrupts, and also to avoid generation of that known
+        * spurious interrupt in the first place.
+        */
+       ret = sdio_claim_irq(func, if_sdio_interrupt);
+       if (ret)
+               goto release;
+
+       /*
+        * Enable interrupts now that everything is set up
+        */
+       sdio_writeb(func, 0x0f, IF_SDIO_H_INT_MASK, &ret);
+       if (ret)
+               goto release_irq;
+
+       sdio_release_host(func);
+
+       /* Set fw_ready before queuing any commands so that
+        * lbs_thread won't block from sending them to firmware.
+        */
+       priv->fw_ready = 1;
+
+       /*
+        * FUNC_INIT is required for SD8688 WLAN/BT multiple functions
+        */
+       if (card->model == MODEL_8688) {
+               struct cmd_header cmd;
+
+               memset(&cmd, 0, sizeof(cmd));
+
+               lbs_deb_sdio("send function INIT command\n");
+               if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd),
+                               lbs_cmd_copyback, (unsigned long) &cmd))
+                       netdev_alert(priv->dev, "CMD_FUNC_INIT cmd failed\n");
+       }
+
+       wake_up(&card->pwron_waitq);
+
+       if (!card->started) {
+               ret = lbs_start_card(priv);
+               if_sdio_power_off(card);
+               if (ret == 0) {
+                       card->started = true;
+                       /* Tell PM core that we don't need the card to be
+                        * powered now */
+                       pm_runtime_put(&func->dev);
+               }
+       }
+
+       return;
+
+release_irq:
+       sdio_release_irq(func);
+release:
+       sdio_release_host(func);
+}
+
+static int if_sdio_power_on(struct if_sdio_card *card)
+{
+       struct sdio_func *func = card->func;
+       struct mmc_host *host = func->card->host;
+       int ret;
+
+       sdio_claim_host(func);
+
+       ret = sdio_enable_func(func);
+       if (ret)
+               goto release;
+
+       /* For 1-bit transfers to the 8686 model, we need to enable the
+        * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0
+        * bit to allow access to non-vendor registers. */
+       if ((card->model == MODEL_8686) &&
+           (host->caps & MMC_CAP_SDIO_IRQ) &&
+           (host->ios.bus_width == MMC_BUS_WIDTH_1)) {
+               u8 reg;
+
+               func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
+               reg = sdio_f0_readb(func, SDIO_CCCR_IF, &ret);
+               if (ret)
+                       goto disable;
+
+               reg |= SDIO_BUS_ECSI;
+               sdio_f0_writeb(func, reg, SDIO_CCCR_IF, &ret);
+               if (ret)
+                       goto disable;
+       }
+
+       card->ioport = sdio_readb(func, IF_SDIO_IOPORT, &ret);
+       if (ret)
+               goto disable;
+
+       card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 1, &ret) << 8;
+       if (ret)
+               goto disable;
+
+       card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 2, &ret) << 16;
+       if (ret)
+               goto disable;
+
+       sdio_release_host(func);
+       ret = if_sdio_prog_firmware(card);
+       if (ret) {
+               sdio_claim_host(func);
+               goto disable;
+       }
+
+       return 0;
+
+disable:
+       sdio_disable_func(func);
+release:
+       sdio_release_host(func);
+       return ret;
+}
+
+static int if_sdio_power_off(struct if_sdio_card *card)
+{
+       struct sdio_func *func = card->func;
+       struct lbs_private *priv = card->priv;
+
+       priv->fw_ready = 0;
+
+       sdio_claim_host(func);
+       sdio_release_irq(func);
+       sdio_disable_func(func);
+       sdio_release_host(func);
+       return 0;
+}
+
+
+/*******************************************************************/
+/* Libertas callbacks                                              */
+/*******************************************************************/
+
+static int if_sdio_host_to_card(struct lbs_private *priv,
+               u8 type, u8 *buf, u16 nb)
+{
+       int ret;
+       struct if_sdio_card *card;
+       struct if_sdio_packet *packet, *cur;
+       u16 size;
+       unsigned long flags;
+
+       lbs_deb_enter_args(LBS_DEB_SDIO, "type %d, bytes %d", type, nb);
+
+       card = priv->card;
+
+       if (nb > (65536 - sizeof(struct if_sdio_packet) - 4)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /*
+        * The transfer must be in one transaction or the firmware
+        * goes suicidal. There's no way to guarantee that for all
+        * controllers, but we can at least try.
+        */
+       size = sdio_align_size(card->func, nb + 4);
+
+       packet = kzalloc(sizeof(struct if_sdio_packet) + size,
+                       GFP_ATOMIC);
+       if (!packet) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       packet->next = NULL;
+       packet->nb = size;
+
+       /*
+        * SDIO specific header.
+        */
+       packet->buffer[0] = (nb + 4) & 0xff;
+       packet->buffer[1] = ((nb + 4) >> 8) & 0xff;
+       packet->buffer[2] = type;
+       packet->buffer[3] = 0;
+
+       memcpy(packet->buffer + 4, buf, nb);
+
+       spin_lock_irqsave(&card->lock, flags);
+
+       if (!card->packets)
+               card->packets = packet;
+       else {
+               cur = card->packets;
+               while (cur->next)
+                       cur = cur->next;
+               cur->next = packet;
+       }
+
+       switch (type) {
+       case MVMS_CMD:
+               priv->dnld_sent = DNLD_CMD_SENT;
+               break;
+       case MVMS_DAT:
+               priv->dnld_sent = DNLD_DATA_SENT;
+               break;
+       default:
+               lbs_deb_sdio("unknown packet type %d\n", (int)type);
+       }
+
+       spin_unlock_irqrestore(&card->lock, flags);
+
+       queue_work(card->workqueue, &card->packet_worker);
+
+       ret = 0;
+
+out:
+       lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+
+       return ret;
+}
+
+static int if_sdio_enter_deep_sleep(struct lbs_private *priv)
+{
+       int ret = -1;
+       struct cmd_header cmd;
+
+       memset(&cmd, 0, sizeof(cmd));
+
+       lbs_deb_sdio("send DEEP_SLEEP command\n");
+       ret = __lbs_cmd(priv, CMD_802_11_DEEP_SLEEP, &cmd, sizeof(cmd),
+                       lbs_cmd_copyback, (unsigned long) &cmd);
+       if (ret)
+               netdev_err(priv->dev, "DEEP_SLEEP cmd failed\n");
+
+       mdelay(200);
+       return ret;
+}
+
+static int if_sdio_exit_deep_sleep(struct lbs_private *priv)
+{
+       struct if_sdio_card *card = priv->card;
+       int ret = -1;
+
+       lbs_deb_enter(LBS_DEB_SDIO);
+       sdio_claim_host(card->func);
+
+       sdio_writeb(card->func, HOST_POWER_UP, CONFIGURATION_REG, &ret);
+       if (ret)
+               netdev_err(priv->dev, "sdio_writeb failed!\n");
+
+       sdio_release_host(card->func);
+       lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+       return ret;
+}
+
+static int if_sdio_reset_deep_sleep_wakeup(struct lbs_private *priv)
+{
+       struct if_sdio_card *card = priv->card;
+       int ret = -1;
+
+       lbs_deb_enter(LBS_DEB_SDIO);
+       sdio_claim_host(card->func);
+
+       sdio_writeb(card->func, 0, CONFIGURATION_REG, &ret);
+       if (ret)
+               netdev_err(priv->dev, "sdio_writeb failed!\n");
+
+       sdio_release_host(card->func);
+       lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+       return ret;
+
+}
+
+static struct mmc_host *reset_host;
+
+static void if_sdio_reset_card_worker(struct work_struct *work)
+{
+       /*
+        * The actual reset operation must be run outside of lbs_thread. This
+        * is because mmc_remove_host() will cause the device to be instantly
+        * destroyed, and the libertas driver then needs to end lbs_thread,
+        * leading to a deadlock.
+        *
+        * We run it in a workqueue totally independent from the if_sdio_card
+        * instance for that reason.
+        */
+
+       pr_info("Resetting card...");
+       mmc_remove_host(reset_host);
+       mmc_add_host(reset_host);
+}
+static DECLARE_WORK(card_reset_work, if_sdio_reset_card_worker);
+
+static void if_sdio_reset_card(struct lbs_private *priv)
+{
+       struct if_sdio_card *card = priv->card;
+
+       if (work_pending(&card_reset_work))
+               return;
+
+       reset_host = card->func->card->host;
+       schedule_work(&card_reset_work);
+}
+
+static int if_sdio_power_save(struct lbs_private *priv)
+{
+       struct if_sdio_card *card = priv->card;
+       int ret;
+
+       flush_workqueue(card->workqueue);
+
+       ret = if_sdio_power_off(card);
+
+       /* Let runtime PM know the card is powered off */
+       pm_runtime_put_sync(&card->func->dev);
+
+       return ret;
+}
+
+static int if_sdio_power_restore(struct lbs_private *priv)
+{
+       struct if_sdio_card *card = priv->card;
+       int r;
+
+       /* Make sure the card will not be powered off by runtime PM */
+       pm_runtime_get_sync(&card->func->dev);
+
+       r = if_sdio_power_on(card);
+       if (r)
+               return r;
+
+       wait_event(card->pwron_waitq, priv->fw_ready);
+       return 0;
+}
+
+
+/*******************************************************************/
+/* SDIO callbacks                                                  */
+/*******************************************************************/
+
+static void if_sdio_interrupt(struct sdio_func *func)
+{
+       int ret;
+       struct if_sdio_card *card;
+       u8 cause;
+
+       lbs_deb_enter(LBS_DEB_SDIO);
+
+       card = sdio_get_drvdata(func);
+
+       cause = sdio_readb(card->func, IF_SDIO_H_INT_STATUS, &ret);
+       if (ret || !cause)
+               goto out;
+
+       lbs_deb_sdio("interrupt: 0x%X\n", (unsigned)cause);
+
+       sdio_writeb(card->func, ~cause, IF_SDIO_H_INT_STATUS, &ret);
+       if (ret)
+               goto out;
+
+       /*
+        * Ignore the define name, this really means the card has
+        * successfully received the command.
+        */
+       card->priv->is_activity_detected = 1;
+       if (cause & IF_SDIO_H_INT_DNLD)
+               lbs_host_to_card_done(card->priv);
+
+
+       if (cause & IF_SDIO_H_INT_UPLD) {
+               ret = if_sdio_card_to_host(card);
+               if (ret)
+                       goto out;
+       }
+
+       ret = 0;
+
+out:
+       lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+}
+
+static int if_sdio_probe(struct sdio_func *func,
+               const struct sdio_device_id *id)
+{
+       struct if_sdio_card *card;
+       struct lbs_private *priv;
+       int ret, i;
+       unsigned int model;
+       struct if_sdio_packet *packet;
+
+       lbs_deb_enter(LBS_DEB_SDIO);
+
+       for (i = 0;i < func->card->num_info;i++) {
+               if (sscanf(func->card->info[i],
+                               "802.11 SDIO ID: %x", &model) == 1)
+                       break;
+               if (sscanf(func->card->info[i],
+                               "ID: %x", &model) == 1)
+                       break;
+               if (!strcmp(func->card->info[i], "IBIS Wireless SDIO Card")) {
+                       model = MODEL_8385;
+                       break;
+               }
+       }
+
+       if (i == func->card->num_info) {
+               pr_err("unable to identify card model\n");
+               return -ENODEV;
+       }
+
+       card = kzalloc(sizeof(struct if_sdio_card), GFP_KERNEL);
+       if (!card)
+               return -ENOMEM;
+
+       card->func = func;
+       card->model = model;
+
+       switch (card->model) {
+       case MODEL_8385:
+               card->scratch_reg = IF_SDIO_SCRATCH_OLD;
+               break;
+       case MODEL_8686:
+               card->scratch_reg = IF_SDIO_SCRATCH;
+               break;
+       case MODEL_8688:
+       default: /* for newer chipsets */
+               card->scratch_reg = IF_SDIO_FW_STATUS;
+               break;
+       }
+
+       spin_lock_init(&card->lock);
+       card->workqueue = create_workqueue("libertas_sdio");
+       INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker);
+       init_waitqueue_head(&card->pwron_waitq);
+
+       /* Check if we support this card */
+       for (i = 0; i < ARRAY_SIZE(fw_table); i++) {
+               if (card->model == fw_table[i].model)
+                       break;
+       }
+       if (i == ARRAY_SIZE(fw_table)) {
+               pr_err("unknown card model 0x%x\n", card->model);
+               ret = -ENODEV;
+               goto free;
+       }
+
+       sdio_set_drvdata(func, card);
+
+       lbs_deb_sdio("class = 0x%X, vendor = 0x%X, "
+                       "device = 0x%X, model = 0x%X, ioport = 0x%X\n",
+                       func->class, func->vendor, func->device,
+                       model, (unsigned)card->ioport);
+
+
+       priv = lbs_add_card(card, &func->dev);
+       if (!priv) {
+               ret = -ENOMEM;
+               goto free;
+       }
+
+       card->priv = priv;
+
+       priv->card = card;
+       priv->hw_host_to_card = if_sdio_host_to_card;
+       priv->enter_deep_sleep = if_sdio_enter_deep_sleep;
+       priv->exit_deep_sleep = if_sdio_exit_deep_sleep;
+       priv->reset_deep_sleep_wakeup = if_sdio_reset_deep_sleep_wakeup;
+       priv->reset_card = if_sdio_reset_card;
+       priv->power_save = if_sdio_power_save;
+       priv->power_restore = if_sdio_power_restore;
+
+       ret = if_sdio_power_on(card);
+       if (ret)
+               goto err_activate_card;
+
+out:
+       lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+
+       return ret;
+
+err_activate_card:
+       flush_workqueue(card->workqueue);
+       lbs_remove_card(priv);
+free:
+       destroy_workqueue(card->workqueue);
+       while (card->packets) {
+               packet = card->packets;
+               card->packets = card->packets->next;
+               kfree(packet);
+       }
+
+       kfree(card);
+
+       goto out;
+}
+
+static void if_sdio_remove(struct sdio_func *func)
+{
+       struct if_sdio_card *card;
+       struct if_sdio_packet *packet;
+
+       lbs_deb_enter(LBS_DEB_SDIO);
+
+       card = sdio_get_drvdata(func);
+
+       /* Undo decrement done above in if_sdio_probe */
+       pm_runtime_get_noresume(&func->dev);
+
+       if (user_rmmod && (card->model == MODEL_8688)) {
+               /*
+                * FUNC_SHUTDOWN is required for SD8688 WLAN/BT
+                * multiple functions
+                */
+               struct cmd_header cmd;
+
+               memset(&cmd, 0, sizeof(cmd));
+
+               lbs_deb_sdio("send function SHUTDOWN command\n");
+               if (__lbs_cmd(card->priv, CMD_FUNC_SHUTDOWN,
+                               &cmd, sizeof(cmd), lbs_cmd_copyback,
+                               (unsigned long) &cmd))
+                       pr_alert("CMD_FUNC_SHUTDOWN cmd failed\n");
+       }
+
+
+       lbs_deb_sdio("call remove card\n");
+       lbs_stop_card(card->priv);
+       lbs_remove_card(card->priv);
+
+       flush_workqueue(card->workqueue);
+       destroy_workqueue(card->workqueue);
+
+       while (card->packets) {
+               packet = card->packets;
+               card->packets = card->packets->next;
+               kfree(packet);
+       }
+
+       kfree(card);
+       lbs_deb_leave(LBS_DEB_SDIO);
+}
+
+static int if_sdio_suspend(struct device *dev)
+{
+       struct sdio_func *func = dev_to_sdio_func(dev);
+       int ret;
+       struct if_sdio_card *card = sdio_get_drvdata(func);
+
+       mmc_pm_flag_t flags = sdio_get_host_pm_caps(func);
+
+       /* If we're powered off anyway, just let the mmc layer remove the
+        * card. */
+       if (!lbs_iface_active(card->priv))
+               return -ENOSYS;
+
+       dev_info(dev, "%s: suspend: PM flags = 0x%x\n",
+                sdio_func_id(func), flags);
+
+       /* If we aren't being asked to wake on anything, we should bail out
+        * and let the SD stack power down the card.
+        */
+       if (card->priv->wol_criteria == EHS_REMOVE_WAKEUP) {
+               dev_info(dev, "Suspend without wake params -- powering down card\n");
+               return -ENOSYS;
+       }
+
+       if (!(flags & MMC_PM_KEEP_POWER)) {
+               dev_err(dev, "%s: cannot remain alive while host is suspended\n",
+                       sdio_func_id(func));
+               return -ENOSYS;
+       }
+
+       ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
+       if (ret)
+               return ret;
+
+       ret = lbs_suspend(card->priv);
+       if (ret)
+               return ret;
+
+       return sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ);
+}
+
+static int if_sdio_resume(struct device *dev)
+{
+       struct sdio_func *func = dev_to_sdio_func(dev);
+       struct if_sdio_card *card = sdio_get_drvdata(func);
+       int ret;
+
+       dev_info(dev, "%s: resume: we're back\n", sdio_func_id(func));
+
+       ret = lbs_resume(card->priv);
+
+       return ret;
+}
+
+static const struct dev_pm_ops if_sdio_pm_ops = {
+       .suspend        = if_sdio_suspend,
+       .resume         = if_sdio_resume,
+};
+
+static struct sdio_driver if_sdio_driver = {
+       .name           = "libertas_sdio",
+       .id_table       = if_sdio_ids,
+       .probe          = if_sdio_probe,
+       .remove         = if_sdio_remove,
+       .drv = {
+               .pm = &if_sdio_pm_ops,
+       },
+};
+
+/*******************************************************************/
+/* Module functions                                                */
+/*******************************************************************/
+
+static int __init if_sdio_init_module(void)
+{
+       int ret = 0;
+
+       lbs_deb_enter(LBS_DEB_SDIO);
+
+       printk(KERN_INFO "libertas_sdio: Libertas SDIO driver\n");
+       printk(KERN_INFO "libertas_sdio: Copyright Pierre Ossman\n");
+
+       ret = sdio_register_driver(&if_sdio_driver);
+
+       /* Clear the flag in case user removes the card. */
+       user_rmmod = 0;
+
+       lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+
+       return ret;
+}
+
+static void __exit if_sdio_exit_module(void)
+{
+       lbs_deb_enter(LBS_DEB_SDIO);
+
+       /* Set the flag as user is removing this module. */
+       user_rmmod = 1;
+
+       cancel_work_sync(&card_reset_work);
+
+       sdio_unregister_driver(&if_sdio_driver);
+
+       lbs_deb_leave(LBS_DEB_SDIO);
+}
+
+module_init(if_sdio_init_module);
+module_exit(if_sdio_exit_module);
+
+MODULE_DESCRIPTION("Libertas SDIO WLAN Driver");
+MODULE_AUTHOR("Pierre Ossman");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/marvell/libertas/if_sdio.h b/drivers/net/wireless/marvell/libertas/if_sdio.h
new file mode 100644 (file)
index 0000000..62fda35
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ *  linux/drivers/net/wireless/libertas/if_sdio.h
+ *
+ *  Copyright 2007 Pierre Ossman
+ *
+ * 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.
+ */
+
+#ifndef _LBS_IF_SDIO_H
+#define _LBS_IF_SDIO_H
+
+#define IF_SDIO_IOPORT         0x00
+
+#define IF_SDIO_H_INT_MASK     0x04
+#define   IF_SDIO_H_INT_OFLOW  0x08
+#define   IF_SDIO_H_INT_UFLOW  0x04
+#define   IF_SDIO_H_INT_DNLD   0x02
+#define   IF_SDIO_H_INT_UPLD   0x01
+
+#define IF_SDIO_H_INT_STATUS   0x05
+#define IF_SDIO_H_INT_RSR      0x06
+#define IF_SDIO_H_INT_STATUS2  0x07
+
+#define IF_SDIO_RD_BASE                0x10
+
+#define IF_SDIO_STATUS         0x20
+#define   IF_SDIO_IO_RDY       0x08
+#define   IF_SDIO_CIS_RDY      0x04
+#define   IF_SDIO_UL_RDY       0x02
+#define   IF_SDIO_DL_RDY       0x01
+
+#define IF_SDIO_C_INT_MASK     0x24
+#define IF_SDIO_C_INT_STATUS   0x28
+#define IF_SDIO_C_INT_RSR      0x2C
+
+#define IF_SDIO_SCRATCH                0x34
+#define IF_SDIO_SCRATCH_OLD    0x80fe
+#define IF_SDIO_FW_STATUS      0x40
+#define   IF_SDIO_FIRMWARE_OK  0xfedc
+
+#define IF_SDIO_RX_LEN         0x42
+#define IF_SDIO_RX_UNIT                0x43
+
+#define IF_SDIO_EVENT           0x80fc
+
+#define IF_SDIO_BLOCK_SIZE     256
+#define CONFIGURATION_REG               0x03
+#define HOST_POWER_UP                   (0x1U << 1)
+#endif
diff --git a/drivers/net/wireless/marvell/libertas/if_spi.c b/drivers/net/wireless/marvell/libertas/if_spi.c
new file mode 100644 (file)
index 0000000..82c0796
--- /dev/null
@@ -0,0 +1,1318 @@
+/*
+ *     linux/drivers/net/wireless/libertas/if_spi.c
+ *
+ *     Driver for Marvell SPI WLAN cards.
+ *
+ *     Copyright 2008 Analog Devices Inc.
+ *
+ *     Authors:
+ *     Andrey Yurovsky <andrey@cozybit.com>
+ *     Colin McCabe <colin@cozybit.com>
+ *
+ *     Inspired by if_sdio.c, Copyright 2007-2008 Pierre Ossman
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/hardirq.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/firmware.h>
+#include <linux/jiffies.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/slab.h>
+#include <linux/spi/libertas_spi.h>
+#include <linux/spi/spi.h>
+
+#include "host.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "if_spi.h"
+
+struct if_spi_packet {
+       struct list_head                list;
+       u16                             blen;
+       u8                              buffer[0] __attribute__((aligned(4)));
+};
+
+struct if_spi_card {
+       struct spi_device               *spi;
+       struct lbs_private              *priv;
+       struct libertas_spi_platform_data *pdata;
+
+       /* The card ID and card revision, as reported by the hardware. */
+       u16                             card_id;
+       u8                              card_rev;
+
+       /* The last time that we initiated an SPU operation */
+       unsigned long                   prev_xfer_time;
+
+       int                             use_dummy_writes;
+       unsigned long                   spu_port_delay;
+       unsigned long                   spu_reg_delay;
+
+       /* Handles all SPI communication (except for FW load) */
+       struct workqueue_struct         *workqueue;
+       struct work_struct              packet_work;
+       struct work_struct              resume_work;
+
+       u8                              cmd_buffer[IF_SPI_CMD_BUF_SIZE];
+
+       /* A buffer of incoming packets from libertas core.
+        * Since we can't sleep in hw_host_to_card, we have to buffer
+        * them. */
+       struct list_head                cmd_packet_list;
+       struct list_head                data_packet_list;
+
+       /* Protects cmd_packet_list and data_packet_list */
+       spinlock_t                      buffer_lock;
+
+       /* True is card suspended */
+       u8                              suspended;
+};
+
+static void free_if_spi_card(struct if_spi_card *card)
+{
+       struct list_head *cursor, *next;
+       struct if_spi_packet *packet;
+
+       list_for_each_safe(cursor, next, &card->cmd_packet_list) {
+               packet = container_of(cursor, struct if_spi_packet, list);
+               list_del(&packet->list);
+               kfree(packet);
+       }
+       list_for_each_safe(cursor, next, &card->data_packet_list) {
+               packet = container_of(cursor, struct if_spi_packet, list);
+               list_del(&packet->list);
+               kfree(packet);
+       }
+       kfree(card);
+}
+
+#define MODEL_8385     0x04
+#define MODEL_8686     0x0b
+#define MODEL_8688     0x10
+
+static const struct lbs_fw_table fw_table[] = {
+       { MODEL_8385, "libertas/gspi8385_helper.bin", "libertas/gspi8385.bin" },
+       { MODEL_8385, "libertas/gspi8385_hlp.bin", "libertas/gspi8385.bin" },
+       { MODEL_8686, "libertas/gspi8686_v9_helper.bin", "libertas/gspi8686_v9.bin" },
+       { MODEL_8686, "libertas/gspi8686_hlp.bin", "libertas/gspi8686.bin" },
+       { MODEL_8688, "libertas/gspi8688_helper.bin", "libertas/gspi8688.bin" },
+       { 0, NULL, NULL }
+};
+MODULE_FIRMWARE("libertas/gspi8385_helper.bin");
+MODULE_FIRMWARE("libertas/gspi8385_hlp.bin");
+MODULE_FIRMWARE("libertas/gspi8385.bin");
+MODULE_FIRMWARE("libertas/gspi8686_v9_helper.bin");
+MODULE_FIRMWARE("libertas/gspi8686_v9.bin");
+MODULE_FIRMWARE("libertas/gspi8686_hlp.bin");
+MODULE_FIRMWARE("libertas/gspi8686.bin");
+MODULE_FIRMWARE("libertas/gspi8688_helper.bin");
+MODULE_FIRMWARE("libertas/gspi8688.bin");
+
+
+/*
+ * SPI Interface Unit Routines
+ *
+ * The SPU sits between the host and the WLAN module.
+ * All communication with the firmware is through SPU transactions.
+ *
+ * First we have to put a SPU register name on the bus. Then we can
+ * either read from or write to that register.
+ *
+ */
+
+static void spu_transaction_init(struct if_spi_card *card)
+{
+       if (!time_after(jiffies, card->prev_xfer_time + 1)) {
+               /* Unfortunately, the SPU requires a delay between successive
+                * transactions. If our last transaction was more than a jiffy
+                * ago, we have obviously already delayed enough.
+                * If not, we have to busy-wait to be on the safe side. */
+               ndelay(400);
+       }
+}
+
+static void spu_transaction_finish(struct if_spi_card *card)
+{
+       card->prev_xfer_time = jiffies;
+}
+
+/*
+ * Write out a byte buffer to an SPI register,
+ * using a series of 16-bit transfers.
+ */
+static int spu_write(struct if_spi_card *card, u16 reg, const u8 *buf, int len)
+{
+       int err = 0;
+       __le16 reg_out = cpu_to_le16(reg | IF_SPI_WRITE_OPERATION_MASK);
+       struct spi_message m;
+       struct spi_transfer reg_trans;
+       struct spi_transfer data_trans;
+
+       spi_message_init(&m);
+       memset(&reg_trans, 0, sizeof(reg_trans));
+       memset(&data_trans, 0, sizeof(data_trans));
+
+       /* You must give an even number of bytes to the SPU, even if it
+        * doesn't care about the last one.  */
+       BUG_ON(len & 0x1);
+
+       spu_transaction_init(card);
+
+       /* write SPU register index */
+       reg_trans.tx_buf = &reg_out;
+       reg_trans.len = sizeof(reg_out);
+
+       data_trans.tx_buf = buf;
+       data_trans.len = len;
+
+       spi_message_add_tail(&reg_trans, &m);
+       spi_message_add_tail(&data_trans, &m);
+
+       err = spi_sync(card->spi, &m);
+       spu_transaction_finish(card);
+       return err;
+}
+
+static inline int spu_write_u16(struct if_spi_card *card, u16 reg, u16 val)
+{
+       __le16 buff;
+
+       buff = cpu_to_le16(val);
+       return spu_write(card, reg, (u8 *)&buff, sizeof(u16));
+}
+
+static inline int spu_reg_is_port_reg(u16 reg)
+{
+       switch (reg) {
+       case IF_SPI_IO_RDWRPORT_REG:
+       case IF_SPI_CMD_RDWRPORT_REG:
+       case IF_SPI_DATA_RDWRPORT_REG:
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+static int spu_read(struct if_spi_card *card, u16 reg, u8 *buf, int len)
+{
+       unsigned int delay;
+       int err = 0;
+       __le16 reg_out = cpu_to_le16(reg | IF_SPI_READ_OPERATION_MASK);
+       struct spi_message m;
+       struct spi_transfer reg_trans;
+       struct spi_transfer dummy_trans;
+       struct spi_transfer data_trans;
+
+       /*
+        * You must take an even number of bytes from the SPU, even if you
+        * don't care about the last one.
+        */
+       BUG_ON(len & 0x1);
+
+       spu_transaction_init(card);
+
+       spi_message_init(&m);
+       memset(&reg_trans, 0, sizeof(reg_trans));
+       memset(&dummy_trans, 0, sizeof(dummy_trans));
+       memset(&data_trans, 0, sizeof(data_trans));
+
+       /* write SPU register index */
+       reg_trans.tx_buf = &reg_out;
+       reg_trans.len = sizeof(reg_out);
+       spi_message_add_tail(&reg_trans, &m);
+
+       delay = spu_reg_is_port_reg(reg) ? card->spu_port_delay :
+                                               card->spu_reg_delay;
+       if (card->use_dummy_writes) {
+               /* Clock in dummy cycles while the SPU fills the FIFO */
+               dummy_trans.len = delay / 8;
+               spi_message_add_tail(&dummy_trans, &m);
+       } else {
+               /* Busy-wait while the SPU fills the FIFO */
+               reg_trans.delay_usecs =
+                       DIV_ROUND_UP((100 + (delay * 10)), 1000);
+       }
+
+       /* read in data */
+       data_trans.rx_buf = buf;
+       data_trans.len = len;
+       spi_message_add_tail(&data_trans, &m);
+
+       err = spi_sync(card->spi, &m);
+       spu_transaction_finish(card);
+       return err;
+}
+
+/* Read 16 bits from an SPI register */
+static inline int spu_read_u16(struct if_spi_card *card, u16 reg, u16 *val)
+{
+       __le16 buf;
+       int ret;
+
+       ret = spu_read(card, reg, (u8 *)&buf, sizeof(buf));
+       if (ret == 0)
+               *val = le16_to_cpup(&buf);
+       return ret;
+}
+
+/*
+ * Read 32 bits from an SPI register.
+ * The low 16 bits are read first.
+ */
+static int spu_read_u32(struct if_spi_card *card, u16 reg, u32 *val)
+{
+       __le32 buf;
+       int err;
+
+       err = spu_read(card, reg, (u8 *)&buf, sizeof(buf));
+       if (!err)
+               *val = le32_to_cpup(&buf);
+       return err;
+}
+
+/*
+ * Keep reading 16 bits from an SPI register until you get the correct result.
+ *
+ * If mask = 0, the correct result is any non-zero number.
+ * If mask != 0, the correct result is any number where
+ * number & target_mask == target
+ *
+ * Returns -ETIMEDOUT if a second passes without the correct result.
+ */
+static int spu_wait_for_u16(struct if_spi_card *card, u16 reg,
+                       u16 target_mask, u16 target)
+{
+       int err;
+       unsigned long timeout = jiffies + 5*HZ;
+       while (1) {
+               u16 val;
+               err = spu_read_u16(card, reg, &val);
+               if (err)
+                       return err;
+               if (target_mask) {
+                       if ((val & target_mask) == target)
+                               return 0;
+               } else {
+                       if (val)
+                               return 0;
+               }
+               udelay(100);
+               if (time_after(jiffies, timeout)) {
+                       pr_err("%s: timeout with val=%02x, target_mask=%02x, target=%02x\n",
+                              __func__, val, target_mask, target);
+                       return -ETIMEDOUT;
+               }
+       }
+}
+
+/*
+ * Read 16 bits from an SPI register until you receive a specific value.
+ * Returns -ETIMEDOUT if a 4 tries pass without success.
+ */
+static int spu_wait_for_u32(struct if_spi_card *card, u32 reg, u32 target)
+{
+       int err, try;
+       for (try = 0; try < 4; ++try) {
+               u32 val = 0;
+               err = spu_read_u32(card, reg, &val);
+               if (err)
+                       return err;
+               if (val == target)
+                       return 0;
+               mdelay(100);
+       }
+       return -ETIMEDOUT;
+}
+
+static int spu_set_interrupt_mode(struct if_spi_card *card,
+                          int suppress_host_int,
+                          int auto_int)
+{
+       int err = 0;
+
+       /*
+        * We can suppress a host interrupt by clearing the appropriate
+        * bit in the "host interrupt status mask" register
+        */
+       if (suppress_host_int) {
+               err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_MASK_REG, 0);
+               if (err)
+                       return err;
+       } else {
+               err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_MASK_REG,
+                             IF_SPI_HISM_TX_DOWNLOAD_RDY |
+                             IF_SPI_HISM_RX_UPLOAD_RDY |
+                             IF_SPI_HISM_CMD_DOWNLOAD_RDY |
+                             IF_SPI_HISM_CARDEVENT |
+                             IF_SPI_HISM_CMD_UPLOAD_RDY);
+               if (err)
+                       return err;
+       }
+
+       /*
+        * If auto-interrupts are on, the completion of certain transactions
+        * will trigger an interrupt automatically. If auto-interrupts
+        * are off, we need to set the "Card Interrupt Cause" register to
+        * trigger a card interrupt.
+        */
+       if (auto_int) {
+               err = spu_write_u16(card, IF_SPI_HOST_INT_CTRL_REG,
+                               IF_SPI_HICT_TX_DOWNLOAD_OVER_AUTO |
+                               IF_SPI_HICT_RX_UPLOAD_OVER_AUTO |
+                               IF_SPI_HICT_CMD_DOWNLOAD_OVER_AUTO |
+                               IF_SPI_HICT_CMD_UPLOAD_OVER_AUTO);
+               if (err)
+                       return err;
+       } else {
+               err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_MASK_REG, 0);
+               if (err)
+                       return err;
+       }
+       return err;
+}
+
+static int spu_get_chip_revision(struct if_spi_card *card,
+                                 u16 *card_id, u8 *card_rev)
+{
+       int err = 0;
+       u32 dev_ctrl;
+       err = spu_read_u32(card, IF_SPI_DEVICEID_CTRL_REG, &dev_ctrl);
+       if (err)
+               return err;
+       *card_id = IF_SPI_DEVICEID_CTRL_REG_TO_CARD_ID(dev_ctrl);
+       *card_rev = IF_SPI_DEVICEID_CTRL_REG_TO_CARD_REV(dev_ctrl);
+       return err;
+}
+
+static int spu_set_bus_mode(struct if_spi_card *card, u16 mode)
+{
+       int err = 0;
+       u16 rval;
+       /* set bus mode */
+       err = spu_write_u16(card, IF_SPI_SPU_BUS_MODE_REG, mode);
+       if (err)
+               return err;
+       /* Check that we were able to read back what we just wrote. */
+       err = spu_read_u16(card, IF_SPI_SPU_BUS_MODE_REG, &rval);
+       if (err)
+               return err;
+       if ((rval & 0xF) != mode) {
+               pr_err("Can't read bus mode register\n");
+               return -EIO;
+       }
+       return 0;
+}
+
+static int spu_init(struct if_spi_card *card, int use_dummy_writes)
+{
+       int err = 0;
+       u32 delay;
+
+       /*
+        * We have to start up in timed delay mode so that we can safely
+        * read the Delay Read Register.
+        */
+       card->use_dummy_writes = 0;
+       err = spu_set_bus_mode(card,
+                               IF_SPI_BUS_MODE_SPI_CLOCK_PHASE_RISING |
+                               IF_SPI_BUS_MODE_DELAY_METHOD_TIMED |
+                               IF_SPI_BUS_MODE_16_BIT_ADDRESS_16_BIT_DATA);
+       if (err)
+               return err;
+       card->spu_port_delay = 1000;
+       card->spu_reg_delay = 1000;
+       err = spu_read_u32(card, IF_SPI_DELAY_READ_REG, &delay);
+       if (err)
+               return err;
+       card->spu_port_delay = delay & 0x0000ffff;
+       card->spu_reg_delay = (delay & 0xffff0000) >> 16;
+
+       /* If dummy clock delay mode has been requested, switch to it now */
+       if (use_dummy_writes) {
+               card->use_dummy_writes = 1;
+               err = spu_set_bus_mode(card,
+                               IF_SPI_BUS_MODE_SPI_CLOCK_PHASE_RISING |
+                               IF_SPI_BUS_MODE_DELAY_METHOD_DUMMY_CLOCK |
+                               IF_SPI_BUS_MODE_16_BIT_ADDRESS_16_BIT_DATA);
+               if (err)
+                       return err;
+       }
+
+       lbs_deb_spi("Initialized SPU unit. "
+                   "spu_port_delay=0x%04lx, spu_reg_delay=0x%04lx\n",
+                   card->spu_port_delay, card->spu_reg_delay);
+       return err;
+}
+
+/*
+ * Firmware Loading
+ */
+
+static int if_spi_prog_helper_firmware(struct if_spi_card *card,
+                                       const struct firmware *firmware)
+{
+       int err = 0;
+       int bytes_remaining;
+       const u8 *fw;
+       u8 temp[HELPER_FW_LOAD_CHUNK_SZ];
+
+       lbs_deb_enter(LBS_DEB_SPI);
+
+       err = spu_set_interrupt_mode(card, 1, 0);
+       if (err)
+               goto out;
+
+       bytes_remaining = firmware->size;
+       fw = firmware->data;
+
+       /* Load helper firmware image */
+       while (bytes_remaining > 0) {
+               /*
+                * Scratch pad 1 should contain the number of bytes we
+                * want to download to the firmware
+                */
+               err = spu_write_u16(card, IF_SPI_SCRATCH_1_REG,
+                                       HELPER_FW_LOAD_CHUNK_SZ);
+               if (err)
+                       goto out;
+
+               err = spu_wait_for_u16(card, IF_SPI_HOST_INT_STATUS_REG,
+                                       IF_SPI_HIST_CMD_DOWNLOAD_RDY,
+                                       IF_SPI_HIST_CMD_DOWNLOAD_RDY);
+               if (err)
+                       goto out;
+
+               /*
+                * Feed the data into the command read/write port reg
+                * in chunks of 64 bytes
+                */
+               memset(temp, 0, sizeof(temp));
+               memcpy(temp, fw,
+                      min(bytes_remaining, HELPER_FW_LOAD_CHUNK_SZ));
+               mdelay(10);
+               err = spu_write(card, IF_SPI_CMD_RDWRPORT_REG,
+                                       temp, HELPER_FW_LOAD_CHUNK_SZ);
+               if (err)
+                       goto out;
+
+               /* Interrupt the boot code */
+               err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG, 0);
+               if (err)
+                       goto out;
+               err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG,
+                                      IF_SPI_CIC_CMD_DOWNLOAD_OVER);
+               if (err)
+                       goto out;
+               bytes_remaining -= HELPER_FW_LOAD_CHUNK_SZ;
+               fw += HELPER_FW_LOAD_CHUNK_SZ;
+       }
+
+       /*
+        * Once the helper / single stage firmware download is complete,
+        * write 0 to scratch pad 1 and interrupt the
+        * bootloader. This completes the helper download.
+        */
+       err = spu_write_u16(card, IF_SPI_SCRATCH_1_REG, FIRMWARE_DNLD_OK);
+       if (err)
+               goto out;
+       err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG, 0);
+       if (err)
+               goto out;
+       err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG,
+                               IF_SPI_CIC_CMD_DOWNLOAD_OVER);
+out:
+       if (err)
+               pr_err("failed to load helper firmware (err=%d)\n", err);
+       lbs_deb_leave_args(LBS_DEB_SPI, "err %d", err);
+       return err;
+}
+
+/*
+ * Returns the length of the next packet the firmware expects us to send.
+ * Sets crc_err if the previous transfer had a CRC error.
+ */
+static int if_spi_prog_main_firmware_check_len(struct if_spi_card *card,
+                                               int *crc_err)
+{
+       u16 len;
+       int err = 0;
+
+       /*
+        * wait until the host interrupt status register indicates
+        * that we are ready to download
+        */
+       err = spu_wait_for_u16(card, IF_SPI_HOST_INT_STATUS_REG,
+                               IF_SPI_HIST_CMD_DOWNLOAD_RDY,
+                               IF_SPI_HIST_CMD_DOWNLOAD_RDY);
+       if (err) {
+               pr_err("timed out waiting for host_int_status\n");
+               return err;
+       }
+
+       /* Ask the device how many bytes of firmware it wants. */
+       err = spu_read_u16(card, IF_SPI_SCRATCH_1_REG, &len);
+       if (err)
+               return err;
+
+       if (len > IF_SPI_CMD_BUF_SIZE) {
+               pr_err("firmware load device requested a larger transfer than we are prepared to handle (len = %d)\n",
+                      len);
+               return -EIO;
+       }
+       if (len & 0x1) {
+               lbs_deb_spi("%s: crc error\n", __func__);
+               len &= ~0x1;
+               *crc_err = 1;
+       } else
+               *crc_err = 0;
+
+       return len;
+}
+
+static int if_spi_prog_main_firmware(struct if_spi_card *card,
+                                       const struct firmware *firmware)
+{
+       struct lbs_private *priv = card->priv;
+       int len, prev_len;
+       int bytes, crc_err = 0, err = 0;
+       const u8 *fw;
+       u16 num_crc_errs;
+
+       lbs_deb_enter(LBS_DEB_SPI);
+
+       err = spu_set_interrupt_mode(card, 1, 0);
+       if (err)
+               goto out;
+
+       err = spu_wait_for_u16(card, IF_SPI_SCRATCH_1_REG, 0, 0);
+       if (err) {
+               netdev_err(priv->dev,
+                          "%s: timed out waiting for initial scratch reg = 0\n",
+                          __func__);
+               goto out;
+       }
+
+       num_crc_errs = 0;
+       prev_len = 0;
+       bytes = firmware->size;
+       fw = firmware->data;
+       while ((len = if_spi_prog_main_firmware_check_len(card, &crc_err))) {
+               if (len < 0) {
+                       err = len;
+                       goto out;
+               }
+               if (bytes < 0) {
+                       /*
+                        * If there are no more bytes left, we would normally
+                        * expect to have terminated with len = 0
+                        */
+                       netdev_err(priv->dev,
+                                  "Firmware load wants more bytes than we have to offer.\n");
+                       break;
+               }
+               if (crc_err) {
+                       /* Previous transfer failed. */
+                       if (++num_crc_errs > MAX_MAIN_FW_LOAD_CRC_ERR) {
+                               pr_err("Too many CRC errors encountered in firmware load.\n");
+                               err = -EIO;
+                               goto out;
+                       }
+               } else {
+                       /* Previous transfer succeeded. Advance counters. */
+                       bytes -= prev_len;
+                       fw += prev_len;
+               }
+               if (bytes < len) {
+                       memset(card->cmd_buffer, 0, len);
+                       memcpy(card->cmd_buffer, fw, bytes);
+               } else
+                       memcpy(card->cmd_buffer, fw, len);
+
+               err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG, 0);
+               if (err)
+                       goto out;
+               err = spu_write(card, IF_SPI_CMD_RDWRPORT_REG,
+                               card->cmd_buffer, len);
+               if (err)
+                       goto out;
+               err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG ,
+                                       IF_SPI_CIC_CMD_DOWNLOAD_OVER);
+               if (err)
+                       goto out;
+               prev_len = len;
+       }
+       if (bytes > prev_len) {
+               pr_err("firmware load wants fewer bytes than we have to offer\n");
+       }
+
+       /* Confirm firmware download */
+       err = spu_wait_for_u32(card, IF_SPI_SCRATCH_4_REG,
+                                       SUCCESSFUL_FW_DOWNLOAD_MAGIC);
+       if (err) {
+               pr_err("failed to confirm the firmware download\n");
+               goto out;
+       }
+
+out:
+       if (err)
+               pr_err("failed to load firmware (err=%d)\n", err);
+       lbs_deb_leave_args(LBS_DEB_SPI, "err %d", err);
+       return err;
+}
+
+/*
+ * SPI Transfer Thread
+ *
+ * The SPI worker handles all SPI transfers, so there is no need for a lock.
+ */
+
+/* Move a command from the card to the host */
+static int if_spi_c2h_cmd(struct if_spi_card *card)
+{
+       struct lbs_private *priv = card->priv;
+       unsigned long flags;
+       int err = 0;
+       u16 len;
+       u8 i;
+
+       /*
+        * We need a buffer big enough to handle whatever people send to
+        * hw_host_to_card
+        */
+       BUILD_BUG_ON(IF_SPI_CMD_BUF_SIZE < LBS_CMD_BUFFER_SIZE);
+       BUILD_BUG_ON(IF_SPI_CMD_BUF_SIZE < LBS_UPLD_SIZE);
+
+       /*
+        * It's just annoying if the buffer size isn't a multiple of 4, because
+        * then we might have len < IF_SPI_CMD_BUF_SIZE but
+        * ALIGN(len, 4) > IF_SPI_CMD_BUF_SIZE
+        */
+       BUILD_BUG_ON(IF_SPI_CMD_BUF_SIZE % 4 != 0);
+
+       lbs_deb_enter(LBS_DEB_SPI);
+
+       /* How many bytes are there to read? */
+       err = spu_read_u16(card, IF_SPI_SCRATCH_2_REG, &len);
+       if (err)
+               goto out;
+       if (!len) {
+               netdev_err(priv->dev, "%s: error: card has no data for host\n",
+                          __func__);
+               err = -EINVAL;
+               goto out;
+       } else if (len > IF_SPI_CMD_BUF_SIZE) {
+               netdev_err(priv->dev,
+                          "%s: error: response packet too large: %d bytes, but maximum is %d\n",
+                          __func__, len, IF_SPI_CMD_BUF_SIZE);
+               err = -EINVAL;
+               goto out;
+       }
+
+       /* Read the data from the WLAN module into our command buffer */
+       err = spu_read(card, IF_SPI_CMD_RDWRPORT_REG,
+                               card->cmd_buffer, ALIGN(len, 4));
+       if (err)
+               goto out;
+
+       spin_lock_irqsave(&priv->driver_lock, flags);
+       i = (priv->resp_idx == 0) ? 1 : 0;
+       BUG_ON(priv->resp_len[i]);
+       priv->resp_len[i] = len;
+       memcpy(priv->resp_buf[i], card->cmd_buffer, len);
+       lbs_notify_command_response(priv, i);
+       spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+out:
+       if (err)
+               netdev_err(priv->dev, "%s: err=%d\n", __func__, err);
+       lbs_deb_leave(LBS_DEB_SPI);
+       return err;
+}
+
+/* Move data from the card to the host */
+static int if_spi_c2h_data(struct if_spi_card *card)
+{
+       struct lbs_private *priv = card->priv;
+       struct sk_buff *skb;
+       char *data;
+       u16 len;
+       int err = 0;
+
+       lbs_deb_enter(LBS_DEB_SPI);
+
+       /* How many bytes are there to read? */
+       err = spu_read_u16(card, IF_SPI_SCRATCH_1_REG, &len);
+       if (err)
+               goto out;
+       if (!len) {
+               netdev_err(priv->dev, "%s: error: card has no data for host\n",
+                          __func__);
+               err = -EINVAL;
+               goto out;
+       } else if (len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
+               netdev_err(priv->dev,
+                          "%s: error: card has %d bytes of data, but our maximum skb size is %zu\n",
+                          __func__, len, MRVDRV_ETH_RX_PACKET_BUFFER_SIZE);
+               err = -EINVAL;
+               goto out;
+       }
+
+       /* TODO: should we allocate a smaller skb if we have less data? */
+       skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE);
+       if (!skb) {
+               err = -ENOBUFS;
+               goto out;
+       }
+       skb_reserve(skb, IPFIELD_ALIGN_OFFSET);
+       data = skb_put(skb, len);
+
+       /* Read the data from the WLAN module into our skb... */
+       err = spu_read(card, IF_SPI_DATA_RDWRPORT_REG, data, ALIGN(len, 4));
+       if (err)
+               goto free_skb;
+
+       /* pass the SKB to libertas */
+       err = lbs_process_rxed_packet(card->priv, skb);
+       if (err)
+               goto free_skb;
+
+       /* success */
+       goto out;
+
+free_skb:
+       dev_kfree_skb(skb);
+out:
+       if (err)
+               netdev_err(priv->dev, "%s: err=%d\n", __func__, err);
+       lbs_deb_leave(LBS_DEB_SPI);
+       return err;
+}
+
+/* Move data or a command from the host to the card. */
+static void if_spi_h2c(struct if_spi_card *card,
+                       struct if_spi_packet *packet, int type)
+{
+       struct lbs_private *priv = card->priv;
+       int err = 0;
+       u16 int_type, port_reg;
+
+       switch (type) {
+       case MVMS_DAT:
+               int_type = IF_SPI_CIC_TX_DOWNLOAD_OVER;
+               port_reg = IF_SPI_DATA_RDWRPORT_REG;
+               break;
+       case MVMS_CMD:
+               int_type = IF_SPI_CIC_CMD_DOWNLOAD_OVER;
+               port_reg = IF_SPI_CMD_RDWRPORT_REG;
+               break;
+       default:
+               netdev_err(priv->dev, "can't transfer buffer of type %d\n",
+                          type);
+               err = -EINVAL;
+               goto out;
+       }
+
+       /* Write the data to the card */
+       err = spu_write(card, port_reg, packet->buffer, packet->blen);
+       if (err)
+               goto out;
+
+out:
+       kfree(packet);
+
+       if (err)
+               netdev_err(priv->dev, "%s: error %d\n", __func__, err);
+}
+
+/* Inform the host about a card event */
+static void if_spi_e2h(struct if_spi_card *card)
+{
+       int err = 0;
+       u32 cause;
+       struct lbs_private *priv = card->priv;
+
+       err = spu_read_u32(card, IF_SPI_SCRATCH_3_REG, &cause);
+       if (err)
+               goto out;
+
+       /* re-enable the card event interrupt */
+       spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG,
+                       ~IF_SPI_HICU_CARD_EVENT);
+
+       /* generate a card interrupt */
+       spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG, IF_SPI_CIC_HOST_EVENT);
+
+       lbs_queue_event(priv, cause & 0xff);
+out:
+       if (err)
+               netdev_err(priv->dev, "%s: error %d\n", __func__, err);
+}
+
+static void if_spi_host_to_card_worker(struct work_struct *work)
+{
+       int err;
+       struct if_spi_card *card;
+       u16 hiStatus;
+       unsigned long flags;
+       struct if_spi_packet *packet;
+       struct lbs_private *priv;
+
+       card = container_of(work, struct if_spi_card, packet_work);
+       priv = card->priv;
+
+       lbs_deb_enter(LBS_DEB_SPI);
+
+       /*
+        * Read the host interrupt status register to see what we
+        * can do.
+        */
+       err = spu_read_u16(card, IF_SPI_HOST_INT_STATUS_REG,
+                               &hiStatus);
+       if (err) {
+               netdev_err(priv->dev, "I/O error\n");
+               goto err;
+       }
+
+       if (hiStatus & IF_SPI_HIST_CMD_UPLOAD_RDY) {
+               err = if_spi_c2h_cmd(card);
+               if (err)
+                       goto err;
+       }
+       if (hiStatus & IF_SPI_HIST_RX_UPLOAD_RDY) {
+               err = if_spi_c2h_data(card);
+               if (err)
+                       goto err;
+       }
+
+       /*
+        * workaround: in PS mode, the card does not set the Command
+        * Download Ready bit, but it sets TX Download Ready.
+        */
+       if (hiStatus & IF_SPI_HIST_CMD_DOWNLOAD_RDY ||
+          (card->priv->psstate != PS_STATE_FULL_POWER &&
+           (hiStatus & IF_SPI_HIST_TX_DOWNLOAD_RDY))) {
+               /*
+                * This means two things. First of all,
+                * if there was a previous command sent, the card has
+                * successfully received it.
+                * Secondly, it is now ready to download another
+                * command.
+                */
+               lbs_host_to_card_done(card->priv);
+
+               /* Do we have any command packets from the host to send? */
+               packet = NULL;
+               spin_lock_irqsave(&card->buffer_lock, flags);
+               if (!list_empty(&card->cmd_packet_list)) {
+                       packet = (struct if_spi_packet *)(card->
+                                       cmd_packet_list.next);
+                       list_del(&packet->list);
+               }
+               spin_unlock_irqrestore(&card->buffer_lock, flags);
+
+               if (packet)
+                       if_spi_h2c(card, packet, MVMS_CMD);
+       }
+       if (hiStatus & IF_SPI_HIST_TX_DOWNLOAD_RDY) {
+               /* Do we have any data packets from the host to send? */
+               packet = NULL;
+               spin_lock_irqsave(&card->buffer_lock, flags);
+               if (!list_empty(&card->data_packet_list)) {
+                       packet = (struct if_spi_packet *)(card->
+                                       data_packet_list.next);
+                       list_del(&packet->list);
+               }
+               spin_unlock_irqrestore(&card->buffer_lock, flags);
+
+               if (packet)
+                       if_spi_h2c(card, packet, MVMS_DAT);
+       }
+       if (hiStatus & IF_SPI_HIST_CARD_EVENT)
+               if_spi_e2h(card);
+
+err:
+       if (err)
+               netdev_err(priv->dev, "%s: got error %d\n", __func__, err);
+
+       lbs_deb_leave(LBS_DEB_SPI);
+}
+
+/*
+ * Host to Card
+ *
+ * Called from Libertas to transfer some data to the WLAN device
+ * We can't sleep here.
+ */
+static int if_spi_host_to_card(struct lbs_private *priv,
+                               u8 type, u8 *buf, u16 nb)
+{
+       int err = 0;
+       unsigned long flags;
+       struct if_spi_card *card = priv->card;
+       struct if_spi_packet *packet;
+       u16 blen;
+
+       lbs_deb_enter_args(LBS_DEB_SPI, "type %d, bytes %d", type, nb);
+
+       if (nb == 0) {
+               netdev_err(priv->dev, "%s: invalid size requested: %d\n",
+                          __func__, nb);
+               err = -EINVAL;
+               goto out;
+       }
+       blen = ALIGN(nb, 4);
+       packet = kzalloc(sizeof(struct if_spi_packet) + blen, GFP_ATOMIC);
+       if (!packet) {
+               err = -ENOMEM;
+               goto out;
+       }
+       packet->blen = blen;
+       memcpy(packet->buffer, buf, nb);
+       memset(packet->buffer + nb, 0, blen - nb);
+
+       switch (type) {
+       case MVMS_CMD:
+               priv->dnld_sent = DNLD_CMD_SENT;
+               spin_lock_irqsave(&card->buffer_lock, flags);
+               list_add_tail(&packet->list, &card->cmd_packet_list);
+               spin_unlock_irqrestore(&card->buffer_lock, flags);
+               break;
+       case MVMS_DAT:
+               priv->dnld_sent = DNLD_DATA_SENT;
+               spin_lock_irqsave(&card->buffer_lock, flags);
+               list_add_tail(&packet->list, &card->data_packet_list);
+               spin_unlock_irqrestore(&card->buffer_lock, flags);
+               break;
+       default:
+               kfree(packet);
+               netdev_err(priv->dev, "can't transfer buffer of type %d\n",
+                          type);
+               err = -EINVAL;
+               break;
+       }
+
+       /* Queue spi xfer work */
+       queue_work(card->workqueue, &card->packet_work);
+out:
+       lbs_deb_leave_args(LBS_DEB_SPI, "err=%d", err);
+       return err;
+}
+
+/*
+ * Host Interrupts
+ *
+ * Service incoming interrupts from the WLAN device. We can't sleep here, so
+ * don't try to talk on the SPI bus, just queue the SPI xfer work.
+ */
+static irqreturn_t if_spi_host_interrupt(int irq, void *dev_id)
+{
+       struct if_spi_card *card = dev_id;
+
+       queue_work(card->workqueue, &card->packet_work);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * SPI callbacks
+ */
+
+static int if_spi_init_card(struct if_spi_card *card)
+{
+       struct lbs_private *priv = card->priv;
+       int err, i;
+       u32 scratch;
+       const struct firmware *helper = NULL;
+       const struct firmware *mainfw = NULL;
+
+       lbs_deb_enter(LBS_DEB_SPI);
+
+       err = spu_init(card, card->pdata->use_dummy_writes);
+       if (err)
+               goto out;
+       err = spu_get_chip_revision(card, &card->card_id, &card->card_rev);
+       if (err)
+               goto out;
+
+       err = spu_read_u32(card, IF_SPI_SCRATCH_4_REG, &scratch);
+       if (err)
+               goto out;
+       if (scratch == SUCCESSFUL_FW_DOWNLOAD_MAGIC)
+               lbs_deb_spi("Firmware is already loaded for "
+                           "Marvell WLAN 802.11 adapter\n");
+       else {
+               /* Check if we support this card */
+               for (i = 0; i < ARRAY_SIZE(fw_table); i++) {
+                       if (card->card_id == fw_table[i].model)
+                               break;
+               }
+               if (i == ARRAY_SIZE(fw_table)) {
+                       netdev_err(priv->dev, "Unsupported chip_id: 0x%02x\n",
+                                  card->card_id);
+                       err = -ENODEV;
+                       goto out;
+               }
+
+               err = lbs_get_firmware(&card->spi->dev, card->card_id,
+                                       &fw_table[0], &helper, &mainfw);
+               if (err) {
+                       netdev_err(priv->dev, "failed to find firmware (%d)\n",
+                                  err);
+                       goto out;
+               }
+
+               lbs_deb_spi("Initializing FW for Marvell WLAN 802.11 adapter "
+                               "(chip_id = 0x%04x, chip_rev = 0x%02x) "
+                               "attached to SPI bus_num %d, chip_select %d. "
+                               "spi->max_speed_hz=%d\n",
+                               card->card_id, card->card_rev,
+                               card->spi->master->bus_num,
+                               card->spi->chip_select,
+                               card->spi->max_speed_hz);
+               err = if_spi_prog_helper_firmware(card, helper);
+               if (err)
+                       goto out;
+               err = if_spi_prog_main_firmware(card, mainfw);
+               if (err)
+                       goto out;
+               lbs_deb_spi("loaded FW for Marvell WLAN 802.11 adapter\n");
+       }
+
+       err = spu_set_interrupt_mode(card, 0, 1);
+       if (err)
+               goto out;
+
+out:
+       lbs_deb_leave_args(LBS_DEB_SPI, "err %d\n", err);
+       return err;
+}
+
+static void if_spi_resume_worker(struct work_struct *work)
+{
+       struct if_spi_card *card;
+
+       card = container_of(work, struct if_spi_card, resume_work);
+
+       if (card->suspended) {
+               if (card->pdata->setup)
+                       card->pdata->setup(card->spi);
+
+               /* Init card ... */
+               if_spi_init_card(card);
+
+               enable_irq(card->spi->irq);
+
+               /* And resume it ... */
+               lbs_resume(card->priv);
+
+               card->suspended = 0;
+       }
+}
+
+static int if_spi_probe(struct spi_device *spi)
+{
+       struct if_spi_card *card;
+       struct lbs_private *priv = NULL;
+       struct libertas_spi_platform_data *pdata = dev_get_platdata(&spi->dev);
+       int err = 0;
+
+       lbs_deb_enter(LBS_DEB_SPI);
+
+       if (!pdata) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       if (pdata->setup) {
+               err = pdata->setup(spi);
+               if (err)
+                       goto out;
+       }
+
+       /* Allocate card structure to represent this specific device */
+       card = kzalloc(sizeof(struct if_spi_card), GFP_KERNEL);
+       if (!card) {
+               err = -ENOMEM;
+               goto teardown;
+       }
+       spi_set_drvdata(spi, card);
+       card->pdata = pdata;
+       card->spi = spi;
+       card->prev_xfer_time = jiffies;
+
+       INIT_LIST_HEAD(&card->cmd_packet_list);
+       INIT_LIST_HEAD(&card->data_packet_list);
+       spin_lock_init(&card->buffer_lock);
+
+       /* Initialize the SPI Interface Unit */
+
+       /* Firmware load */
+       err = if_spi_init_card(card);
+       if (err)
+               goto free_card;
+
+       /*
+        * Register our card with libertas.
+        * This will call alloc_etherdev.
+        */
+       priv = lbs_add_card(card, &spi->dev);
+       if (!priv) {
+               err = -ENOMEM;
+               goto free_card;
+       }
+       card->priv = priv;
+       priv->setup_fw_on_resume = 1;
+       priv->card = card;
+       priv->hw_host_to_card = if_spi_host_to_card;
+       priv->enter_deep_sleep = NULL;
+       priv->exit_deep_sleep = NULL;
+       priv->reset_deep_sleep_wakeup = NULL;
+       priv->fw_ready = 1;
+
+       /* Initialize interrupt handling stuff. */
+       card->workqueue = create_workqueue("libertas_spi");
+       INIT_WORK(&card->packet_work, if_spi_host_to_card_worker);
+       INIT_WORK(&card->resume_work, if_spi_resume_worker);
+
+       err = request_irq(spi->irq, if_spi_host_interrupt,
+                       IRQF_TRIGGER_FALLING, "libertas_spi", card);
+       if (err) {
+               pr_err("can't get host irq line-- request_irq failed\n");
+               goto terminate_workqueue;
+       }
+
+       /*
+        * Start the card.
+        * This will call register_netdev, and we'll start
+        * getting interrupts...
+        */
+       err = lbs_start_card(priv);
+       if (err)
+               goto release_irq;
+
+       lbs_deb_spi("Finished initializing WLAN module.\n");
+
+       /* successful exit */
+       goto out;
+
+release_irq:
+       free_irq(spi->irq, card);
+terminate_workqueue:
+       flush_workqueue(card->workqueue);
+       destroy_workqueue(card->workqueue);
+       lbs_remove_card(priv); /* will call free_netdev */
+free_card:
+       free_if_spi_card(card);
+teardown:
+       if (pdata->teardown)
+               pdata->teardown(spi);
+out:
+       lbs_deb_leave_args(LBS_DEB_SPI, "err %d\n", err);
+       return err;
+}
+
+static int libertas_spi_remove(struct spi_device *spi)
+{
+       struct if_spi_card *card = spi_get_drvdata(spi);
+       struct lbs_private *priv = card->priv;
+
+       lbs_deb_spi("libertas_spi_remove\n");
+       lbs_deb_enter(LBS_DEB_SPI);
+
+       cancel_work_sync(&card->resume_work);
+
+       lbs_stop_card(priv);
+       lbs_remove_card(priv); /* will call free_netdev */
+
+       free_irq(spi->irq, card);
+       flush_workqueue(card->workqueue);
+       destroy_workqueue(card->workqueue);
+       if (card->pdata->teardown)
+               card->pdata->teardown(spi);
+       free_if_spi_card(card);
+       lbs_deb_leave(LBS_DEB_SPI);
+       return 0;
+}
+
+static int if_spi_suspend(struct device *dev)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       struct if_spi_card *card = spi_get_drvdata(spi);
+
+       if (!card->suspended) {
+               lbs_suspend(card->priv);
+               flush_workqueue(card->workqueue);
+               disable_irq(spi->irq);
+
+               if (card->pdata->teardown)
+                       card->pdata->teardown(spi);
+               card->suspended = 1;
+       }
+
+       return 0;
+}
+
+static int if_spi_resume(struct device *dev)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       struct if_spi_card *card = spi_get_drvdata(spi);
+
+       /* Schedule delayed work */
+       schedule_work(&card->resume_work);
+
+       return 0;
+}
+
+static const struct dev_pm_ops if_spi_pm_ops = {
+       .suspend        = if_spi_suspend,
+       .resume         = if_spi_resume,
+};
+
+static struct spi_driver libertas_spi_driver = {
+       .probe  = if_spi_probe,
+       .remove = libertas_spi_remove,
+       .driver = {
+               .name   = "libertas_spi",
+               .pm     = &if_spi_pm_ops,
+       },
+};
+
+/*
+ * Module functions
+ */
+
+static int __init if_spi_init_module(void)
+{
+       int ret = 0;
+       lbs_deb_enter(LBS_DEB_SPI);
+       printk(KERN_INFO "libertas_spi: Libertas SPI driver\n");
+       ret = spi_register_driver(&libertas_spi_driver);
+       lbs_deb_leave(LBS_DEB_SPI);
+       return ret;
+}
+
+static void __exit if_spi_exit_module(void)
+{
+       lbs_deb_enter(LBS_DEB_SPI);
+       spi_unregister_driver(&libertas_spi_driver);
+       lbs_deb_leave(LBS_DEB_SPI);
+}
+
+module_init(if_spi_init_module);
+module_exit(if_spi_exit_module);
+
+MODULE_DESCRIPTION("Libertas SPI WLAN Driver");
+MODULE_AUTHOR("Andrey Yurovsky <andrey@cozybit.com>, "
+             "Colin McCabe <colin@cozybit.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:libertas_spi");
diff --git a/drivers/net/wireless/marvell/libertas/if_spi.h b/drivers/net/wireless/marvell/libertas/if_spi.h
new file mode 100644 (file)
index 0000000..e450e31
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ *     linux/drivers/net/wireless/libertas/if_spi.c
+ *
+ *     Driver for Marvell SPI WLAN cards.
+ *
+ *     Copyright 2008 Analog Devices Inc.
+ *
+ *     Authors:
+ *     Andrey Yurovsky <andrey@cozybit.com>
+ *     Colin McCabe <colin@cozybit.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#ifndef _LBS_IF_SPI_H_
+#define _LBS_IF_SPI_H_
+
+#define IPFIELD_ALIGN_OFFSET 2
+#define IF_SPI_CMD_BUF_SIZE 2400
+
+/***************** Firmware *****************/
+
+#define IF_SPI_FW_NAME_MAX 30
+
+#define MAX_MAIN_FW_LOAD_CRC_ERR 10
+
+/* Chunk size when loading the helper firmware */
+#define HELPER_FW_LOAD_CHUNK_SZ 64
+
+/* Value to write to indicate end of helper firmware dnld */
+#define FIRMWARE_DNLD_OK 0x0000
+
+/* Value to check once the main firmware is downloaded */
+#define SUCCESSFUL_FW_DOWNLOAD_MAGIC 0x88888888
+
+/***************** SPI Interface Unit *****************/
+/* Masks used in SPI register read/write operations */
+#define IF_SPI_READ_OPERATION_MASK 0x0
+#define IF_SPI_WRITE_OPERATION_MASK 0x8000
+
+/* SPI register offsets. 4-byte aligned. */
+#define IF_SPI_DEVICEID_CTRL_REG 0x00  /* DeviceID controller reg */
+#define IF_SPI_IO_READBASE_REG 0x04    /* Read I/O base reg */
+#define IF_SPI_IO_WRITEBASE_REG 0x08   /* Write I/O base reg */
+#define IF_SPI_IO_RDWRPORT_REG 0x0C    /* Read/Write I/O port reg */
+
+#define IF_SPI_CMD_READBASE_REG 0x10   /* Read command base reg */
+#define IF_SPI_CMD_WRITEBASE_REG 0x14  /* Write command base reg */
+#define IF_SPI_CMD_RDWRPORT_REG 0x18   /* Read/Write command port reg */
+
+#define IF_SPI_DATA_READBASE_REG 0x1C  /* Read data base reg */
+#define IF_SPI_DATA_WRITEBASE_REG 0x20 /* Write data base reg */
+#define IF_SPI_DATA_RDWRPORT_REG 0x24  /* Read/Write data port reg */
+
+#define IF_SPI_SCRATCH_1_REG 0x28      /* Scratch reg 1 */
+#define IF_SPI_SCRATCH_2_REG 0x2C      /* Scratch reg 2 */
+#define IF_SPI_SCRATCH_3_REG 0x30      /* Scratch reg 3 */
+#define IF_SPI_SCRATCH_4_REG 0x34      /* Scratch reg 4 */
+
+#define IF_SPI_TX_FRAME_SEQ_NUM_REG 0x38 /* Tx frame sequence number reg */
+#define IF_SPI_TX_FRAME_STATUS_REG 0x3C        /* Tx frame status reg */
+
+#define IF_SPI_HOST_INT_CTRL_REG 0x40  /* Host interrupt controller reg */
+
+#define IF_SPI_CARD_INT_CAUSE_REG 0x44 /* Card interrupt cause reg */
+#define IF_SPI_CARD_INT_STATUS_REG 0x48 /* Card interrupt status reg */
+#define IF_SPI_CARD_INT_EVENT_MASK_REG 0x4C /* Card interrupt event mask */
+#define IF_SPI_CARD_INT_STATUS_MASK_REG        0x50 /* Card interrupt status mask */
+
+#define IF_SPI_CARD_INT_RESET_SELECT_REG 0x54 /* Card interrupt reset select */
+
+#define IF_SPI_HOST_INT_CAUSE_REG 0x58 /* Host interrupt cause reg */
+#define IF_SPI_HOST_INT_STATUS_REG 0x5C        /* Host interrupt status reg */
+#define IF_SPI_HOST_INT_EVENT_MASK_REG 0x60 /* Host interrupt event mask */
+#define IF_SPI_HOST_INT_STATUS_MASK_REG        0x64 /* Host interrupt status mask */
+#define IF_SPI_HOST_INT_RESET_SELECT_REG 0x68 /* Host interrupt reset select */
+
+#define IF_SPI_DELAY_READ_REG 0x6C     /* Delay read reg */
+#define IF_SPI_SPU_BUS_MODE_REG 0x70   /* SPU BUS mode reg */
+
+/***************** IF_SPI_DEVICEID_CTRL_REG *****************/
+#define IF_SPI_DEVICEID_CTRL_REG_TO_CARD_ID(dc) ((dc & 0xffff0000)>>16)
+#define IF_SPI_DEVICEID_CTRL_REG_TO_CARD_REV(dc) (dc & 0x000000ff)
+
+/***************** IF_SPI_HOST_INT_CTRL_REG *****************/
+/* Host Interrupt Control bit : Wake up */
+#define IF_SPI_HICT_WAKE_UP                            (1<<0)
+/* Host Interrupt Control bit : WLAN ready */
+#define IF_SPI_HICT_WLAN_READY                         (1<<1)
+/*#define IF_SPI_HICT_FIFO_FIRST_HALF_EMPTY            (1<<2) */
+/*#define IF_SPI_HICT_FIFO_SECOND_HALF_EMPTY           (1<<3) */
+/*#define IF_SPI_HICT_IRQSRC_WLAN                      (1<<4) */
+/* Host Interrupt Control bit : Tx auto download */
+#define IF_SPI_HICT_TX_DOWNLOAD_OVER_AUTO              (1<<5)
+/* Host Interrupt Control bit : Rx auto upload */
+#define IF_SPI_HICT_RX_UPLOAD_OVER_AUTO                        (1<<6)
+/* Host Interrupt Control bit : Command auto download */
+#define IF_SPI_HICT_CMD_DOWNLOAD_OVER_AUTO             (1<<7)
+/* Host Interrupt Control bit : Command auto upload */
+#define IF_SPI_HICT_CMD_UPLOAD_OVER_AUTO               (1<<8)
+
+/***************** IF_SPI_CARD_INT_CAUSE_REG *****************/
+/* Card Interrupt Case bit : Tx download over */
+#define IF_SPI_CIC_TX_DOWNLOAD_OVER                    (1<<0)
+/* Card Interrupt Case bit : Rx upload over */
+#define IF_SPI_CIC_RX_UPLOAD_OVER                      (1<<1)
+/* Card Interrupt Case bit : Command download over */
+#define IF_SPI_CIC_CMD_DOWNLOAD_OVER                   (1<<2)
+/* Card Interrupt Case bit : Host event */
+#define IF_SPI_CIC_HOST_EVENT                          (1<<3)
+/* Card Interrupt Case bit : Command upload over */
+#define IF_SPI_CIC_CMD_UPLOAD_OVER                     (1<<4)
+/* Card Interrupt Case bit : Power down */
+#define IF_SPI_CIC_POWER_DOWN                          (1<<5)
+
+/***************** IF_SPI_CARD_INT_STATUS_REG *****************/
+#define IF_SPI_CIS_TX_DOWNLOAD_OVER                    (1<<0)
+#define IF_SPI_CIS_RX_UPLOAD_OVER                      (1<<1)
+#define IF_SPI_CIS_CMD_DOWNLOAD_OVER                   (1<<2)
+#define IF_SPI_CIS_HOST_EVENT                          (1<<3)
+#define IF_SPI_CIS_CMD_UPLOAD_OVER                     (1<<4)
+#define IF_SPI_CIS_POWER_DOWN                          (1<<5)
+
+/***************** IF_SPI_HOST_INT_CAUSE_REG *****************/
+#define IF_SPI_HICU_TX_DOWNLOAD_RDY                    (1<<0)
+#define IF_SPI_HICU_RX_UPLOAD_RDY                      (1<<1)
+#define IF_SPI_HICU_CMD_DOWNLOAD_RDY                   (1<<2)
+#define IF_SPI_HICU_CARD_EVENT                         (1<<3)
+#define IF_SPI_HICU_CMD_UPLOAD_RDY                     (1<<4)
+#define IF_SPI_HICU_IO_WR_FIFO_OVERFLOW                        (1<<5)
+#define IF_SPI_HICU_IO_RD_FIFO_UNDERFLOW               (1<<6)
+#define IF_SPI_HICU_DATA_WR_FIFO_OVERFLOW              (1<<7)
+#define IF_SPI_HICU_DATA_RD_FIFO_UNDERFLOW             (1<<8)
+#define IF_SPI_HICU_CMD_WR_FIFO_OVERFLOW               (1<<9)
+#define IF_SPI_HICU_CMD_RD_FIFO_UNDERFLOW              (1<<10)
+
+/***************** IF_SPI_HOST_INT_STATUS_REG *****************/
+/* Host Interrupt Status bit : Tx download ready */
+#define IF_SPI_HIST_TX_DOWNLOAD_RDY                    (1<<0)
+/* Host Interrupt Status bit : Rx upload ready */
+#define IF_SPI_HIST_RX_UPLOAD_RDY                      (1<<1)
+/* Host Interrupt Status bit : Command download ready */
+#define IF_SPI_HIST_CMD_DOWNLOAD_RDY                   (1<<2)
+/* Host Interrupt Status bit : Card event */
+#define IF_SPI_HIST_CARD_EVENT                         (1<<3)
+/* Host Interrupt Status bit : Command upload ready */
+#define IF_SPI_HIST_CMD_UPLOAD_RDY                     (1<<4)
+/* Host Interrupt Status bit : I/O write FIFO overflow */
+#define IF_SPI_HIST_IO_WR_FIFO_OVERFLOW                        (1<<5)
+/* Host Interrupt Status bit : I/O read FIFO underflow */
+#define IF_SPI_HIST_IO_RD_FIFO_UNDRFLOW                        (1<<6)
+/* Host Interrupt Status bit : Data write FIFO overflow */
+#define IF_SPI_HIST_DATA_WR_FIFO_OVERFLOW              (1<<7)
+/* Host Interrupt Status bit : Data read FIFO underflow */
+#define IF_SPI_HIST_DATA_RD_FIFO_UNDERFLOW             (1<<8)
+/* Host Interrupt Status bit : Command write FIFO overflow */
+#define IF_SPI_HIST_CMD_WR_FIFO_OVERFLOW               (1<<9)
+/* Host Interrupt Status bit : Command read FIFO underflow */
+#define IF_SPI_HIST_CMD_RD_FIFO_UNDERFLOW              (1<<10)
+
+/***************** IF_SPI_HOST_INT_STATUS_MASK_REG *****************/
+/* Host Interrupt Status Mask bit : Tx download ready */
+#define IF_SPI_HISM_TX_DOWNLOAD_RDY                    (1<<0)
+/* Host Interrupt Status Mask bit : Rx upload ready */
+#define IF_SPI_HISM_RX_UPLOAD_RDY                      (1<<1)
+/* Host Interrupt Status Mask bit : Command download ready */
+#define IF_SPI_HISM_CMD_DOWNLOAD_RDY                   (1<<2)
+/* Host Interrupt Status Mask bit : Card event */
+#define IF_SPI_HISM_CARDEVENT                          (1<<3)
+/* Host Interrupt Status Mask bit : Command upload ready */
+#define IF_SPI_HISM_CMD_UPLOAD_RDY                     (1<<4)
+/* Host Interrupt Status Mask bit : I/O write FIFO overflow */
+#define IF_SPI_HISM_IO_WR_FIFO_OVERFLOW                        (1<<5)
+/* Host Interrupt Status Mask bit : I/O read FIFO underflow */
+#define IF_SPI_HISM_IO_RD_FIFO_UNDERFLOW               (1<<6)
+/* Host Interrupt Status Mask bit : Data write FIFO overflow */
+#define IF_SPI_HISM_DATA_WR_FIFO_OVERFLOW              (1<<7)
+/* Host Interrupt Status Mask bit : Data write FIFO underflow */
+#define IF_SPI_HISM_DATA_RD_FIFO_UNDERFLOW             (1<<8)
+/* Host Interrupt Status Mask bit : Command write FIFO overflow */
+#define IF_SPI_HISM_CMD_WR_FIFO_OVERFLOW               (1<<9)
+/* Host Interrupt Status Mask bit : Command write FIFO underflow */
+#define IF_SPI_HISM_CMD_RD_FIFO_UNDERFLOW              (1<<10)
+
+/***************** IF_SPI_SPU_BUS_MODE_REG *****************/
+/* SCK edge on which the WLAN module outputs data on MISO */
+#define IF_SPI_BUS_MODE_SPI_CLOCK_PHASE_FALLING 0x8
+#define IF_SPI_BUS_MODE_SPI_CLOCK_PHASE_RISING 0x0
+
+/* In a SPU read operation, there is a delay between writing the SPU
+ * register name and getting back data from the WLAN module.
+ * This can be specified in terms of nanoseconds or in terms of dummy
+ * clock cycles which the master must output before receiving a response. */
+#define IF_SPI_BUS_MODE_DELAY_METHOD_DUMMY_CLOCK 0x4
+#define IF_SPI_BUS_MODE_DELAY_METHOD_TIMED 0x0
+
+/* Some different modes of SPI operation */
+#define IF_SPI_BUS_MODE_8_BIT_ADDRESS_16_BIT_DATA 0x00
+#define IF_SPI_BUS_MODE_8_BIT_ADDRESS_32_BIT_DATA 0x01
+#define IF_SPI_BUS_MODE_16_BIT_ADDRESS_16_BIT_DATA 0x02
+#define IF_SPI_BUS_MODE_16_BIT_ADDRESS_32_BIT_DATA 0x03
+
+#endif
diff --git a/drivers/net/wireless/marvell/libertas/if_usb.c b/drivers/net/wireless/marvell/libertas/if_usb.c
new file mode 100644 (file)
index 0000000..dff08a2
--- /dev/null
@@ -0,0 +1,1018 @@
+/*
+ * This file contains functions used in USB interface module.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/firmware.h>
+#include <linux/netdevice.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/olpc-ec.h>
+
+#ifdef CONFIG_OLPC
+#include <asm/olpc.h>
+#endif
+
+#define DRV_NAME "usb8xxx"
+
+#include "host.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "cmd.h"
+#include "if_usb.h"
+
+#define INSANEDEBUG    0
+#define lbs_deb_usb2(...) do { if (INSANEDEBUG) lbs_deb_usbd(__VA_ARGS__); } while (0)
+
+#define MESSAGE_HEADER_LEN     4
+
+MODULE_FIRMWARE("libertas/usb8388_v9.bin");
+MODULE_FIRMWARE("libertas/usb8388_v5.bin");
+MODULE_FIRMWARE("libertas/usb8388.bin");
+MODULE_FIRMWARE("libertas/usb8682.bin");
+MODULE_FIRMWARE("usb8388.bin");
+
+enum {
+       MODEL_UNKNOWN = 0x0,
+       MODEL_8388 = 0x1,
+       MODEL_8682 = 0x2
+};
+
+/* table of firmware file names */
+static const struct lbs_fw_table fw_table[] = {
+       { MODEL_8388, "libertas/usb8388_olpc.bin", NULL },
+       { MODEL_8388, "libertas/usb8388_v9.bin", NULL },
+       { MODEL_8388, "libertas/usb8388_v5.bin", NULL },
+       { MODEL_8388, "libertas/usb8388.bin", NULL },
+       { MODEL_8388, "usb8388.bin", NULL },
+       { MODEL_8682, "libertas/usb8682.bin", NULL }
+};
+
+static struct usb_device_id if_usb_table[] = {
+       /* Enter the device signature inside */
+       { USB_DEVICE(0x1286, 0x2001), .driver_info = MODEL_8388 },
+       { USB_DEVICE(0x05a3, 0x8388), .driver_info = MODEL_8388 },
+       {}      /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, if_usb_table);
+
+static void if_usb_receive(struct urb *urb);
+static void if_usb_receive_fwload(struct urb *urb);
+static void if_usb_prog_firmware(struct lbs_private *priv, int ret,
+                                const struct firmware *fw,
+                                const struct firmware *unused);
+static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
+                              uint8_t *payload, uint16_t nb);
+static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload,
+                       uint16_t nb);
+static void if_usb_free(struct if_usb_card *cardp);
+static int if_usb_submit_rx_urb(struct if_usb_card *cardp);
+static int if_usb_reset_device(struct if_usb_card *cardp);
+
+/**
+ * if_usb_write_bulk_callback - callback function to handle the status
+ * of the URB
+ * @urb:       pointer to &urb structure
+ * returns:    N/A
+ */
+static void if_usb_write_bulk_callback(struct urb *urb)
+{
+       struct if_usb_card *cardp = (struct if_usb_card *) urb->context;
+
+       /* handle the transmission complete validations */
+
+       if (urb->status == 0) {
+               struct lbs_private *priv = cardp->priv;
+
+               lbs_deb_usb2(&urb->dev->dev, "URB status is successful\n");
+               lbs_deb_usb2(&urb->dev->dev, "Actual length transmitted %d\n",
+                            urb->actual_length);
+
+               /* Boot commands such as UPDATE_FW and UPDATE_BOOT2 are not
+                * passed up to the lbs level.
+                */
+               if (priv && priv->dnld_sent != DNLD_BOOTCMD_SENT)
+                       lbs_host_to_card_done(priv);
+       } else {
+               /* print the failure status number for debug */
+               pr_info("URB in failure status: %d\n", urb->status);
+       }
+}
+
+/**
+ * if_usb_free - free tx/rx urb, skb and rx buffer
+ * @cardp:     pointer to &if_usb_card
+ * returns:    N/A
+ */
+static void if_usb_free(struct if_usb_card *cardp)
+{
+       lbs_deb_enter(LBS_DEB_USB);
+
+       /* Unlink tx & rx urb */
+       usb_kill_urb(cardp->tx_urb);
+       usb_kill_urb(cardp->rx_urb);
+
+       usb_free_urb(cardp->tx_urb);
+       cardp->tx_urb = NULL;
+
+       usb_free_urb(cardp->rx_urb);
+       cardp->rx_urb = NULL;
+
+       kfree(cardp->ep_out_buf);
+       cardp->ep_out_buf = NULL;
+
+       lbs_deb_leave(LBS_DEB_USB);
+}
+
+static void if_usb_setup_firmware(struct lbs_private *priv)
+{
+       struct if_usb_card *cardp = priv->card;
+       struct cmd_ds_set_boot2_ver b2_cmd;
+       struct cmd_ds_802_11_fw_wake_method wake_method;
+
+       b2_cmd.hdr.size = cpu_to_le16(sizeof(b2_cmd));
+       b2_cmd.action = 0;
+       b2_cmd.version = cardp->boot2_version;
+
+       if (lbs_cmd_with_response(priv, CMD_SET_BOOT2_VER, &b2_cmd))
+               lbs_deb_usb("Setting boot2 version failed\n");
+
+       priv->wol_gpio = 2; /* Wake via GPIO2... */
+       priv->wol_gap = 20; /* ... after 20ms    */
+       lbs_host_sleep_cfg(priv, EHS_WAKE_ON_UNICAST_DATA,
+                       (struct wol_config *) NULL);
+
+       wake_method.hdr.size = cpu_to_le16(sizeof(wake_method));
+       wake_method.action = cpu_to_le16(CMD_ACT_GET);
+       if (lbs_cmd_with_response(priv, CMD_802_11_FW_WAKE_METHOD, &wake_method)) {
+               netdev_info(priv->dev, "Firmware does not seem to support PS mode\n");
+               priv->fwcapinfo &= ~FW_CAPINFO_PS;
+       } else {
+               if (le16_to_cpu(wake_method.method) == CMD_WAKE_METHOD_COMMAND_INT) {
+                       lbs_deb_usb("Firmware seems to support PS with wake-via-command\n");
+               } else {
+                       /* The versions which boot up this way don't seem to
+                          work even if we set it to the command interrupt */
+                       priv->fwcapinfo &= ~FW_CAPINFO_PS;
+                       netdev_info(priv->dev,
+                                   "Firmware doesn't wake via command interrupt; disabling PS mode\n");
+               }
+       }
+}
+
+static void if_usb_fw_timeo(unsigned long priv)
+{
+       struct if_usb_card *cardp = (void *)priv;
+
+       if (cardp->fwdnldover) {
+               lbs_deb_usb("Download complete, no event. Assuming success\n");
+       } else {
+               pr_err("Download timed out\n");
+               cardp->surprise_removed = 1;
+       }
+       wake_up(&cardp->fw_wq);
+}
+
+#ifdef CONFIG_OLPC
+static void if_usb_reset_olpc_card(struct lbs_private *priv)
+{
+       printk(KERN_CRIT "Resetting OLPC wireless via EC...\n");
+       olpc_ec_cmd(0x25, NULL, 0, NULL, 0);
+}
+#endif
+
+/**
+ * if_usb_probe - sets the configuration values
+ * @intf:      &usb_interface pointer
+ * @id:        pointer to usb_device_id
+ * returns:    0 on success, error code on failure
+ */
+static int if_usb_probe(struct usb_interface *intf,
+                       const struct usb_device_id *id)
+{
+       struct usb_device *udev;
+       struct usb_host_interface *iface_desc;
+       struct usb_endpoint_descriptor *endpoint;
+       struct lbs_private *priv;
+       struct if_usb_card *cardp;
+       int r = -ENOMEM;
+       int i;
+
+       udev = interface_to_usbdev(intf);
+
+       cardp = kzalloc(sizeof(struct if_usb_card), GFP_KERNEL);
+       if (!cardp)
+               goto error;
+
+       setup_timer(&cardp->fw_timeout, if_usb_fw_timeo, (unsigned long)cardp);
+       init_waitqueue_head(&cardp->fw_wq);
+
+       cardp->udev = udev;
+       cardp->model = (uint32_t) id->driver_info;
+       iface_desc = intf->cur_altsetting;
+
+       lbs_deb_usbd(&udev->dev, "bcdUSB = 0x%X bDeviceClass = 0x%X"
+                    " bDeviceSubClass = 0x%X, bDeviceProtocol = 0x%X\n",
+                    le16_to_cpu(udev->descriptor.bcdUSB),
+                    udev->descriptor.bDeviceClass,
+                    udev->descriptor.bDeviceSubClass,
+                    udev->descriptor.bDeviceProtocol);
+
+       for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+               endpoint = &iface_desc->endpoint[i].desc;
+               if (usb_endpoint_is_bulk_in(endpoint)) {
+                       cardp->ep_in_size = le16_to_cpu(endpoint->wMaxPacketSize);
+                       cardp->ep_in = usb_endpoint_num(endpoint);
+
+                       lbs_deb_usbd(&udev->dev, "in_endpoint = %d\n", cardp->ep_in);
+                       lbs_deb_usbd(&udev->dev, "Bulk in size is %d\n", cardp->ep_in_size);
+
+               } else if (usb_endpoint_is_bulk_out(endpoint)) {
+                       cardp->ep_out_size = le16_to_cpu(endpoint->wMaxPacketSize);
+                       cardp->ep_out = usb_endpoint_num(endpoint);
+
+                       lbs_deb_usbd(&udev->dev, "out_endpoint = %d\n", cardp->ep_out);
+                       lbs_deb_usbd(&udev->dev, "Bulk out size is %d\n", cardp->ep_out_size);
+               }
+       }
+       if (!cardp->ep_out_size || !cardp->ep_in_size) {
+               lbs_deb_usbd(&udev->dev, "Endpoints not found\n");
+               goto dealloc;
+       }
+       if (!(cardp->rx_urb = usb_alloc_urb(0, GFP_KERNEL))) {
+               lbs_deb_usbd(&udev->dev, "Rx URB allocation failed\n");
+               goto dealloc;
+       }
+       if (!(cardp->tx_urb = usb_alloc_urb(0, GFP_KERNEL))) {
+               lbs_deb_usbd(&udev->dev, "Tx URB allocation failed\n");
+               goto dealloc;
+       }
+       cardp->ep_out_buf = kmalloc(MRVDRV_ETH_TX_PACKET_BUFFER_SIZE, GFP_KERNEL);
+       if (!cardp->ep_out_buf) {
+               lbs_deb_usbd(&udev->dev, "Could not allocate buffer\n");
+               goto dealloc;
+       }
+
+       if (!(priv = lbs_add_card(cardp, &intf->dev)))
+               goto err_add_card;
+
+       cardp->priv = priv;
+
+       priv->hw_host_to_card = if_usb_host_to_card;
+       priv->enter_deep_sleep = NULL;
+       priv->exit_deep_sleep = NULL;
+       priv->reset_deep_sleep_wakeup = NULL;
+#ifdef CONFIG_OLPC
+       if (machine_is_olpc())
+               priv->reset_card = if_usb_reset_olpc_card;
+#endif
+
+       cardp->boot2_version = udev->descriptor.bcdDevice;
+
+       usb_get_dev(udev);
+       usb_set_intfdata(intf, cardp);
+
+       r = lbs_get_firmware_async(priv, &udev->dev, cardp->model,
+                                  fw_table, if_usb_prog_firmware);
+       if (r)
+               goto err_get_fw;
+
+       return 0;
+
+err_get_fw:
+       lbs_remove_card(priv);
+err_add_card:
+       if_usb_reset_device(cardp);
+dealloc:
+       if_usb_free(cardp);
+
+error:
+       return r;
+}
+
+/**
+ * if_usb_disconnect - free resource and cleanup
+ * @intf:      USB interface structure
+ * returns:    N/A
+ */
+static void if_usb_disconnect(struct usb_interface *intf)
+{
+       struct if_usb_card *cardp = usb_get_intfdata(intf);
+       struct lbs_private *priv = cardp->priv;
+
+       lbs_deb_enter(LBS_DEB_MAIN);
+
+       cardp->surprise_removed = 1;
+
+       if (priv) {
+               lbs_stop_card(priv);
+               lbs_remove_card(priv);
+       }
+
+       /* Unlink and free urb */
+       if_usb_free(cardp);
+
+       usb_set_intfdata(intf, NULL);
+       usb_put_dev(interface_to_usbdev(intf));
+
+       lbs_deb_leave(LBS_DEB_MAIN);
+}
+
+/**
+ * if_usb_send_fw_pkt - download FW
+ * @cardp:     pointer to &struct if_usb_card
+ * returns:    0
+ */
+static int if_usb_send_fw_pkt(struct if_usb_card *cardp)
+{
+       struct fwdata *fwdata = cardp->ep_out_buf;
+       const uint8_t *firmware = cardp->fw->data;
+
+       /* If we got a CRC failure on the last block, back
+          up and retry it */
+       if (!cardp->CRC_OK) {
+               cardp->totalbytes = cardp->fwlastblksent;
+               cardp->fwseqnum--;
+       }
+
+       lbs_deb_usb2(&cardp->udev->dev, "totalbytes = %d\n",
+                    cardp->totalbytes);
+
+       /* struct fwdata (which we sent to the card) has an
+          extra __le32 field in between the header and the data,
+          which is not in the struct fwheader in the actual
+          firmware binary. Insert the seqnum in the middle... */
+       memcpy(&fwdata->hdr, &firmware[cardp->totalbytes],
+              sizeof(struct fwheader));
+
+       cardp->fwlastblksent = cardp->totalbytes;
+       cardp->totalbytes += sizeof(struct fwheader);
+
+       memcpy(fwdata->data, &firmware[cardp->totalbytes],
+              le32_to_cpu(fwdata->hdr.datalength));
+
+       lbs_deb_usb2(&cardp->udev->dev, "Data length = %d\n",
+                    le32_to_cpu(fwdata->hdr.datalength));
+
+       fwdata->seqnum = cpu_to_le32(++cardp->fwseqnum);
+       cardp->totalbytes += le32_to_cpu(fwdata->hdr.datalength);
+
+       usb_tx_block(cardp, cardp->ep_out_buf, sizeof(struct fwdata) +
+                    le32_to_cpu(fwdata->hdr.datalength));
+
+       if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_DATA_TO_RECV)) {
+               lbs_deb_usb2(&cardp->udev->dev, "There are data to follow\n");
+               lbs_deb_usb2(&cardp->udev->dev, "seqnum = %d totalbytes = %d\n",
+                            cardp->fwseqnum, cardp->totalbytes);
+       } else if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK)) {
+               lbs_deb_usb2(&cardp->udev->dev, "Host has finished FW downloading\n");
+               lbs_deb_usb2(&cardp->udev->dev, "Donwloading FW JUMP BLOCK\n");
+
+               cardp->fwfinalblk = 1;
+       }
+
+       lbs_deb_usb2(&cardp->udev->dev, "Firmware download done; size %d\n",
+                    cardp->totalbytes);
+
+       return 0;
+}
+
+static int if_usb_reset_device(struct if_usb_card *cardp)
+{
+       struct cmd_header *cmd = cardp->ep_out_buf + 4;
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_USB);
+
+       *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST);
+
+       cmd->command = cpu_to_le16(CMD_802_11_RESET);
+       cmd->size = cpu_to_le16(sizeof(cmd));
+       cmd->result = cpu_to_le16(0);
+       cmd->seqnum = cpu_to_le16(0x5a5a);
+       usb_tx_block(cardp, cardp->ep_out_buf, 4 + sizeof(struct cmd_header));
+
+       msleep(100);
+       ret = usb_reset_device(cardp->udev);
+       msleep(100);
+
+#ifdef CONFIG_OLPC
+       if (ret && machine_is_olpc())
+               if_usb_reset_olpc_card(NULL);
+#endif
+
+       lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret);
+
+       return ret;
+}
+
+/**
+ *  usb_tx_block - transfer the data to the device
+ *  @cardp:    pointer to &struct if_usb_card
+ *  @payload:  pointer to payload data
+ *  @nb:       data length
+ *  returns:   0 for success or negative error code
+ */
+static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, uint16_t nb)
+{
+       int ret;
+
+       /* check if device is removed */
+       if (cardp->surprise_removed) {
+               lbs_deb_usbd(&cardp->udev->dev, "Device removed\n");
+               ret = -ENODEV;
+               goto tx_ret;
+       }
+
+       usb_fill_bulk_urb(cardp->tx_urb, cardp->udev,
+                         usb_sndbulkpipe(cardp->udev,
+                                         cardp->ep_out),
+                         payload, nb, if_usb_write_bulk_callback, cardp);
+
+       cardp->tx_urb->transfer_flags |= URB_ZERO_PACKET;
+
+       if ((ret = usb_submit_urb(cardp->tx_urb, GFP_ATOMIC))) {
+               lbs_deb_usbd(&cardp->udev->dev, "usb_submit_urb failed: %d\n", ret);
+       } else {
+               lbs_deb_usb2(&cardp->udev->dev, "usb_submit_urb success\n");
+               ret = 0;
+       }
+
+tx_ret:
+       return ret;
+}
+
+static int __if_usb_submit_rx_urb(struct if_usb_card *cardp,
+                                 void (*callbackfn)(struct urb *urb))
+{
+       struct sk_buff *skb;
+       int ret = -1;
+
+       if (!(skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE))) {
+               pr_err("No free skb\n");
+               goto rx_ret;
+       }
+
+       cardp->rx_skb = skb;
+
+       /* Fill the receive configuration URB and initialise the Rx call back */
+       usb_fill_bulk_urb(cardp->rx_urb, cardp->udev,
+                         usb_rcvbulkpipe(cardp->udev, cardp->ep_in),
+                         skb->data + IPFIELD_ALIGN_OFFSET,
+                         MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn,
+                         cardp);
+
+       cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET;
+
+       lbs_deb_usb2(&cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb);
+       if ((ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC))) {
+               lbs_deb_usbd(&cardp->udev->dev, "Submit Rx URB failed: %d\n", ret);
+               kfree_skb(skb);
+               cardp->rx_skb = NULL;
+               ret = -1;
+       } else {
+               lbs_deb_usb2(&cardp->udev->dev, "Submit Rx URB success\n");
+               ret = 0;
+       }
+
+rx_ret:
+       return ret;
+}
+
+static int if_usb_submit_rx_urb_fwload(struct if_usb_card *cardp)
+{
+       return __if_usb_submit_rx_urb(cardp, &if_usb_receive_fwload);
+}
+
+static int if_usb_submit_rx_urb(struct if_usb_card *cardp)
+{
+       return __if_usb_submit_rx_urb(cardp, &if_usb_receive);
+}
+
+static void if_usb_receive_fwload(struct urb *urb)
+{
+       struct if_usb_card *cardp = urb->context;
+       struct sk_buff *skb = cardp->rx_skb;
+       struct fwsyncheader *syncfwheader;
+       struct bootcmdresp bootcmdresp;
+
+       if (urb->status) {
+               lbs_deb_usbd(&cardp->udev->dev,
+                            "URB status is failed during fw load\n");
+               kfree_skb(skb);
+               return;
+       }
+
+       if (cardp->fwdnldover) {
+               __le32 *tmp = (__le32 *)(skb->data + IPFIELD_ALIGN_OFFSET);
+
+               if (tmp[0] == cpu_to_le32(CMD_TYPE_INDICATION) &&
+                   tmp[1] == cpu_to_le32(MACREG_INT_CODE_FIRMWARE_READY)) {
+                       pr_info("Firmware ready event received\n");
+                       wake_up(&cardp->fw_wq);
+               } else {
+                       lbs_deb_usb("Waiting for confirmation; got %x %x\n",
+                                   le32_to_cpu(tmp[0]), le32_to_cpu(tmp[1]));
+                       if_usb_submit_rx_urb_fwload(cardp);
+               }
+               kfree_skb(skb);
+               return;
+       }
+       if (cardp->bootcmdresp <= 0) {
+               memcpy (&bootcmdresp, skb->data + IPFIELD_ALIGN_OFFSET,
+                       sizeof(bootcmdresp));
+
+               if (le16_to_cpu(cardp->udev->descriptor.bcdDevice) < 0x3106) {
+                       kfree_skb(skb);
+                       if_usb_submit_rx_urb_fwload(cardp);
+                       cardp->bootcmdresp = BOOT_CMD_RESP_OK;
+                       lbs_deb_usbd(&cardp->udev->dev,
+                                    "Received valid boot command response\n");
+                       return;
+               }
+               if (bootcmdresp.magic != cpu_to_le32(BOOT_CMD_MAGIC_NUMBER)) {
+                       if (bootcmdresp.magic == cpu_to_le32(CMD_TYPE_REQUEST) ||
+                           bootcmdresp.magic == cpu_to_le32(CMD_TYPE_DATA) ||
+                           bootcmdresp.magic == cpu_to_le32(CMD_TYPE_INDICATION)) {
+                               if (!cardp->bootcmdresp)
+                                       pr_info("Firmware already seems alive; resetting\n");
+                               cardp->bootcmdresp = -1;
+                       } else {
+                               pr_info("boot cmd response wrong magic number (0x%x)\n",
+                                           le32_to_cpu(bootcmdresp.magic));
+                       }
+               } else if ((bootcmdresp.cmd != BOOT_CMD_FW_BY_USB) &&
+                          (bootcmdresp.cmd != BOOT_CMD_UPDATE_FW) &&
+                          (bootcmdresp.cmd != BOOT_CMD_UPDATE_BOOT2)) {
+                       pr_info("boot cmd response cmd_tag error (%d)\n",
+                               bootcmdresp.cmd);
+               } else if (bootcmdresp.result != BOOT_CMD_RESP_OK) {
+                       pr_info("boot cmd response result error (%d)\n",
+                               bootcmdresp.result);
+               } else {
+                       cardp->bootcmdresp = 1;
+                       lbs_deb_usbd(&cardp->udev->dev,
+                                    "Received valid boot command response\n");
+               }
+               kfree_skb(skb);
+               if_usb_submit_rx_urb_fwload(cardp);
+               return;
+       }
+
+       syncfwheader = kmemdup(skb->data + IPFIELD_ALIGN_OFFSET,
+                              sizeof(struct fwsyncheader), GFP_ATOMIC);
+       if (!syncfwheader) {
+               lbs_deb_usbd(&cardp->udev->dev, "Failure to allocate syncfwheader\n");
+               kfree_skb(skb);
+               return;
+       }
+
+       if (!syncfwheader->cmd) {
+               lbs_deb_usb2(&cardp->udev->dev, "FW received Blk with correct CRC\n");
+               lbs_deb_usb2(&cardp->udev->dev, "FW received Blk seqnum = %d\n",
+                            le32_to_cpu(syncfwheader->seqnum));
+               cardp->CRC_OK = 1;
+       } else {
+               lbs_deb_usbd(&cardp->udev->dev, "FW received Blk with CRC error\n");
+               cardp->CRC_OK = 0;
+       }
+
+       kfree_skb(skb);
+
+       /* Give device 5s to either write firmware to its RAM or eeprom */
+       mod_timer(&cardp->fw_timeout, jiffies + (HZ*5));
+
+       if (cardp->fwfinalblk) {
+               cardp->fwdnldover = 1;
+               goto exit;
+       }
+
+       if_usb_send_fw_pkt(cardp);
+
+ exit:
+       if_usb_submit_rx_urb_fwload(cardp);
+
+       kfree(syncfwheader);
+}
+
+#define MRVDRV_MIN_PKT_LEN     30
+
+static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb,
+                                      struct if_usb_card *cardp,
+                                      struct lbs_private *priv)
+{
+       if (recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + MESSAGE_HEADER_LEN
+           || recvlength < MRVDRV_MIN_PKT_LEN) {
+               lbs_deb_usbd(&cardp->udev->dev, "Packet length is Invalid\n");
+               kfree_skb(skb);
+               return;
+       }
+
+       skb_reserve(skb, IPFIELD_ALIGN_OFFSET);
+       skb_put(skb, recvlength);
+       skb_pull(skb, MESSAGE_HEADER_LEN);
+
+       lbs_process_rxed_packet(priv, skb);
+}
+
+static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff,
+                                     struct sk_buff *skb,
+                                     struct if_usb_card *cardp,
+                                     struct lbs_private *priv)
+{
+       u8 i;
+
+       if (recvlength > LBS_CMD_BUFFER_SIZE) {
+               lbs_deb_usbd(&cardp->udev->dev,
+                            "The receive buffer is too large\n");
+               kfree_skb(skb);
+               return;
+       }
+
+       BUG_ON(!in_interrupt());
+
+       spin_lock(&priv->driver_lock);
+
+       i = (priv->resp_idx == 0) ? 1 : 0;
+       BUG_ON(priv->resp_len[i]);
+       priv->resp_len[i] = (recvlength - MESSAGE_HEADER_LEN);
+       memcpy(priv->resp_buf[i], recvbuff + MESSAGE_HEADER_LEN,
+               priv->resp_len[i]);
+       kfree_skb(skb);
+       lbs_notify_command_response(priv, i);
+
+       spin_unlock(&priv->driver_lock);
+
+       lbs_deb_usbd(&cardp->udev->dev,
+                   "Wake up main thread to handle cmd response\n");
+}
+
+/**
+ *  if_usb_receive - read the packet into the upload buffer,
+ *  wake up the main thread and initialise the Rx callack
+ *
+ *  @urb:      pointer to &struct urb
+ *  returns:   N/A
+ */
+static void if_usb_receive(struct urb *urb)
+{
+       struct if_usb_card *cardp = urb->context;
+       struct sk_buff *skb = cardp->rx_skb;
+       struct lbs_private *priv = cardp->priv;
+       int recvlength = urb->actual_length;
+       uint8_t *recvbuff = NULL;
+       uint32_t recvtype = 0;
+       __le32 *pkt = (__le32 *)(skb->data + IPFIELD_ALIGN_OFFSET);
+       uint32_t event;
+
+       lbs_deb_enter(LBS_DEB_USB);
+
+       if (recvlength) {
+               if (urb->status) {
+                       lbs_deb_usbd(&cardp->udev->dev, "RX URB failed: %d\n",
+                                    urb->status);
+                       kfree_skb(skb);
+                       goto setup_for_next;
+               }
+
+               recvbuff = skb->data + IPFIELD_ALIGN_OFFSET;
+               recvtype = le32_to_cpu(pkt[0]);
+               lbs_deb_usbd(&cardp->udev->dev,
+                           "Recv length = 0x%x, Recv type = 0x%X\n",
+                           recvlength, recvtype);
+       } else if (urb->status) {
+               kfree_skb(skb);
+               goto rx_exit;
+       }
+
+       switch (recvtype) {
+       case CMD_TYPE_DATA:
+               process_cmdtypedata(recvlength, skb, cardp, priv);
+               break;
+
+       case CMD_TYPE_REQUEST:
+               process_cmdrequest(recvlength, recvbuff, skb, cardp, priv);
+               break;
+
+       case CMD_TYPE_INDICATION:
+               /* Event handling */
+               event = le32_to_cpu(pkt[1]);
+               lbs_deb_usbd(&cardp->udev->dev, "**EVENT** 0x%X\n", event);
+               kfree_skb(skb);
+
+               /* Icky undocumented magic special case */
+               if (event & 0xffff0000) {
+                       u32 trycount = (event & 0xffff0000) >> 16;
+
+                       lbs_send_tx_feedback(priv, trycount);
+               } else
+                       lbs_queue_event(priv, event & 0xFF);
+               break;
+
+       default:
+               lbs_deb_usbd(&cardp->udev->dev, "Unknown command type 0x%X\n",
+                            recvtype);
+               kfree_skb(skb);
+               break;
+       }
+
+setup_for_next:
+       if_usb_submit_rx_urb(cardp);
+rx_exit:
+       lbs_deb_leave(LBS_DEB_USB);
+}
+
+/**
+ *  if_usb_host_to_card - downloads data to FW
+ *  @priv:     pointer to &struct lbs_private structure
+ *  @type:     type of data
+ *  @payload:  pointer to data buffer
+ *  @nb:       number of bytes
+ *  returns:   0 for success or negative error code
+ */
+static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
+                              uint8_t *payload, uint16_t nb)
+{
+       struct if_usb_card *cardp = priv->card;
+
+       lbs_deb_usbd(&cardp->udev->dev,"*** type = %u\n", type);
+       lbs_deb_usbd(&cardp->udev->dev,"size after = %d\n", nb);
+
+       if (type == MVMS_CMD) {
+               *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST);
+               priv->dnld_sent = DNLD_CMD_SENT;
+       } else {
+               *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_DATA);
+               priv->dnld_sent = DNLD_DATA_SENT;
+       }
+
+       memcpy((cardp->ep_out_buf + MESSAGE_HEADER_LEN), payload, nb);
+
+       return usb_tx_block(cardp, cardp->ep_out_buf, nb + MESSAGE_HEADER_LEN);
+}
+
+/**
+ *  if_usb_issue_boot_command - issues Boot command to the Boot2 code
+ *  @cardp:    pointer to &if_usb_card
+ *  @ivalue:   1:Boot from FW by USB-Download
+ *             2:Boot from FW in EEPROM
+ *  returns:   0 for success or negative error code
+ */
+static int if_usb_issue_boot_command(struct if_usb_card *cardp, int ivalue)
+{
+       struct bootcmd *bootcmd = cardp->ep_out_buf;
+
+       /* Prepare command */
+       bootcmd->magic = cpu_to_le32(BOOT_CMD_MAGIC_NUMBER);
+       bootcmd->cmd = ivalue;
+       memset(bootcmd->pad, 0, sizeof(bootcmd->pad));
+
+       /* Issue command */
+       usb_tx_block(cardp, cardp->ep_out_buf, sizeof(*bootcmd));
+
+       return 0;
+}
+
+
+/**
+ *  check_fwfile_format - check the validity of Boot2/FW image
+ *
+ *  @data:     pointer to image
+ *  @totlen:   image length
+ *  returns:     0 (good) or 1 (failure)
+ */
+static int check_fwfile_format(const uint8_t *data, uint32_t totlen)
+{
+       uint32_t bincmd, exit;
+       uint32_t blksize, offset, len;
+       int ret;
+
+       ret = 1;
+       exit = len = 0;
+
+       do {
+               struct fwheader *fwh = (void *)data;
+
+               bincmd = le32_to_cpu(fwh->dnldcmd);
+               blksize = le32_to_cpu(fwh->datalength);
+               switch (bincmd) {
+               case FW_HAS_DATA_TO_RECV:
+                       offset = sizeof(struct fwheader) + blksize;
+                       data += offset;
+                       len += offset;
+                       if (len >= totlen)
+                               exit = 1;
+                       break;
+               case FW_HAS_LAST_BLOCK:
+                       exit = 1;
+                       ret = 0;
+                       break;
+               default:
+                       exit = 1;
+                       break;
+               }
+       } while (!exit);
+
+       if (ret)
+               pr_err("firmware file format check FAIL\n");
+       else
+               lbs_deb_fw("firmware file format check PASS\n");
+
+       return ret;
+}
+
+static void if_usb_prog_firmware(struct lbs_private *priv, int ret,
+                                const struct firmware *fw,
+                                const struct firmware *unused)
+{
+       struct if_usb_card *cardp = priv->card;
+       int i = 0;
+       static int reset_count = 10;
+
+       lbs_deb_enter(LBS_DEB_USB);
+
+       if (ret) {
+               pr_err("failed to find firmware (%d)\n", ret);
+               goto done;
+       }
+
+       cardp->fw = fw;
+       if (check_fwfile_format(cardp->fw->data, cardp->fw->size)) {
+               ret = -EINVAL;
+               goto done;
+       }
+
+       /* Cancel any pending usb business */
+       usb_kill_urb(cardp->rx_urb);
+       usb_kill_urb(cardp->tx_urb);
+
+       cardp->fwlastblksent = 0;
+       cardp->fwdnldover = 0;
+       cardp->totalbytes = 0;
+       cardp->fwfinalblk = 0;
+       cardp->bootcmdresp = 0;
+
+restart:
+       if (if_usb_submit_rx_urb_fwload(cardp) < 0) {
+               lbs_deb_usbd(&cardp->udev->dev, "URB submission is failed\n");
+               ret = -EIO;
+               goto done;
+       }
+
+       cardp->bootcmdresp = 0;
+       do {
+               int j = 0;
+               i++;
+               if_usb_issue_boot_command(cardp, BOOT_CMD_FW_BY_USB);
+               /* wait for command response */
+               do {
+                       j++;
+                       msleep_interruptible(100);
+               } while (cardp->bootcmdresp == 0 && j < 10);
+       } while (cardp->bootcmdresp == 0 && i < 5);
+
+       if (cardp->bootcmdresp == BOOT_CMD_RESP_NOT_SUPPORTED) {
+               /* Return to normal operation */
+               ret = -EOPNOTSUPP;
+               usb_kill_urb(cardp->rx_urb);
+               usb_kill_urb(cardp->tx_urb);
+               if (if_usb_submit_rx_urb(cardp) < 0)
+                       ret = -EIO;
+               goto done;
+       } else if (cardp->bootcmdresp <= 0) {
+               if (--reset_count >= 0) {
+                       if_usb_reset_device(cardp);
+                       goto restart;
+               }
+               ret = -EIO;
+               goto done;
+       }
+
+       i = 0;
+
+       cardp->totalbytes = 0;
+       cardp->fwlastblksent = 0;
+       cardp->CRC_OK = 1;
+       cardp->fwdnldover = 0;
+       cardp->fwseqnum = -1;
+       cardp->totalbytes = 0;
+       cardp->fwfinalblk = 0;
+
+       /* Send the first firmware packet... */
+       if_usb_send_fw_pkt(cardp);
+
+       /* ... and wait for the process to complete */
+       wait_event_interruptible(cardp->fw_wq, cardp->surprise_removed || cardp->fwdnldover);
+
+       del_timer_sync(&cardp->fw_timeout);
+       usb_kill_urb(cardp->rx_urb);
+
+       if (!cardp->fwdnldover) {
+               pr_info("failed to load fw, resetting device!\n");
+               if (--reset_count >= 0) {
+                       if_usb_reset_device(cardp);
+                       goto restart;
+               }
+
+               pr_info("FW download failure, time = %d ms\n", i * 100);
+               ret = -EIO;
+               goto done;
+       }
+
+       cardp->priv->fw_ready = 1;
+       if_usb_submit_rx_urb(cardp);
+
+       if (lbs_start_card(priv))
+               goto done;
+
+       if_usb_setup_firmware(priv);
+
+       /*
+        * EHS_REMOVE_WAKEUP is not supported on all versions of the firmware.
+        */
+       priv->wol_criteria = EHS_REMOVE_WAKEUP;
+       if (lbs_host_sleep_cfg(priv, priv->wol_criteria, NULL))
+               priv->ehs_remove_supported = false;
+
+ done:
+       cardp->fw = NULL;
+       lbs_deb_leave(LBS_DEB_USB);
+}
+
+
+#ifdef CONFIG_PM
+static int if_usb_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct if_usb_card *cardp = usb_get_intfdata(intf);
+       struct lbs_private *priv = cardp->priv;
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_USB);
+
+       if (priv->psstate != PS_STATE_FULL_POWER) {
+               ret = -1;
+               goto out;
+       }
+
+#ifdef CONFIG_OLPC
+       if (machine_is_olpc()) {
+               if (priv->wol_criteria == EHS_REMOVE_WAKEUP)
+                       olpc_ec_wakeup_clear(EC_SCI_SRC_WLAN);
+               else
+                       olpc_ec_wakeup_set(EC_SCI_SRC_WLAN);
+       }
+#endif
+
+       ret = lbs_suspend(priv);
+       if (ret)
+               goto out;
+
+       /* Unlink tx & rx urb */
+       usb_kill_urb(cardp->tx_urb);
+       usb_kill_urb(cardp->rx_urb);
+
+ out:
+       lbs_deb_leave(LBS_DEB_USB);
+       return ret;
+}
+
+static int if_usb_resume(struct usb_interface *intf)
+{
+       struct if_usb_card *cardp = usb_get_intfdata(intf);
+       struct lbs_private *priv = cardp->priv;
+
+       lbs_deb_enter(LBS_DEB_USB);
+
+       if_usb_submit_rx_urb(cardp);
+
+       lbs_resume(priv);
+
+       lbs_deb_leave(LBS_DEB_USB);
+       return 0;
+}
+#else
+#define if_usb_suspend NULL
+#define if_usb_resume NULL
+#endif
+
+static struct usb_driver if_usb_driver = {
+       .name = DRV_NAME,
+       .probe = if_usb_probe,
+       .disconnect = if_usb_disconnect,
+       .id_table = if_usb_table,
+       .suspend = if_usb_suspend,
+       .resume = if_usb_resume,
+       .reset_resume = if_usb_resume,
+       .disable_hub_initiated_lpm = 1,
+};
+
+module_usb_driver(if_usb_driver);
+
+MODULE_DESCRIPTION("8388 USB WLAN Driver");
+MODULE_AUTHOR("Marvell International Ltd. and Red Hat, Inc.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/marvell/libertas/if_usb.h b/drivers/net/wireless/marvell/libertas/if_usb.h
new file mode 100644 (file)
index 0000000..6e42eac
--- /dev/null
@@ -0,0 +1,106 @@
+#ifndef _LBS_IF_USB_H
+#define _LBS_IF_USB_H
+
+#include <linux/wait.h>
+#include <linux/timer.h>
+
+struct lbs_private;
+
+/*
+ * This file contains definition for USB interface.
+ */
+#define CMD_TYPE_REQUEST               0xF00DFACE
+#define CMD_TYPE_DATA                  0xBEADC0DE
+#define CMD_TYPE_INDICATION            0xBEEFFACE
+
+#define IPFIELD_ALIGN_OFFSET           2
+
+#define BOOT_CMD_FW_BY_USB             0x01
+#define BOOT_CMD_FW_IN_EEPROM          0x02
+#define BOOT_CMD_UPDATE_BOOT2          0x03
+#define BOOT_CMD_UPDATE_FW             0x04
+#define BOOT_CMD_MAGIC_NUMBER          0x4C56524D   /* LVRM */
+
+struct bootcmd
+{
+       __le32  magic;
+       uint8_t cmd;
+       uint8_t pad[11];
+};
+
+#define BOOT_CMD_RESP_OK               0x0001
+#define BOOT_CMD_RESP_FAIL             0x0000
+#define BOOT_CMD_RESP_NOT_SUPPORTED    0x0002
+
+struct bootcmdresp
+{
+       __le32  magic;
+       uint8_t cmd;
+       uint8_t result;
+       uint8_t pad[2];
+};
+
+/* USB card description structure*/
+struct if_usb_card {
+       struct usb_device *udev;
+       uint32_t model;  /* MODEL_* */
+       struct urb *rx_urb, *tx_urb;
+       struct lbs_private *priv;
+
+       struct sk_buff *rx_skb;
+
+       uint8_t ep_in;
+       uint8_t ep_out;
+
+       /* bootcmdresp == 0 means command is pending
+        * bootcmdresp < 0 means error
+        * bootcmdresp > 0 is a BOOT_CMD_RESP_* from firmware
+        */
+       int8_t bootcmdresp;
+
+       int ep_in_size;
+
+       void *ep_out_buf;
+       int ep_out_size;
+
+       const struct firmware *fw;
+       struct timer_list fw_timeout;
+       wait_queue_head_t fw_wq;
+       uint32_t fwseqnum;
+       uint32_t totalbytes;
+       uint32_t fwlastblksent;
+       uint8_t CRC_OK;
+       uint8_t fwdnldover;
+       uint8_t fwfinalblk;
+       uint8_t surprise_removed;
+
+       __le16 boot2_version;
+};
+
+/* fwheader */
+struct fwheader {
+       __le32 dnldcmd;
+       __le32 baseaddr;
+       __le32 datalength;
+       __le32 CRC;
+};
+
+#define FW_MAX_DATA_BLK_SIZE   600
+/* FWData */
+struct fwdata {
+       struct fwheader hdr;
+       __le32 seqnum;
+       uint8_t data[0];
+};
+
+/* fwsyncheader */
+struct fwsyncheader {
+       __le32 cmd;
+       __le32 seqnum;
+};
+
+#define FW_HAS_DATA_TO_RECV            0x00000001
+#define FW_HAS_LAST_BLOCK              0x00000004
+
+
+#endif
diff --git a/drivers/net/wireless/marvell/libertas/main.c b/drivers/net/wireless/marvell/libertas/main.c
new file mode 100644 (file)
index 0000000..8079560
--- /dev/null
@@ -0,0 +1,1225 @@
+/*
+ * This file contains the major functions in WLAN
+ * driver. It includes init, exit, open, close and main
+ * thread etc..
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/hardirq.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/kthread.h>
+#include <linux/kfifo.h>
+#include <linux/slab.h>
+#include <net/cfg80211.h>
+
+#include "host.h"
+#include "decl.h"
+#include "dev.h"
+#include "cfg.h"
+#include "debugfs.h"
+#include "cmd.h"
+#include "mesh.h"
+
+#define DRIVER_RELEASE_VERSION "323.p0"
+const char lbs_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION
+#ifdef  DEBUG
+    "-dbg"
+#endif
+    "";
+
+
+/* Module parameters */
+unsigned int lbs_debug;
+EXPORT_SYMBOL_GPL(lbs_debug);
+module_param_named(libertas_debug, lbs_debug, int, 0644);
+
+unsigned int lbs_disablemesh;
+EXPORT_SYMBOL_GPL(lbs_disablemesh);
+module_param_named(libertas_disablemesh, lbs_disablemesh, int, 0644);
+
+
+/*
+ * This global structure is used to send the confirm_sleep command as
+ * fast as possible down to the firmware.
+ */
+struct cmd_confirm_sleep confirm_sleep;
+
+
+/*
+ * the table to keep region code
+ */
+u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE] =
+    { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 };
+
+/*
+ * FW rate table.  FW refers to rates by their index in this table, not by the
+ * rate value itself.  Values of 0x00 are
+ * reserved positions.
+ */
+static u8 fw_data_rates[MAX_RATES] =
+    { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12,
+      0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00
+};
+
+/**
+ *  lbs_fw_index_to_data_rate - use index to get the data rate
+ *
+ *  @idx:      The index of data rate
+ *  returns:   data rate or 0
+ */
+u32 lbs_fw_index_to_data_rate(u8 idx)
+{
+       if (idx >= sizeof(fw_data_rates))
+               idx = 0;
+       return fw_data_rates[idx];
+}
+
+/**
+ *  lbs_data_rate_to_fw_index - use rate to get the index
+ *
+ *  @rate:     data rate
+ *  returns:   index or 0
+ */
+u8 lbs_data_rate_to_fw_index(u32 rate)
+{
+       u8 i;
+
+       if (!rate)
+               return 0;
+
+       for (i = 0; i < sizeof(fw_data_rates); i++) {
+               if (rate == fw_data_rates[i])
+                       return i;
+       }
+       return 0;
+}
+
+int lbs_set_iface_type(struct lbs_private *priv, enum nl80211_iftype type)
+{
+       int ret = 0;
+
+       switch (type) {
+       case NL80211_IFTYPE_MONITOR:
+               ret = lbs_set_monitor_mode(priv, 1);
+               break;
+       case NL80211_IFTYPE_STATION:
+               if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR)
+                       ret = lbs_set_monitor_mode(priv, 0);
+               if (!ret)
+                       ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, 1);
+               break;
+       case NL80211_IFTYPE_ADHOC:
+               if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR)
+                       ret = lbs_set_monitor_mode(priv, 0);
+               if (!ret)
+                       ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, 2);
+               break;
+       default:
+               ret = -ENOTSUPP;
+       }
+       return ret;
+}
+
+int lbs_start_iface(struct lbs_private *priv)
+{
+       struct cmd_ds_802_11_mac_address cmd;
+       int ret;
+
+       if (priv->power_restore) {
+               ret = priv->power_restore(priv);
+               if (ret)
+                       return ret;
+       }
+
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       cmd.action = cpu_to_le16(CMD_ACT_SET);
+       memcpy(cmd.macadd, priv->current_addr, ETH_ALEN);
+
+       ret = lbs_cmd_with_response(priv, CMD_802_11_MAC_ADDRESS, &cmd);
+       if (ret) {
+               lbs_deb_net("set MAC address failed\n");
+               goto err;
+       }
+
+       ret = lbs_set_iface_type(priv, priv->wdev->iftype);
+       if (ret) {
+               lbs_deb_net("set iface type failed\n");
+               goto err;
+       }
+
+       ret = lbs_set_11d_domain_info(priv);
+       if (ret) {
+               lbs_deb_net("set 11d domain info failed\n");
+               goto err;
+       }
+
+       lbs_update_channel(priv);
+
+       priv->iface_running = true;
+       return 0;
+
+err:
+       if (priv->power_save)
+               priv->power_save(priv);
+       return ret;
+}
+
+/**
+ *  lbs_dev_open - open the ethX interface
+ *
+ *  @dev:      A pointer to &net_device structure
+ *  returns:   0 or -EBUSY if monitor mode active
+ */
+static int lbs_dev_open(struct net_device *dev)
+{
+       struct lbs_private *priv = dev->ml_priv;
+       int ret = 0;
+
+       lbs_deb_enter(LBS_DEB_NET);
+       if (!priv->iface_running) {
+               ret = lbs_start_iface(priv);
+               if (ret)
+                       goto out;
+       }
+
+       spin_lock_irq(&priv->driver_lock);
+
+       netif_carrier_off(dev);
+
+       if (!priv->tx_pending_len)
+               netif_wake_queue(dev);
+
+       spin_unlock_irq(&priv->driver_lock);
+
+out:
+       lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
+       return ret;
+}
+
+static bool lbs_command_queue_empty(struct lbs_private *priv)
+{
+       unsigned long flags;
+       bool ret;
+       spin_lock_irqsave(&priv->driver_lock, flags);
+       ret = priv->cur_cmd == NULL && list_empty(&priv->cmdpendingq);
+       spin_unlock_irqrestore(&priv->driver_lock, flags);
+       return ret;
+}
+
+int lbs_stop_iface(struct lbs_private *priv)
+{
+       unsigned long flags;
+       int ret = 0;
+
+       lbs_deb_enter(LBS_DEB_MAIN);
+
+       spin_lock_irqsave(&priv->driver_lock, flags);
+       priv->iface_running = false;
+       kfree_skb(priv->currenttxskb);
+       priv->currenttxskb = NULL;
+       priv->tx_pending_len = 0;
+       spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+       cancel_work_sync(&priv->mcast_work);
+       del_timer_sync(&priv->tx_lockup_timer);
+
+       /* Disable command processing, and wait for all commands to complete */
+       lbs_deb_main("waiting for commands to complete\n");
+       wait_event(priv->waitq, lbs_command_queue_empty(priv));
+       lbs_deb_main("all commands completed\n");
+
+       if (priv->power_save)
+               ret = priv->power_save(priv);
+
+       lbs_deb_leave(LBS_DEB_MAIN);
+       return ret;
+}
+
+/**
+ *  lbs_eth_stop - close the ethX interface
+ *
+ *  @dev:      A pointer to &net_device structure
+ *  returns:   0
+ */
+static int lbs_eth_stop(struct net_device *dev)
+{
+       struct lbs_private *priv = dev->ml_priv;
+
+       lbs_deb_enter(LBS_DEB_NET);
+
+       if (priv->connect_status == LBS_CONNECTED)
+               lbs_disconnect(priv, WLAN_REASON_DEAUTH_LEAVING);
+
+       spin_lock_irq(&priv->driver_lock);
+       netif_stop_queue(dev);
+       spin_unlock_irq(&priv->driver_lock);
+
+       lbs_update_mcast(priv);
+       cancel_delayed_work_sync(&priv->scan_work);
+       if (priv->scan_req)
+               lbs_scan_done(priv);
+
+       netif_carrier_off(priv->dev);
+
+       if (!lbs_iface_active(priv))
+               lbs_stop_iface(priv);
+
+       lbs_deb_leave(LBS_DEB_NET);
+       return 0;
+}
+
+void lbs_host_to_card_done(struct lbs_private *priv)
+{
+       unsigned long flags;
+
+       lbs_deb_enter(LBS_DEB_THREAD);
+
+       spin_lock_irqsave(&priv->driver_lock, flags);
+       del_timer(&priv->tx_lockup_timer);
+
+       priv->dnld_sent = DNLD_RES_RECEIVED;
+
+       /* Wake main thread if commands are pending */
+       if (!priv->cur_cmd || priv->tx_pending_len > 0) {
+               if (!priv->wakeup_dev_required)
+                       wake_up(&priv->waitq);
+       }
+
+       spin_unlock_irqrestore(&priv->driver_lock, flags);
+       lbs_deb_leave(LBS_DEB_THREAD);
+}
+EXPORT_SYMBOL_GPL(lbs_host_to_card_done);
+
+int lbs_set_mac_address(struct net_device *dev, void *addr)
+{
+       int ret = 0;
+       struct lbs_private *priv = dev->ml_priv;
+       struct sockaddr *phwaddr = addr;
+
+       lbs_deb_enter(LBS_DEB_NET);
+
+       /*
+        * Can only set MAC address when all interfaces are down, to be written
+        * to the hardware when one of them is brought up.
+        */
+       if (lbs_iface_active(priv))
+               return -EBUSY;
+
+       /* In case it was called from the mesh device */
+       dev = priv->dev;
+
+       memcpy(priv->current_addr, phwaddr->sa_data, ETH_ALEN);
+       memcpy(dev->dev_addr, phwaddr->sa_data, ETH_ALEN);
+       if (priv->mesh_dev)
+               memcpy(priv->mesh_dev->dev_addr, phwaddr->sa_data, ETH_ALEN);
+
+       lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
+       return ret;
+}
+
+
+static inline int mac_in_list(unsigned char *list, int list_len,
+                             unsigned char *mac)
+{
+       while (list_len) {
+               if (!memcmp(list, mac, ETH_ALEN))
+                       return 1;
+               list += ETH_ALEN;
+               list_len--;
+       }
+       return 0;
+}
+
+
+static int lbs_add_mcast_addrs(struct cmd_ds_mac_multicast_adr *cmd,
+                              struct net_device *dev, int nr_addrs)
+{
+       int i = nr_addrs;
+       struct netdev_hw_addr *ha;
+       int cnt;
+
+       if ((dev->flags & (IFF_UP|IFF_MULTICAST)) != (IFF_UP|IFF_MULTICAST))
+               return nr_addrs;
+
+       netif_addr_lock_bh(dev);
+       cnt = netdev_mc_count(dev);
+       netdev_for_each_mc_addr(ha, dev) {
+               if (mac_in_list(cmd->maclist, nr_addrs, ha->addr)) {
+                       lbs_deb_net("mcast address %s:%pM skipped\n", dev->name,
+                                   ha->addr);
+                       cnt--;
+                       continue;
+               }
+
+               if (i == MRVDRV_MAX_MULTICAST_LIST_SIZE)
+                       break;
+               memcpy(&cmd->maclist[6*i], ha->addr, ETH_ALEN);
+               lbs_deb_net("mcast address %s:%pM added to filter\n", dev->name,
+                           ha->addr);
+               i++;
+               cnt--;
+       }
+       netif_addr_unlock_bh(dev);
+       if (cnt)
+               return -EOVERFLOW;
+
+       return i;
+}
+
+void lbs_update_mcast(struct lbs_private *priv)
+{
+       struct cmd_ds_mac_multicast_adr mcast_cmd;
+       int dev_flags = 0;
+       int nr_addrs;
+       int old_mac_control = priv->mac_control;
+
+       lbs_deb_enter(LBS_DEB_NET);
+
+       if (netif_running(priv->dev))
+               dev_flags |= priv->dev->flags;
+       if (priv->mesh_dev && netif_running(priv->mesh_dev))
+               dev_flags |= priv->mesh_dev->flags;
+
+       if (dev_flags & IFF_PROMISC) {
+               priv->mac_control |= CMD_ACT_MAC_PROMISCUOUS_ENABLE;
+               priv->mac_control &= ~(CMD_ACT_MAC_ALL_MULTICAST_ENABLE |
+                                      CMD_ACT_MAC_MULTICAST_ENABLE);
+               goto out_set_mac_control;
+       } else if (dev_flags & IFF_ALLMULTI) {
+       do_allmulti:
+               priv->mac_control |= CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
+               priv->mac_control &= ~(CMD_ACT_MAC_PROMISCUOUS_ENABLE |
+                                      CMD_ACT_MAC_MULTICAST_ENABLE);
+               goto out_set_mac_control;
+       }
+
+       /* Once for priv->dev, again for priv->mesh_dev if it exists */
+       nr_addrs = lbs_add_mcast_addrs(&mcast_cmd, priv->dev, 0);
+       if (nr_addrs >= 0 && priv->mesh_dev)
+               nr_addrs = lbs_add_mcast_addrs(&mcast_cmd, priv->mesh_dev, nr_addrs);
+       if (nr_addrs < 0)
+               goto do_allmulti;
+
+       if (nr_addrs) {
+               int size = offsetof(struct cmd_ds_mac_multicast_adr,
+                                   maclist[6*nr_addrs]);
+
+               mcast_cmd.action = cpu_to_le16(CMD_ACT_SET);
+               mcast_cmd.hdr.size = cpu_to_le16(size);
+               mcast_cmd.nr_of_adrs = cpu_to_le16(nr_addrs);
+
+               lbs_cmd_async(priv, CMD_MAC_MULTICAST_ADR, &mcast_cmd.hdr, size);
+
+               priv->mac_control |= CMD_ACT_MAC_MULTICAST_ENABLE;
+       } else
+               priv->mac_control &= ~CMD_ACT_MAC_MULTICAST_ENABLE;
+
+       priv->mac_control &= ~(CMD_ACT_MAC_PROMISCUOUS_ENABLE |
+                              CMD_ACT_MAC_ALL_MULTICAST_ENABLE);
+ out_set_mac_control:
+       if (priv->mac_control != old_mac_control)
+               lbs_set_mac_control(priv);
+
+       lbs_deb_leave(LBS_DEB_NET);
+}
+
+static void lbs_set_mcast_worker(struct work_struct *work)
+{
+       struct lbs_private *priv = container_of(work, struct lbs_private, mcast_work);
+       lbs_update_mcast(priv);
+}
+
+void lbs_set_multicast_list(struct net_device *dev)
+{
+       struct lbs_private *priv = dev->ml_priv;
+
+       schedule_work(&priv->mcast_work);
+}
+
+/**
+ *  lbs_thread - handles the major jobs in the LBS driver.
+ *  It handles all events generated by firmware, RX data received
+ *  from firmware and TX data sent from kernel.
+ *
+ *  @data:     A pointer to &lbs_thread structure
+ *  returns:   0
+ */
+static int lbs_thread(void *data)
+{
+       struct net_device *dev = data;
+       struct lbs_private *priv = dev->ml_priv;
+       wait_queue_t wait;
+
+       lbs_deb_enter(LBS_DEB_THREAD);
+
+       init_waitqueue_entry(&wait, current);
+
+       for (;;) {
+               int shouldsleep;
+               u8 resp_idx;
+
+               lbs_deb_thread("1: currenttxskb %p, dnld_sent %d\n",
+                               priv->currenttxskb, priv->dnld_sent);
+
+               add_wait_queue(&priv->waitq, &wait);
+               set_current_state(TASK_INTERRUPTIBLE);
+               spin_lock_irq(&priv->driver_lock);
+
+               if (kthread_should_stop())
+                       shouldsleep = 0;        /* Bye */
+               else if (priv->surpriseremoved)
+                       shouldsleep = 1;        /* We need to wait until we're _told_ to die */
+               else if (priv->psstate == PS_STATE_SLEEP)
+                       shouldsleep = 1;        /* Sleep mode. Nothing we can do till it wakes */
+               else if (priv->cmd_timed_out)
+                       shouldsleep = 0;        /* Command timed out. Recover */
+               else if (!priv->fw_ready)
+                       shouldsleep = 1;        /* Firmware not ready. We're waiting for it */
+               else if (priv->dnld_sent)
+                       shouldsleep = 1;        /* Something is en route to the device already */
+               else if (priv->tx_pending_len > 0)
+                       shouldsleep = 0;        /* We've a packet to send */
+               else if (priv->resp_len[priv->resp_idx])
+                       shouldsleep = 0;        /* We have a command response */
+               else if (priv->cur_cmd)
+                       shouldsleep = 1;        /* Can't send a command; one already running */
+               else if (!list_empty(&priv->cmdpendingq) &&
+                                       !(priv->wakeup_dev_required))
+                       shouldsleep = 0;        /* We have a command to send */
+               else if (kfifo_len(&priv->event_fifo))
+                       shouldsleep = 0;        /* We have an event to process */
+               else
+                       shouldsleep = 1;        /* No command */
+
+               if (shouldsleep) {
+                       lbs_deb_thread("sleeping, connect_status %d, "
+                               "psmode %d, psstate %d\n",
+                               priv->connect_status,
+                               priv->psmode, priv->psstate);
+                       spin_unlock_irq(&priv->driver_lock);
+                       schedule();
+               } else
+                       spin_unlock_irq(&priv->driver_lock);
+
+               lbs_deb_thread("2: currenttxskb %p, dnld_send %d\n",
+                              priv->currenttxskb, priv->dnld_sent);
+
+               set_current_state(TASK_RUNNING);
+               remove_wait_queue(&priv->waitq, &wait);
+
+               lbs_deb_thread("3: currenttxskb %p, dnld_sent %d\n",
+                              priv->currenttxskb, priv->dnld_sent);
+
+               if (kthread_should_stop()) {
+                       lbs_deb_thread("break from main thread\n");
+                       break;
+               }
+
+               if (priv->surpriseremoved) {
+                       lbs_deb_thread("adapter removed; waiting to die...\n");
+                       continue;
+               }
+
+               lbs_deb_thread("4: currenttxskb %p, dnld_sent %d\n",
+                      priv->currenttxskb, priv->dnld_sent);
+
+               /* Process any pending command response */
+               spin_lock_irq(&priv->driver_lock);
+               resp_idx = priv->resp_idx;
+               if (priv->resp_len[resp_idx]) {
+                       spin_unlock_irq(&priv->driver_lock);
+                       lbs_process_command_response(priv,
+                               priv->resp_buf[resp_idx],
+                               priv->resp_len[resp_idx]);
+                       spin_lock_irq(&priv->driver_lock);
+                       priv->resp_len[resp_idx] = 0;
+               }
+               spin_unlock_irq(&priv->driver_lock);
+
+               /* Process hardware events, e.g. card removed, link lost */
+               spin_lock_irq(&priv->driver_lock);
+               while (kfifo_len(&priv->event_fifo)) {
+                       u32 event;
+
+                       if (kfifo_out(&priv->event_fifo,
+                               (unsigned char *) &event, sizeof(event)) !=
+                               sizeof(event))
+                                       break;
+                       spin_unlock_irq(&priv->driver_lock);
+                       lbs_process_event(priv, event);
+                       spin_lock_irq(&priv->driver_lock);
+               }
+               spin_unlock_irq(&priv->driver_lock);
+
+               if (priv->wakeup_dev_required) {
+                       lbs_deb_thread("Waking up device...\n");
+                       /* Wake up device */
+                       if (priv->exit_deep_sleep(priv))
+                               lbs_deb_thread("Wakeup device failed\n");
+                       continue;
+               }
+
+               /* command timeout stuff */
+               if (priv->cmd_timed_out && priv->cur_cmd) {
+                       struct cmd_ctrl_node *cmdnode = priv->cur_cmd;
+
+                       netdev_info(dev, "Timeout submitting command 0x%04x\n",
+                                   le16_to_cpu(cmdnode->cmdbuf->command));
+                       lbs_complete_command(priv, cmdnode, -ETIMEDOUT);
+
+                       /* Reset card, but only when it isn't in the process
+                        * of being shutdown anyway. */
+                       if (!dev->dismantle && priv->reset_card)
+                               priv->reset_card(priv);
+               }
+               priv->cmd_timed_out = 0;
+
+               if (!priv->fw_ready)
+                       continue;
+
+               /* Check if we need to confirm Sleep Request received previously */
+               if (priv->psstate == PS_STATE_PRE_SLEEP &&
+                   !priv->dnld_sent && !priv->cur_cmd) {
+                       if (priv->connect_status == LBS_CONNECTED) {
+                               lbs_deb_thread("pre-sleep, currenttxskb %p, "
+                                       "dnld_sent %d, cur_cmd %p\n",
+                                       priv->currenttxskb, priv->dnld_sent,
+                                       priv->cur_cmd);
+
+                               lbs_ps_confirm_sleep(priv);
+                       } else {
+                               /* workaround for firmware sending
+                                * deauth/linkloss event immediately
+                                * after sleep request; remove this
+                                * after firmware fixes it
+                                */
+                               priv->psstate = PS_STATE_AWAKE;
+                               netdev_alert(dev,
+                                            "ignore PS_SleepConfirm in non-connected state\n");
+                       }
+               }
+
+               /* The PS state is changed during processing of Sleep Request
+                * event above
+                */
+               if ((priv->psstate == PS_STATE_SLEEP) ||
+                   (priv->psstate == PS_STATE_PRE_SLEEP))
+                       continue;
+
+               if (priv->is_deep_sleep)
+                       continue;
+
+               /* Execute the next command */
+               if (!priv->dnld_sent && !priv->cur_cmd)
+                       lbs_execute_next_command(priv);
+
+               spin_lock_irq(&priv->driver_lock);
+               if (!priv->dnld_sent && priv->tx_pending_len > 0) {
+                       int ret = priv->hw_host_to_card(priv, MVMS_DAT,
+                                                       priv->tx_pending_buf,
+                                                       priv->tx_pending_len);
+                       if (ret) {
+                               lbs_deb_tx("host_to_card failed %d\n", ret);
+                               priv->dnld_sent = DNLD_RES_RECEIVED;
+                       } else {
+                               mod_timer(&priv->tx_lockup_timer,
+                                         jiffies + (HZ * 5));
+                       }
+                       priv->tx_pending_len = 0;
+                       if (!priv->currenttxskb) {
+                               /* We can wake the queues immediately if we aren't
+                                  waiting for TX feedback */
+                               if (priv->connect_status == LBS_CONNECTED)
+                                       netif_wake_queue(priv->dev);
+                               if (priv->mesh_dev &&
+                                   netif_running(priv->mesh_dev))
+                                       netif_wake_queue(priv->mesh_dev);
+                       }
+               }
+               spin_unlock_irq(&priv->driver_lock);
+       }
+
+       del_timer(&priv->command_timer);
+       del_timer(&priv->tx_lockup_timer);
+       del_timer(&priv->auto_deepsleep_timer);
+
+       lbs_deb_leave(LBS_DEB_THREAD);
+       return 0;
+}
+
+/**
+ * lbs_setup_firmware - gets the HW spec from the firmware and sets
+ *        some basic parameters
+ *
+ *  @priv:     A pointer to &struct lbs_private structure
+ *  returns:   0 or -1
+ */
+static int lbs_setup_firmware(struct lbs_private *priv)
+{
+       int ret = -1;
+       s16 curlevel = 0, minlevel = 0, maxlevel = 0;
+
+       lbs_deb_enter(LBS_DEB_FW);
+
+       /* Read MAC address from firmware */
+       eth_broadcast_addr(priv->current_addr);
+       ret = lbs_update_hw_spec(priv);
+       if (ret)
+               goto done;
+
+       /* Read power levels if available */
+       ret = lbs_get_tx_power(priv, &curlevel, &minlevel, &maxlevel);
+       if (ret == 0) {
+               priv->txpower_cur = curlevel;
+               priv->txpower_min = minlevel;
+               priv->txpower_max = maxlevel;
+       }
+
+       /* Send cmd to FW to enable 11D function */
+       ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_11D_ENABLE, 1);
+       if (ret)
+               goto done;
+
+       ret = lbs_set_mac_control_sync(priv);
+done:
+       lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
+       return ret;
+}
+
+int lbs_suspend(struct lbs_private *priv)
+{
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_FW);
+
+       if (priv->is_deep_sleep) {
+               ret = lbs_set_deep_sleep(priv, 0);
+               if (ret) {
+                       netdev_err(priv->dev,
+                                  "deep sleep cancellation failed: %d\n", ret);
+                       return ret;
+               }
+               priv->deep_sleep_required = 1;
+       }
+
+       ret = lbs_set_host_sleep(priv, 1);
+
+       netif_device_detach(priv->dev);
+       if (priv->mesh_dev)
+               netif_device_detach(priv->mesh_dev);
+
+       lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(lbs_suspend);
+
+int lbs_resume(struct lbs_private *priv)
+{
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_FW);
+
+       ret = lbs_set_host_sleep(priv, 0);
+
+       netif_device_attach(priv->dev);
+       if (priv->mesh_dev)
+               netif_device_attach(priv->mesh_dev);
+
+       if (priv->deep_sleep_required) {
+               priv->deep_sleep_required = 0;
+               ret = lbs_set_deep_sleep(priv, 1);
+               if (ret)
+                       netdev_err(priv->dev,
+                                  "deep sleep activation failed: %d\n", ret);
+       }
+
+       if (priv->setup_fw_on_resume)
+               ret = lbs_setup_firmware(priv);
+
+       lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(lbs_resume);
+
+/**
+ * lbs_cmd_timeout_handler - handles the timeout of command sending.
+ * It will re-send the same command again.
+ *
+ * @data: &struct lbs_private pointer
+ */
+static void lbs_cmd_timeout_handler(unsigned long data)
+{
+       struct lbs_private *priv = (struct lbs_private *)data;
+       unsigned long flags;
+
+       lbs_deb_enter(LBS_DEB_CMD);
+       spin_lock_irqsave(&priv->driver_lock, flags);
+
+       if (!priv->cur_cmd)
+               goto out;
+
+       netdev_info(priv->dev, "command 0x%04x timed out\n",
+                   le16_to_cpu(priv->cur_cmd->cmdbuf->command));
+
+       priv->cmd_timed_out = 1;
+
+       /*
+        * If the device didn't even acknowledge the command, reset the state
+        * so that we don't block all future commands due to this one timeout.
+        */
+       if (priv->dnld_sent == DNLD_CMD_SENT)
+               priv->dnld_sent = DNLD_RES_RECEIVED;
+
+       wake_up(&priv->waitq);
+out:
+       spin_unlock_irqrestore(&priv->driver_lock, flags);
+       lbs_deb_leave(LBS_DEB_CMD);
+}
+
+/**
+ * lbs_tx_lockup_handler - handles the timeout of the passing of TX frames
+ * to the hardware. This is known to frequently happen with SD8686 when
+ * waking up after a Wake-on-WLAN-triggered resume.
+ *
+ * @data: &struct lbs_private pointer
+ */
+static void lbs_tx_lockup_handler(unsigned long data)
+{
+       struct lbs_private *priv = (struct lbs_private *)data;
+       unsigned long flags;
+
+       lbs_deb_enter(LBS_DEB_TX);
+       spin_lock_irqsave(&priv->driver_lock, flags);
+
+       netdev_info(priv->dev, "TX lockup detected\n");
+       if (priv->reset_card)
+               priv->reset_card(priv);
+
+       priv->dnld_sent = DNLD_RES_RECEIVED;
+       wake_up_interruptible(&priv->waitq);
+
+       spin_unlock_irqrestore(&priv->driver_lock, flags);
+       lbs_deb_leave(LBS_DEB_TX);
+}
+
+/**
+ * auto_deepsleep_timer_fn - put the device back to deep sleep mode when
+ * timer expires and no activity (command, event, data etc.) is detected.
+ * @data:      &struct lbs_private pointer
+ * returns:    N/A
+ */
+static void auto_deepsleep_timer_fn(unsigned long data)
+{
+       struct lbs_private *priv = (struct lbs_private *)data;
+
+       lbs_deb_enter(LBS_DEB_CMD);
+
+       if (priv->is_activity_detected) {
+               priv->is_activity_detected = 0;
+       } else {
+               if (priv->is_auto_deep_sleep_enabled &&
+                   (!priv->wakeup_dev_required) &&
+                   (priv->connect_status != LBS_CONNECTED)) {
+                       struct cmd_header cmd;
+
+                       lbs_deb_main("Entering auto deep sleep mode...\n");
+                       memset(&cmd, 0, sizeof(cmd));
+                       cmd.size = cpu_to_le16(sizeof(cmd));
+                       lbs_cmd_async(priv, CMD_802_11_DEEP_SLEEP, &cmd,
+                                       sizeof(cmd));
+               }
+       }
+       mod_timer(&priv->auto_deepsleep_timer , jiffies +
+                               (priv->auto_deep_sleep_timeout * HZ)/1000);
+       lbs_deb_leave(LBS_DEB_CMD);
+}
+
+int lbs_enter_auto_deep_sleep(struct lbs_private *priv)
+{
+       lbs_deb_enter(LBS_DEB_SDIO);
+
+       priv->is_auto_deep_sleep_enabled = 1;
+       if (priv->is_deep_sleep)
+               priv->wakeup_dev_required = 1;
+       mod_timer(&priv->auto_deepsleep_timer ,
+                       jiffies + (priv->auto_deep_sleep_timeout * HZ)/1000);
+
+       lbs_deb_leave(LBS_DEB_SDIO);
+       return 0;
+}
+
+int lbs_exit_auto_deep_sleep(struct lbs_private *priv)
+{
+       lbs_deb_enter(LBS_DEB_SDIO);
+
+       priv->is_auto_deep_sleep_enabled = 0;
+       priv->auto_deep_sleep_timeout = 0;
+       del_timer(&priv->auto_deepsleep_timer);
+
+       lbs_deb_leave(LBS_DEB_SDIO);
+       return 0;
+}
+
+static int lbs_init_adapter(struct lbs_private *priv)
+{
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_MAIN);
+
+       eth_broadcast_addr(priv->current_addr);
+
+       priv->connect_status = LBS_DISCONNECTED;
+       priv->channel = DEFAULT_AD_HOC_CHANNEL;
+       priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
+       priv->radio_on = 1;
+       priv->psmode = LBS802_11POWERMODECAM;
+       priv->psstate = PS_STATE_FULL_POWER;
+       priv->is_deep_sleep = 0;
+       priv->is_auto_deep_sleep_enabled = 0;
+       priv->deep_sleep_required = 0;
+       priv->wakeup_dev_required = 0;
+       init_waitqueue_head(&priv->ds_awake_q);
+       init_waitqueue_head(&priv->scan_q);
+       priv->authtype_auto = 1;
+       priv->is_host_sleep_configured = 0;
+       priv->is_host_sleep_activated = 0;
+       init_waitqueue_head(&priv->host_sleep_q);
+       init_waitqueue_head(&priv->fw_waitq);
+       mutex_init(&priv->lock);
+
+       setup_timer(&priv->command_timer, lbs_cmd_timeout_handler,
+               (unsigned long)priv);
+       setup_timer(&priv->tx_lockup_timer, lbs_tx_lockup_handler,
+               (unsigned long)priv);
+       setup_timer(&priv->auto_deepsleep_timer, auto_deepsleep_timer_fn,
+                       (unsigned long)priv);
+
+       INIT_LIST_HEAD(&priv->cmdfreeq);
+       INIT_LIST_HEAD(&priv->cmdpendingq);
+
+       spin_lock_init(&priv->driver_lock);
+
+       /* Allocate the command buffers */
+       if (lbs_allocate_cmd_buffer(priv)) {
+               pr_err("Out of memory allocating command buffers\n");
+               ret = -ENOMEM;
+               goto out;
+       }
+       priv->resp_idx = 0;
+       priv->resp_len[0] = priv->resp_len[1] = 0;
+
+       /* Create the event FIFO */
+       ret = kfifo_alloc(&priv->event_fifo, sizeof(u32) * 16, GFP_KERNEL);
+       if (ret) {
+               pr_err("Out of memory allocating event FIFO buffer\n");
+               goto out;
+       }
+
+out:
+       lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
+
+       return ret;
+}
+
+static void lbs_free_adapter(struct lbs_private *priv)
+{
+       lbs_deb_enter(LBS_DEB_MAIN);
+
+       lbs_free_cmd_buffer(priv);
+       kfifo_free(&priv->event_fifo);
+       del_timer(&priv->command_timer);
+       del_timer(&priv->tx_lockup_timer);
+       del_timer(&priv->auto_deepsleep_timer);
+
+       lbs_deb_leave(LBS_DEB_MAIN);
+}
+
+static const struct net_device_ops lbs_netdev_ops = {
+       .ndo_open               = lbs_dev_open,
+       .ndo_stop               = lbs_eth_stop,
+       .ndo_start_xmit         = lbs_hard_start_xmit,
+       .ndo_set_mac_address    = lbs_set_mac_address,
+       .ndo_set_rx_mode        = lbs_set_multicast_list,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
+/**
+ * lbs_add_card - adds the card. It will probe the
+ * card, allocate the lbs_priv and initialize the device.
+ *
+ * @card:      A pointer to card
+ * @dmdev:     A pointer to &struct device
+ * returns:    A pointer to &struct lbs_private structure
+ */
+struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
+{
+       struct net_device *dev;
+       struct wireless_dev *wdev;
+       struct lbs_private *priv = NULL;
+
+       lbs_deb_enter(LBS_DEB_MAIN);
+
+       /* Allocate an Ethernet device and register it */
+       wdev = lbs_cfg_alloc(dmdev);
+       if (IS_ERR(wdev)) {
+               pr_err("cfg80211 init failed\n");
+               goto done;
+       }
+
+       wdev->iftype = NL80211_IFTYPE_STATION;
+       priv = wdev_priv(wdev);
+       priv->wdev = wdev;
+
+       if (lbs_init_adapter(priv)) {
+               pr_err("failed to initialize adapter structure\n");
+               goto err_wdev;
+       }
+
+       dev = alloc_netdev(0, "wlan%d", NET_NAME_UNKNOWN, ether_setup);
+       if (!dev) {
+               dev_err(dmdev, "no memory for network device instance\n");
+               goto err_adapter;
+       }
+
+       dev->ieee80211_ptr = wdev;
+       dev->ml_priv = priv;
+       SET_NETDEV_DEV(dev, dmdev);
+       wdev->netdev = dev;
+       priv->dev = dev;
+
+       dev->netdev_ops = &lbs_netdev_ops;
+       dev->watchdog_timeo = 5 * HZ;
+       dev->ethtool_ops = &lbs_ethtool_ops;
+       dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
+
+       priv->card = card;
+
+       strcpy(dev->name, "wlan%d");
+
+       lbs_deb_thread("Starting main thread...\n");
+       init_waitqueue_head(&priv->waitq);
+       priv->main_thread = kthread_run(lbs_thread, dev, "lbs_main");
+       if (IS_ERR(priv->main_thread)) {
+               lbs_deb_thread("Error creating main thread.\n");
+               goto err_ndev;
+       }
+
+       priv->work_thread = create_singlethread_workqueue("lbs_worker");
+       INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker);
+
+       priv->wol_criteria = EHS_REMOVE_WAKEUP;
+       priv->wol_gpio = 0xff;
+       priv->wol_gap = 20;
+       priv->ehs_remove_supported = true;
+
+       goto done;
+
+ err_ndev:
+       free_netdev(dev);
+
+ err_adapter:
+       lbs_free_adapter(priv);
+
+ err_wdev:
+       lbs_cfg_free(priv);
+
+       priv = NULL;
+
+done:
+       lbs_deb_leave_args(LBS_DEB_MAIN, "priv %p", priv);
+       return priv;
+}
+EXPORT_SYMBOL_GPL(lbs_add_card);
+
+
+void lbs_remove_card(struct lbs_private *priv)
+{
+       struct net_device *dev = priv->dev;
+
+       lbs_deb_enter(LBS_DEB_MAIN);
+
+       lbs_remove_mesh(priv);
+
+       if (priv->wiphy_registered)
+               lbs_scan_deinit(priv);
+
+       lbs_wait_for_firmware_load(priv);
+
+       /* worker thread destruction blocks on the in-flight command which
+        * should have been cleared already in lbs_stop_card().
+        */
+       lbs_deb_main("destroying worker thread\n");
+       destroy_workqueue(priv->work_thread);
+       lbs_deb_main("done destroying worker thread\n");
+
+       if (priv->psmode == LBS802_11POWERMODEMAX_PSP) {
+               priv->psmode = LBS802_11POWERMODECAM;
+               lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS, true);
+       }
+
+       if (priv->is_deep_sleep) {
+               priv->is_deep_sleep = 0;
+               wake_up_interruptible(&priv->ds_awake_q);
+       }
+
+       priv->is_host_sleep_configured = 0;
+       priv->is_host_sleep_activated = 0;
+       wake_up_interruptible(&priv->host_sleep_q);
+
+       /* Stop the thread servicing the interrupts */
+       priv->surpriseremoved = 1;
+       kthread_stop(priv->main_thread);
+
+       lbs_free_adapter(priv);
+       lbs_cfg_free(priv);
+       free_netdev(dev);
+
+       lbs_deb_leave(LBS_DEB_MAIN);
+}
+EXPORT_SYMBOL_GPL(lbs_remove_card);
+
+
+int lbs_rtap_supported(struct lbs_private *priv)
+{
+       if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5)
+               return 1;
+
+       /* newer firmware use a capability mask */
+       return ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
+               (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK));
+}
+
+
+int lbs_start_card(struct lbs_private *priv)
+{
+       struct net_device *dev = priv->dev;
+       int ret = -1;
+
+       lbs_deb_enter(LBS_DEB_MAIN);
+
+       /* poke the firmware */
+       ret = lbs_setup_firmware(priv);
+       if (ret)
+               goto done;
+
+       if (!lbs_disablemesh)
+               lbs_init_mesh(priv);
+       else
+               pr_info("%s: mesh disabled\n", dev->name);
+
+       if (lbs_cfg_register(priv)) {
+               pr_err("cannot register device\n");
+               goto done;
+       }
+
+       if (lbs_mesh_activated(priv))
+               lbs_start_mesh(priv);
+
+       lbs_debugfs_init_one(priv, dev);
+
+       netdev_info(dev, "Marvell WLAN 802.11 adapter\n");
+
+       ret = 0;
+
+done:
+       lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(lbs_start_card);
+
+
+void lbs_stop_card(struct lbs_private *priv)
+{
+       struct net_device *dev;
+
+       lbs_deb_enter(LBS_DEB_MAIN);
+
+       if (!priv)
+               goto out;
+       dev = priv->dev;
+
+       /* If the netdev isn't registered, it means that lbs_start_card() was
+        * never called so we have nothing to do here. */
+       if (dev->reg_state != NETREG_REGISTERED)
+               goto out;
+
+       netif_stop_queue(dev);
+       netif_carrier_off(dev);
+
+       lbs_debugfs_remove_one(priv);
+       lbs_deinit_mesh(priv);
+       unregister_netdev(dev);
+
+out:
+       lbs_deb_leave(LBS_DEB_MAIN);
+}
+EXPORT_SYMBOL_GPL(lbs_stop_card);
+
+
+void lbs_queue_event(struct lbs_private *priv, u32 event)
+{
+       unsigned long flags;
+
+       lbs_deb_enter(LBS_DEB_THREAD);
+       spin_lock_irqsave(&priv->driver_lock, flags);
+
+       if (priv->psstate == PS_STATE_SLEEP)
+               priv->psstate = PS_STATE_AWAKE;
+
+       kfifo_in(&priv->event_fifo, (unsigned char *) &event, sizeof(u32));
+
+       wake_up(&priv->waitq);
+
+       spin_unlock_irqrestore(&priv->driver_lock, flags);
+       lbs_deb_leave(LBS_DEB_THREAD);
+}
+EXPORT_SYMBOL_GPL(lbs_queue_event);
+
+void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx)
+{
+       lbs_deb_enter(LBS_DEB_THREAD);
+
+       if (priv->psstate == PS_STATE_SLEEP)
+               priv->psstate = PS_STATE_AWAKE;
+
+       /* Swap buffers by flipping the response index */
+       BUG_ON(resp_idx > 1);
+       priv->resp_idx = resp_idx;
+
+       wake_up(&priv->waitq);
+
+       lbs_deb_leave(LBS_DEB_THREAD);
+}
+EXPORT_SYMBOL_GPL(lbs_notify_command_response);
+
+static int __init lbs_init_module(void)
+{
+       lbs_deb_enter(LBS_DEB_MAIN);
+       memset(&confirm_sleep, 0, sizeof(confirm_sleep));
+       confirm_sleep.hdr.command = cpu_to_le16(CMD_802_11_PS_MODE);
+       confirm_sleep.hdr.size = cpu_to_le16(sizeof(confirm_sleep));
+       confirm_sleep.action = cpu_to_le16(PS_MODE_ACTION_SLEEP_CONFIRMED);
+       lbs_debugfs_init();
+       lbs_deb_leave(LBS_DEB_MAIN);
+       return 0;
+}
+
+static void __exit lbs_exit_module(void)
+{
+       lbs_deb_enter(LBS_DEB_MAIN);
+       lbs_debugfs_remove();
+       lbs_deb_leave(LBS_DEB_MAIN);
+}
+
+module_init(lbs_init_module);
+module_exit(lbs_exit_module);
+
+MODULE_DESCRIPTION("Libertas WLAN Driver Library");
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/marvell/libertas/mesh.c b/drivers/net/wireless/marvell/libertas/mesh.c
new file mode 100644 (file)
index 0000000..d0c881d
--- /dev/null
@@ -0,0 +1,1187 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/hardirq.h>
+#include <linux/netdevice.h>
+#include <linux/if_ether.h>
+#include <linux/if_arp.h>
+#include <linux/kthread.h>
+#include <linux/kfifo.h>
+#include <net/cfg80211.h>
+
+#include "mesh.h"
+#include "decl.h"
+#include "cmd.h"
+
+
+static int lbs_add_mesh(struct lbs_private *priv);
+
+/***************************************************************************
+ * Mesh command handling
+ */
+
+static int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
+                   struct cmd_ds_mesh_access *cmd)
+{
+       int ret;
+
+       lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
+
+       cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS);
+       cmd->hdr.size = cpu_to_le16(sizeof(*cmd));
+       cmd->hdr.result = 0;
+
+       cmd->action = cpu_to_le16(cmd_action);
+
+       ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd);
+
+       lbs_deb_leave(LBS_DEB_CMD);
+       return ret;
+}
+
+static int __lbs_mesh_config_send(struct lbs_private *priv,
+                                 struct cmd_ds_mesh_config *cmd,
+                                 uint16_t action, uint16_t type)
+{
+       int ret;
+       u16 command = CMD_MESH_CONFIG_OLD;
+
+       lbs_deb_enter(LBS_DEB_CMD);
+
+       /*
+        * Command id is 0xac for v10 FW along with mesh interface
+        * id in bits 14-13-12.
+        */
+       if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
+               command = CMD_MESH_CONFIG |
+                         (MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET);
+
+       cmd->hdr.command = cpu_to_le16(command);
+       cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config));
+       cmd->hdr.result = 0;
+
+       cmd->type = cpu_to_le16(type);
+       cmd->action = cpu_to_le16(action);
+
+       ret = lbs_cmd_with_response(priv, command, cmd);
+
+       lbs_deb_leave(LBS_DEB_CMD);
+       return ret;
+}
+
+static int lbs_mesh_config_send(struct lbs_private *priv,
+                        struct cmd_ds_mesh_config *cmd,
+                        uint16_t action, uint16_t type)
+{
+       int ret;
+
+       if (!(priv->fwcapinfo & FW_CAPINFO_PERSISTENT_CONFIG))
+               return -EOPNOTSUPP;
+
+       ret = __lbs_mesh_config_send(priv, cmd, action, type);
+       return ret;
+}
+
+/* This function is the CMD_MESH_CONFIG legacy function.  It only handles the
+ * START and STOP actions.  The extended actions supported by CMD_MESH_CONFIG
+ * are all handled by preparing a struct cmd_ds_mesh_config and passing it to
+ * lbs_mesh_config_send.
+ */
+static int lbs_mesh_config(struct lbs_private *priv, uint16_t action,
+               uint16_t chan)
+{
+       struct cmd_ds_mesh_config cmd;
+       struct mrvl_meshie *ie;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.channel = cpu_to_le16(chan);
+       ie = (struct mrvl_meshie *)cmd.data;
+
+       switch (action) {
+       case CMD_ACT_MESH_CONFIG_START:
+               ie->id = WLAN_EID_VENDOR_SPECIFIC;
+               ie->val.oui[0] = 0x00;
+               ie->val.oui[1] = 0x50;
+               ie->val.oui[2] = 0x43;
+               ie->val.type = MARVELL_MESH_IE_TYPE;
+               ie->val.subtype = MARVELL_MESH_IE_SUBTYPE;
+               ie->val.version = MARVELL_MESH_IE_VERSION;
+               ie->val.active_protocol_id = MARVELL_MESH_PROTO_ID_HWMP;
+               ie->val.active_metric_id = MARVELL_MESH_METRIC_ID;
+               ie->val.mesh_capability = MARVELL_MESH_CAPABILITY;
+               ie->val.mesh_id_len = priv->mesh_ssid_len;
+               memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len);
+               ie->len = sizeof(struct mrvl_meshie_val) -
+                       IEEE80211_MAX_SSID_LEN + priv->mesh_ssid_len;
+               cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val));
+               break;
+       case CMD_ACT_MESH_CONFIG_STOP:
+               break;
+       default:
+               return -1;
+       }
+       lbs_deb_cmd("mesh config action %d type %x channel %d SSID %*pE\n",
+                   action, priv->mesh_tlv, chan, priv->mesh_ssid_len,
+                   priv->mesh_ssid);
+
+       return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
+}
+
+int lbs_mesh_set_channel(struct lbs_private *priv, u8 channel)
+{
+       priv->mesh_channel = channel;
+       return lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, channel);
+}
+
+static uint16_t lbs_mesh_get_channel(struct lbs_private *priv)
+{
+       return priv->mesh_channel ?: 1;
+}
+
+/***************************************************************************
+ * Mesh sysfs support
+ */
+
+/*
+ * Attributes exported through sysfs
+ */
+
+/**
+ * lbs_anycast_get - Get function for sysfs attribute anycast_mask
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
+ */
+static ssize_t lbs_anycast_get(struct device *dev,
+               struct device_attribute *attr, char * buf)
+{
+       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
+       struct cmd_ds_mesh_access mesh_access;
+       int ret;
+
+       memset(&mesh_access, 0, sizeof(mesh_access));
+
+       ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_ANYCAST, &mesh_access);
+       if (ret)
+               return ret;
+
+       return snprintf(buf, 12, "0x%X\n", le32_to_cpu(mesh_access.data[0]));
+}
+
+/**
+ * lbs_anycast_set - Set function for sysfs attribute anycast_mask
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
+ */
+static ssize_t lbs_anycast_set(struct device *dev,
+               struct device_attribute *attr, const char * buf, size_t count)
+{
+       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
+       struct cmd_ds_mesh_access mesh_access;
+       uint32_t datum;
+       int ret;
+
+       memset(&mesh_access, 0, sizeof(mesh_access));
+       sscanf(buf, "%x", &datum);
+       mesh_access.data[0] = cpu_to_le32(datum);
+
+       ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_ANYCAST, &mesh_access);
+       if (ret)
+               return ret;
+
+       return strlen(buf);
+}
+
+/**
+ * lbs_prb_rsp_limit_get - Get function for sysfs attribute prb_rsp_limit
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
+ */
+static ssize_t lbs_prb_rsp_limit_get(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
+       struct cmd_ds_mesh_access mesh_access;
+       int ret;
+       u32 retry_limit;
+
+       memset(&mesh_access, 0, sizeof(mesh_access));
+       mesh_access.data[0] = cpu_to_le32(CMD_ACT_GET);
+
+       ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
+                       &mesh_access);
+       if (ret)
+               return ret;
+
+       retry_limit = le32_to_cpu(mesh_access.data[1]);
+       return snprintf(buf, 10, "%d\n", retry_limit);
+}
+
+/**
+ * lbs_prb_rsp_limit_set - Set function for sysfs attribute prb_rsp_limit
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
+ */
+static ssize_t lbs_prb_rsp_limit_set(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
+       struct cmd_ds_mesh_access mesh_access;
+       int ret;
+       unsigned long retry_limit;
+
+       memset(&mesh_access, 0, sizeof(mesh_access));
+       mesh_access.data[0] = cpu_to_le32(CMD_ACT_SET);
+
+       if (!kstrtoul(buf, 10, &retry_limit))
+               return -ENOTSUPP;
+       if (retry_limit > 15)
+               return -ENOTSUPP;
+
+       mesh_access.data[1] = cpu_to_le32(retry_limit);
+
+       ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
+                       &mesh_access);
+       if (ret)
+               return ret;
+
+       return strlen(buf);
+}
+
+/**
+ * lbs_mesh_get - Get function for sysfs attribute mesh
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
+ */
+static ssize_t lbs_mesh_get(struct device *dev,
+               struct device_attribute *attr, char * buf)
+{
+       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
+       return snprintf(buf, 5, "0x%X\n", !!priv->mesh_dev);
+}
+
+/**
+ * lbs_mesh_set - Set function for sysfs attribute mesh
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
+ */
+static ssize_t lbs_mesh_set(struct device *dev,
+               struct device_attribute *attr, const char * buf, size_t count)
+{
+       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
+       int enable;
+
+       sscanf(buf, "%x", &enable);
+       enable = !!enable;
+       if (enable == !!priv->mesh_dev)
+               return count;
+
+       if (enable)
+               lbs_add_mesh(priv);
+       else
+               lbs_remove_mesh(priv);
+
+       return count;
+}
+
+/*
+ * lbs_mesh attribute to be exported per ethX interface
+ * through sysfs (/sys/class/net/ethX/lbs_mesh)
+ */
+static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set);
+
+/*
+ * anycast_mask attribute to be exported per mshX interface
+ * through sysfs (/sys/class/net/mshX/anycast_mask)
+ */
+static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set);
+
+/*
+ * prb_rsp_limit attribute to be exported per mshX interface
+ * through sysfs (/sys/class/net/mshX/prb_rsp_limit)
+ */
+static DEVICE_ATTR(prb_rsp_limit, 0644, lbs_prb_rsp_limit_get,
+               lbs_prb_rsp_limit_set);
+
+static struct attribute *lbs_mesh_sysfs_entries[] = {
+       &dev_attr_anycast_mask.attr,
+       &dev_attr_prb_rsp_limit.attr,
+       NULL,
+};
+
+static const struct attribute_group lbs_mesh_attr_group = {
+       .attrs = lbs_mesh_sysfs_entries,
+};
+
+
+/***************************************************************************
+ * Persistent configuration support
+ */
+
+static int mesh_get_default_parameters(struct device *dev,
+                                      struct mrvl_mesh_defaults *defs)
+{
+       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
+       struct cmd_ds_mesh_config cmd;
+       int ret;
+
+       memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
+       ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_GET,
+                                  CMD_TYPE_MESH_GET_DEFAULTS);
+
+       if (ret)
+               return -EOPNOTSUPP;
+
+       memcpy(defs, &cmd.data[0], sizeof(struct mrvl_mesh_defaults));
+
+       return 0;
+}
+
+/**
+ * bootflag_get - Get function for sysfs attribute bootflag
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
+ */
+static ssize_t bootflag_get(struct device *dev,
+                           struct device_attribute *attr, char *buf)
+{
+       struct mrvl_mesh_defaults defs;
+       int ret;
+
+       ret = mesh_get_default_parameters(dev, &defs);
+
+       if (ret)
+               return ret;
+
+       return snprintf(buf, 12, "%d\n", le32_to_cpu(defs.bootflag));
+}
+
+/**
+ * bootflag_set - Set function for sysfs attribute bootflag
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
+ */
+static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
+                           const char *buf, size_t count)
+{
+       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
+       struct cmd_ds_mesh_config cmd;
+       uint32_t datum;
+       int ret;
+
+       memset(&cmd, 0, sizeof(cmd));
+       ret = sscanf(buf, "%d", &datum);
+       if ((ret != 1) || (datum > 1))
+               return -EINVAL;
+
+       *((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum);
+       cmd.length = cpu_to_le16(sizeof(uint32_t));
+       ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
+                                  CMD_TYPE_MESH_SET_BOOTFLAG);
+       if (ret)
+               return ret;
+
+       return strlen(buf);
+}
+
+/**
+ * boottime_get - Get function for sysfs attribute boottime
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
+ */
+static ssize_t boottime_get(struct device *dev,
+                           struct device_attribute *attr, char *buf)
+{
+       struct mrvl_mesh_defaults defs;
+       int ret;
+
+       ret = mesh_get_default_parameters(dev, &defs);
+
+       if (ret)
+               return ret;
+
+       return snprintf(buf, 12, "%d\n", defs.boottime);
+}
+
+/**
+ * boottime_set - Set function for sysfs attribute boottime
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
+ */
+static ssize_t boottime_set(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
+       struct cmd_ds_mesh_config cmd;
+       uint32_t datum;
+       int ret;
+
+       memset(&cmd, 0, sizeof(cmd));
+       ret = sscanf(buf, "%d", &datum);
+       if ((ret != 1) || (datum > 255))
+               return -EINVAL;
+
+       /* A too small boot time will result in the device booting into
+        * standalone (no-host) mode before the host can take control of it,
+        * so the change will be hard to revert.  This may be a desired
+        * feature (e.g to configure a very fast boot time for devices that
+        * will not be attached to a host), but dangerous.  So I'm enforcing a
+        * lower limit of 20 seconds:  remove and recompile the driver if this
+        * does not work for you.
+        */
+       datum = (datum < 20) ? 20 : datum;
+       cmd.data[0] = datum;
+       cmd.length = cpu_to_le16(sizeof(uint8_t));
+       ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
+                                  CMD_TYPE_MESH_SET_BOOTTIME);
+       if (ret)
+               return ret;
+
+       return strlen(buf);
+}
+
+/**
+ * channel_get - Get function for sysfs attribute channel
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
+ */
+static ssize_t channel_get(struct device *dev,
+                          struct device_attribute *attr, char *buf)
+{
+       struct mrvl_mesh_defaults defs;
+       int ret;
+
+       ret = mesh_get_default_parameters(dev, &defs);
+
+       if (ret)
+               return ret;
+
+       return snprintf(buf, 12, "%d\n", le16_to_cpu(defs.channel));
+}
+
+/**
+ * channel_set - Set function for sysfs attribute channel
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
+ */
+static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
+                          const char *buf, size_t count)
+{
+       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
+       struct cmd_ds_mesh_config cmd;
+       uint32_t datum;
+       int ret;
+
+       memset(&cmd, 0, sizeof(cmd));
+       ret = sscanf(buf, "%d", &datum);
+       if (ret != 1 || datum < 1 || datum > 11)
+               return -EINVAL;
+
+       *((__le16 *)&cmd.data[0]) = cpu_to_le16(datum);
+       cmd.length = cpu_to_le16(sizeof(uint16_t));
+       ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
+                                  CMD_TYPE_MESH_SET_DEF_CHANNEL);
+       if (ret)
+               return ret;
+
+       return strlen(buf);
+}
+
+/**
+ * mesh_id_get - Get function for sysfs attribute mesh_id
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
+ */
+static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
+                          char *buf)
+{
+       struct mrvl_mesh_defaults defs;
+       int ret;
+
+       ret = mesh_get_default_parameters(dev, &defs);
+
+       if (ret)
+               return ret;
+
+       if (defs.meshie.val.mesh_id_len > IEEE80211_MAX_SSID_LEN) {
+               dev_err(dev, "inconsistent mesh ID length\n");
+               defs.meshie.val.mesh_id_len = IEEE80211_MAX_SSID_LEN;
+       }
+
+       memcpy(buf, defs.meshie.val.mesh_id, defs.meshie.val.mesh_id_len);
+       buf[defs.meshie.val.mesh_id_len] = '\n';
+       buf[defs.meshie.val.mesh_id_len + 1] = '\0';
+
+       return defs.meshie.val.mesh_id_len + 1;
+}
+
+/**
+ * mesh_id_set - Set function for sysfs attribute mesh_id
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
+ */
+static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
+                          const char *buf, size_t count)
+{
+       struct cmd_ds_mesh_config cmd;
+       struct mrvl_mesh_defaults defs;
+       struct mrvl_meshie *ie;
+       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
+       int len;
+       int ret;
+
+       if (count < 2 || count > IEEE80211_MAX_SSID_LEN + 1)
+               return -EINVAL;
+
+       memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
+       ie = (struct mrvl_meshie *) &cmd.data[0];
+
+       /* fetch all other Information Element parameters */
+       ret = mesh_get_default_parameters(dev, &defs);
+
+       cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
+
+       /* transfer IE elements */
+       memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
+
+       len = count - 1;
+       memcpy(ie->val.mesh_id, buf, len);
+       /* SSID len */
+       ie->val.mesh_id_len = len;
+       /* IE len */
+       ie->len = sizeof(struct mrvl_meshie_val) - IEEE80211_MAX_SSID_LEN + len;
+
+       ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
+                                  CMD_TYPE_MESH_SET_MESH_IE);
+       if (ret)
+               return ret;
+
+       return strlen(buf);
+}
+
+/**
+ * protocol_id_get - Get function for sysfs attribute protocol_id
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
+ */
+static ssize_t protocol_id_get(struct device *dev,
+                              struct device_attribute *attr, char *buf)
+{
+       struct mrvl_mesh_defaults defs;
+       int ret;
+
+       ret = mesh_get_default_parameters(dev, &defs);
+
+       if (ret)
+               return ret;
+
+       return snprintf(buf, 5, "%d\n", defs.meshie.val.active_protocol_id);
+}
+
+/**
+ * protocol_id_set - Set function for sysfs attribute protocol_id
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
+ */
+static ssize_t protocol_id_set(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct cmd_ds_mesh_config cmd;
+       struct mrvl_mesh_defaults defs;
+       struct mrvl_meshie *ie;
+       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
+       uint32_t datum;
+       int ret;
+
+       memset(&cmd, 0, sizeof(cmd));
+       ret = sscanf(buf, "%d", &datum);
+       if ((ret != 1) || (datum > 255))
+               return -EINVAL;
+
+       /* fetch all other Information Element parameters */
+       ret = mesh_get_default_parameters(dev, &defs);
+
+       cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
+
+       /* transfer IE elements */
+       ie = (struct mrvl_meshie *) &cmd.data[0];
+       memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
+       /* update protocol id */
+       ie->val.active_protocol_id = datum;
+
+       ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
+                                  CMD_TYPE_MESH_SET_MESH_IE);
+       if (ret)
+               return ret;
+
+       return strlen(buf);
+}
+
+/**
+ * metric_id_get - Get function for sysfs attribute metric_id
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
+ */
+static ssize_t metric_id_get(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct mrvl_mesh_defaults defs;
+       int ret;
+
+       ret = mesh_get_default_parameters(dev, &defs);
+
+       if (ret)
+               return ret;
+
+       return snprintf(buf, 5, "%d\n", defs.meshie.val.active_metric_id);
+}
+
+/**
+ * metric_id_set - Set function for sysfs attribute metric_id
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
+ */
+static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
+                            const char *buf, size_t count)
+{
+       struct cmd_ds_mesh_config cmd;
+       struct mrvl_mesh_defaults defs;
+       struct mrvl_meshie *ie;
+       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
+       uint32_t datum;
+       int ret;
+
+       memset(&cmd, 0, sizeof(cmd));
+       ret = sscanf(buf, "%d", &datum);
+       if ((ret != 1) || (datum > 255))
+               return -EINVAL;
+
+       /* fetch all other Information Element parameters */
+       ret = mesh_get_default_parameters(dev, &defs);
+
+       cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
+
+       /* transfer IE elements */
+       ie = (struct mrvl_meshie *) &cmd.data[0];
+       memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
+       /* update metric id */
+       ie->val.active_metric_id = datum;
+
+       ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
+                                  CMD_TYPE_MESH_SET_MESH_IE);
+       if (ret)
+               return ret;
+
+       return strlen(buf);
+}
+
+/**
+ * capability_get - Get function for sysfs attribute capability
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
+ */
+static ssize_t capability_get(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct mrvl_mesh_defaults defs;
+       int ret;
+
+       ret = mesh_get_default_parameters(dev, &defs);
+
+       if (ret)
+               return ret;
+
+       return snprintf(buf, 5, "%d\n", defs.meshie.val.mesh_capability);
+}
+
+/**
+ * capability_set - Set function for sysfs attribute capability
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
+ */
+static ssize_t capability_set(struct device *dev, struct device_attribute *attr,
+                             const char *buf, size_t count)
+{
+       struct cmd_ds_mesh_config cmd;
+       struct mrvl_mesh_defaults defs;
+       struct mrvl_meshie *ie;
+       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
+       uint32_t datum;
+       int ret;
+
+       memset(&cmd, 0, sizeof(cmd));
+       ret = sscanf(buf, "%d", &datum);
+       if ((ret != 1) || (datum > 255))
+               return -EINVAL;
+
+       /* fetch all other Information Element parameters */
+       ret = mesh_get_default_parameters(dev, &defs);
+
+       cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
+
+       /* transfer IE elements */
+       ie = (struct mrvl_meshie *) &cmd.data[0];
+       memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
+       /* update value */
+       ie->val.mesh_capability = datum;
+
+       ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
+                                  CMD_TYPE_MESH_SET_MESH_IE);
+       if (ret)
+               return ret;
+
+       return strlen(buf);
+}
+
+
+static DEVICE_ATTR(bootflag, 0644, bootflag_get, bootflag_set);
+static DEVICE_ATTR(boottime, 0644, boottime_get, boottime_set);
+static DEVICE_ATTR(channel, 0644, channel_get, channel_set);
+static DEVICE_ATTR(mesh_id, 0644, mesh_id_get, mesh_id_set);
+static DEVICE_ATTR(protocol_id, 0644, protocol_id_get, protocol_id_set);
+static DEVICE_ATTR(metric_id, 0644, metric_id_get, metric_id_set);
+static DEVICE_ATTR(capability, 0644, capability_get, capability_set);
+
+static struct attribute *boot_opts_attrs[] = {
+       &dev_attr_bootflag.attr,
+       &dev_attr_boottime.attr,
+       &dev_attr_channel.attr,
+       NULL
+};
+
+static const struct attribute_group boot_opts_group = {
+       .name = "boot_options",
+       .attrs = boot_opts_attrs,
+};
+
+static struct attribute *mesh_ie_attrs[] = {
+       &dev_attr_mesh_id.attr,
+       &dev_attr_protocol_id.attr,
+       &dev_attr_metric_id.attr,
+       &dev_attr_capability.attr,
+       NULL
+};
+
+static const struct attribute_group mesh_ie_group = {
+       .name = "mesh_ie",
+       .attrs = mesh_ie_attrs,
+};
+
+static void lbs_persist_config_init(struct net_device *dev)
+{
+       int ret;
+       ret = sysfs_create_group(&(dev->dev.kobj), &boot_opts_group);
+       ret = sysfs_create_group(&(dev->dev.kobj), &mesh_ie_group);
+}
+
+static void lbs_persist_config_remove(struct net_device *dev)
+{
+       sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group);
+       sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group);
+}
+
+
+/***************************************************************************
+ * Initializing and starting, stopping mesh
+ */
+
+/*
+ * Check mesh FW version and appropriately send the mesh start
+ * command
+ */
+int lbs_init_mesh(struct lbs_private *priv)
+{
+       int ret = 0;
+
+       lbs_deb_enter(LBS_DEB_MESH);
+
+       /* Determine mesh_fw_ver from fwrelease and fwcapinfo */
+       /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
+       /* 5.110.22 have mesh command with 0xa3 command id */
+       /* 10.0.0.p0 FW brings in mesh config command with different id */
+       /* Check FW version MSB and initialize mesh_fw_ver */
+       if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) {
+               /* Enable mesh, if supported, and work out which TLV it uses.
+                  0x100 + 291 is an unofficial value used in 5.110.20.pXX
+                  0x100 + 37 is the official value used in 5.110.21.pXX
+                  but we check them in that order because 20.pXX doesn't
+                  give an error -- it just silently fails. */
+
+               /* 5.110.20.pXX firmware will fail the command if the channel
+                  doesn't match the existing channel. But only if the TLV
+                  is correct. If the channel is wrong, _BOTH_ versions will
+                  give an error to 0x100+291, and allow 0x100+37 to succeed.
+                  It's just that 5.110.20.pXX will not have done anything
+                  useful */
+
+               priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID;
+               if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1)) {
+                       priv->mesh_tlv = TLV_TYPE_MESH_ID;
+                       if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1))
+                               priv->mesh_tlv = 0;
+               }
+       } else
+       if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
+               (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)) {
+               /* 10.0.0.pXX new firmwares should succeed with TLV
+                * 0x100+37; Do not invoke command with old TLV.
+                */
+               priv->mesh_tlv = TLV_TYPE_MESH_ID;
+               if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1))
+                       priv->mesh_tlv = 0;
+       }
+
+       /* Stop meshing until interface is brought up */
+       lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, 1);
+
+       if (priv->mesh_tlv) {
+               sprintf(priv->mesh_ssid, "mesh");
+               priv->mesh_ssid_len = 4;
+               ret = 1;
+       }
+
+       lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
+       return ret;
+}
+
+void lbs_start_mesh(struct lbs_private *priv)
+{
+       lbs_add_mesh(priv);
+
+       if (device_create_file(&priv->dev->dev, &dev_attr_lbs_mesh))
+               netdev_err(priv->dev, "cannot register lbs_mesh attribute\n");
+}
+
+int lbs_deinit_mesh(struct lbs_private *priv)
+{
+       struct net_device *dev = priv->dev;
+       int ret = 0;
+
+       lbs_deb_enter(LBS_DEB_MESH);
+
+       if (priv->mesh_tlv) {
+               device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
+               ret = 1;
+       }
+
+       lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
+       return ret;
+}
+
+
+/**
+ * lbs_mesh_stop - close the mshX interface
+ *
+ * @dev:       A pointer to &net_device structure
+ * returns:    0
+ */
+static int lbs_mesh_stop(struct net_device *dev)
+{
+       struct lbs_private *priv = dev->ml_priv;
+
+       lbs_deb_enter(LBS_DEB_MESH);
+       lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP,
+               lbs_mesh_get_channel(priv));
+
+       spin_lock_irq(&priv->driver_lock);
+
+       netif_stop_queue(dev);
+       netif_carrier_off(dev);
+
+       spin_unlock_irq(&priv->driver_lock);
+
+       lbs_update_mcast(priv);
+       if (!lbs_iface_active(priv))
+               lbs_stop_iface(priv);
+
+       lbs_deb_leave(LBS_DEB_MESH);
+       return 0;
+}
+
+/**
+ * lbs_mesh_dev_open - open the mshX interface
+ *
+ * @dev:       A pointer to &net_device structure
+ * returns:    0 or -EBUSY if monitor mode active
+ */
+static int lbs_mesh_dev_open(struct net_device *dev)
+{
+       struct lbs_private *priv = dev->ml_priv;
+       int ret = 0;
+
+       lbs_deb_enter(LBS_DEB_NET);
+       if (!priv->iface_running) {
+               ret = lbs_start_iface(priv);
+               if (ret)
+                       goto out;
+       }
+
+       spin_lock_irq(&priv->driver_lock);
+
+       if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
+               ret = -EBUSY;
+               spin_unlock_irq(&priv->driver_lock);
+               goto out;
+       }
+
+       netif_carrier_on(dev);
+
+       if (!priv->tx_pending_len)
+               netif_wake_queue(dev);
+
+       spin_unlock_irq(&priv->driver_lock);
+
+       ret = lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
+               lbs_mesh_get_channel(priv));
+
+out:
+       lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
+       return ret;
+}
+
+static const struct net_device_ops mesh_netdev_ops = {
+       .ndo_open               = lbs_mesh_dev_open,
+       .ndo_stop               = lbs_mesh_stop,
+       .ndo_start_xmit         = lbs_hard_start_xmit,
+       .ndo_set_mac_address    = lbs_set_mac_address,
+       .ndo_set_rx_mode        = lbs_set_multicast_list,
+};
+
+/**
+ * lbs_add_mesh - add mshX interface
+ *
+ * @priv:      A pointer to the &struct lbs_private structure
+ * returns:    0 if successful, -X otherwise
+ */
+static int lbs_add_mesh(struct lbs_private *priv)
+{
+       struct net_device *mesh_dev = NULL;
+       struct wireless_dev *mesh_wdev;
+       int ret = 0;
+
+       lbs_deb_enter(LBS_DEB_MESH);
+
+       /* Allocate a virtual mesh device */
+       mesh_wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
+       if (!mesh_wdev) {
+               lbs_deb_mesh("init mshX wireless device failed\n");
+               ret = -ENOMEM;
+               goto done;
+       }
+
+       mesh_dev = alloc_netdev(0, "msh%d", NET_NAME_UNKNOWN, ether_setup);
+       if (!mesh_dev) {
+               lbs_deb_mesh("init mshX device failed\n");
+               ret = -ENOMEM;
+               goto err_free_wdev;
+       }
+
+       mesh_wdev->iftype = NL80211_IFTYPE_MESH_POINT;
+       mesh_wdev->wiphy = priv->wdev->wiphy;
+       mesh_wdev->netdev = mesh_dev;
+
+       mesh_dev->ml_priv = priv;
+       mesh_dev->ieee80211_ptr = mesh_wdev;
+       priv->mesh_dev = mesh_dev;
+
+       mesh_dev->netdev_ops = &mesh_netdev_ops;
+       mesh_dev->ethtool_ops = &lbs_ethtool_ops;
+       eth_hw_addr_inherit(mesh_dev, priv->dev);
+
+       SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent);
+
+       mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
+       /* Register virtual mesh interface */
+       ret = register_netdev(mesh_dev);
+       if (ret) {
+               pr_err("cannot register mshX virtual interface\n");
+               goto err_free_netdev;
+       }
+
+       ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
+       if (ret)
+               goto err_unregister;
+
+       lbs_persist_config_init(mesh_dev);
+
+       /* Everything successful */
+       ret = 0;
+       goto done;
+
+err_unregister:
+       unregister_netdev(mesh_dev);
+
+err_free_netdev:
+       free_netdev(mesh_dev);
+
+err_free_wdev:
+       kfree(mesh_wdev);
+
+done:
+       lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
+       return ret;
+}
+
+void lbs_remove_mesh(struct lbs_private *priv)
+{
+       struct net_device *mesh_dev;
+
+       mesh_dev = priv->mesh_dev;
+       if (!mesh_dev)
+               return;
+
+       lbs_deb_enter(LBS_DEB_MESH);
+       netif_stop_queue(mesh_dev);
+       netif_carrier_off(mesh_dev);
+       sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
+       lbs_persist_config_remove(mesh_dev);
+       unregister_netdev(mesh_dev);
+       priv->mesh_dev = NULL;
+       kfree(mesh_dev->ieee80211_ptr);
+       free_netdev(mesh_dev);
+       lbs_deb_leave(LBS_DEB_MESH);
+}
+
+
+/***************************************************************************
+ * Sending and receiving
+ */
+struct net_device *lbs_mesh_set_dev(struct lbs_private *priv,
+       struct net_device *dev, struct rxpd *rxpd)
+{
+       if (priv->mesh_dev) {
+               if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID) {
+                       if (rxpd->rx_control & RxPD_MESH_FRAME)
+                               dev = priv->mesh_dev;
+               } else if (priv->mesh_tlv == TLV_TYPE_MESH_ID) {
+                       if (rxpd->u.bss.bss_num == MESH_IFACE_ID)
+                               dev = priv->mesh_dev;
+               }
+       }
+       return dev;
+}
+
+
+void lbs_mesh_set_txpd(struct lbs_private *priv,
+       struct net_device *dev, struct txpd *txpd)
+{
+       if (dev == priv->mesh_dev) {
+               if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID)
+                       txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
+               else if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
+                       txpd->u.bss.bss_num = MESH_IFACE_ID;
+       }
+}
+
+
+/***************************************************************************
+ * Ethtool related
+ */
+
+static const char * const mesh_stat_strings[] = {
+                       "drop_duplicate_bcast",
+                       "drop_ttl_zero",
+                       "drop_no_fwd_route",
+                       "drop_no_buffers",
+                       "fwded_unicast_cnt",
+                       "fwded_bcast_cnt",
+                       "drop_blind_table",
+                       "tx_failed_cnt"
+};
+
+void lbs_mesh_ethtool_get_stats(struct net_device *dev,
+       struct ethtool_stats *stats, uint64_t *data)
+{
+       struct lbs_private *priv = dev->ml_priv;
+       struct cmd_ds_mesh_access mesh_access;
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_ETHTOOL);
+
+       /* Get Mesh Statistics */
+       ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_STATS, &mesh_access);
+
+       if (ret) {
+               memset(data, 0, MESH_STATS_NUM*(sizeof(uint64_t)));
+               return;
+       }
+
+       priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]);
+       priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]);
+       priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]);
+       priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]);
+       priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]);
+       priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]);
+       priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]);
+       priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]);
+
+       data[0] = priv->mstats.fwd_drop_rbt;
+       data[1] = priv->mstats.fwd_drop_ttl;
+       data[2] = priv->mstats.fwd_drop_noroute;
+       data[3] = priv->mstats.fwd_drop_nobuf;
+       data[4] = priv->mstats.fwd_unicast_cnt;
+       data[5] = priv->mstats.fwd_bcast_cnt;
+       data[6] = priv->mstats.drop_blind;
+       data[7] = priv->mstats.tx_failed_cnt;
+
+       lbs_deb_enter(LBS_DEB_ETHTOOL);
+}
+
+int lbs_mesh_ethtool_get_sset_count(struct net_device *dev, int sset)
+{
+       struct lbs_private *priv = dev->ml_priv;
+
+       if (sset == ETH_SS_STATS && dev == priv->mesh_dev)
+               return MESH_STATS_NUM;
+
+       return -EOPNOTSUPP;
+}
+
+void lbs_mesh_ethtool_get_strings(struct net_device *dev,
+       uint32_t stringset, uint8_t *s)
+{
+       int i;
+
+       lbs_deb_enter(LBS_DEB_ETHTOOL);
+
+       switch (stringset) {
+       case ETH_SS_STATS:
+               for (i = 0; i < MESH_STATS_NUM; i++) {
+                       memcpy(s + i * ETH_GSTRING_LEN,
+                                       mesh_stat_strings[i],
+                                       ETH_GSTRING_LEN);
+               }
+               break;
+       }
+       lbs_deb_enter(LBS_DEB_ETHTOOL);
+}
diff --git a/drivers/net/wireless/marvell/libertas/mesh.h b/drivers/net/wireless/marvell/libertas/mesh.h
new file mode 100644 (file)
index 0000000..6603f34
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Contains all definitions needed for the Libertas' MESH implementation.
+ */
+#ifndef _LBS_MESH_H_
+#define _LBS_MESH_H_
+
+
+#include <net/iw_handler.h>
+#include <net/lib80211.h>
+
+#include "host.h"
+#include "dev.h"
+
+#ifdef CONFIG_LIBERTAS_MESH
+
+struct net_device;
+
+int lbs_init_mesh(struct lbs_private *priv);
+void lbs_start_mesh(struct lbs_private *priv);
+int lbs_deinit_mesh(struct lbs_private *priv);
+
+void lbs_remove_mesh(struct lbs_private *priv);
+
+static inline bool lbs_mesh_activated(struct lbs_private *priv)
+{
+       /* Mesh SSID is only programmed after successful init */
+       return priv->mesh_ssid_len != 0;
+}
+
+int lbs_mesh_set_channel(struct lbs_private *priv, u8 channel);
+
+/* Sending / Receiving */
+
+struct rxpd;
+struct txpd;
+
+struct net_device *lbs_mesh_set_dev(struct lbs_private *priv,
+       struct net_device *dev, struct rxpd *rxpd);
+void lbs_mesh_set_txpd(struct lbs_private *priv,
+       struct net_device *dev, struct txpd *txpd);
+
+
+/* Command handling */
+
+struct cmd_ds_command;
+struct cmd_ds_mesh_access;
+struct cmd_ds_mesh_config;
+
+
+/* Ethtool statistics */
+
+struct ethtool_stats;
+
+void lbs_mesh_ethtool_get_stats(struct net_device *dev,
+       struct ethtool_stats *stats, uint64_t *data);
+int lbs_mesh_ethtool_get_sset_count(struct net_device *dev, int sset);
+void lbs_mesh_ethtool_get_strings(struct net_device *dev,
+       uint32_t stringset, uint8_t *s);
+
+
+#else
+
+#define lbs_init_mesh(priv)
+#define lbs_deinit_mesh(priv)
+#define lbs_start_mesh(priv)
+#define lbs_add_mesh(priv)
+#define lbs_remove_mesh(priv)
+#define lbs_mesh_set_dev(priv, dev, rxpd) (dev)
+#define lbs_mesh_set_txpd(priv, dev, txpd)
+#define lbs_mesh_set_channel(priv, channel) (0)
+#define lbs_mesh_activated(priv) (false)
+
+#endif
+
+
+
+#endif
diff --git a/drivers/net/wireless/marvell/libertas/radiotap.h b/drivers/net/wireless/marvell/libertas/radiotap.h
new file mode 100644 (file)
index 0000000..b3c8ea6
--- /dev/null
@@ -0,0 +1,44 @@
+#include <net/ieee80211_radiotap.h>
+
+struct tx_radiotap_hdr {
+       struct ieee80211_radiotap_header hdr;
+       u8 rate;
+       u8 txpower;
+       u8 rts_retries;
+       u8 data_retries;
+} __packed;
+
+#define TX_RADIOTAP_PRESENT (                          \
+       (1 << IEEE80211_RADIOTAP_RATE) |                \
+       (1 << IEEE80211_RADIOTAP_DBM_TX_POWER) |        \
+       (1 << IEEE80211_RADIOTAP_RTS_RETRIES) |         \
+       (1 << IEEE80211_RADIOTAP_DATA_RETRIES)  |       \
+       0)
+
+#define IEEE80211_FC_VERSION_MASK    0x0003
+#define IEEE80211_FC_TYPE_MASK       0x000c
+#define IEEE80211_FC_TYPE_MGT        0x0000
+#define IEEE80211_FC_TYPE_CTL        0x0004
+#define IEEE80211_FC_TYPE_DATA       0x0008
+#define IEEE80211_FC_SUBTYPE_MASK    0x00f0
+#define IEEE80211_FC_TOFROMDS_MASK   0x0300
+#define IEEE80211_FC_TODS_MASK       0x0100
+#define IEEE80211_FC_FROMDS_MASK     0x0200
+#define IEEE80211_FC_NODS            0x0000
+#define IEEE80211_FC_TODS            0x0100
+#define IEEE80211_FC_FROMDS          0x0200
+#define IEEE80211_FC_DSTODS          0x0300
+
+struct rx_radiotap_hdr {
+       struct ieee80211_radiotap_header hdr;
+       u8 flags;
+       u8 rate;
+       u8 antsignal;
+} __packed;
+
+#define RX_RADIOTAP_PRESENT (                  \
+       (1 << IEEE80211_RADIOTAP_FLAGS) |       \
+       (1 << IEEE80211_RADIOTAP_RATE) |        \
+       (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) |\
+       0)
+
diff --git a/drivers/net/wireless/marvell/libertas/rx.c b/drivers/net/wireless/marvell/libertas/rx.c
new file mode 100644 (file)
index 0000000..e446fed
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+ * This file contains the handling of RX in wlan driver.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/etherdevice.h>
+#include <linux/hardirq.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/export.h>
+#include <net/cfg80211.h>
+
+#include "defs.h"
+#include "host.h"
+#include "radiotap.h"
+#include "decl.h"
+#include "dev.h"
+#include "mesh.h"
+
+struct eth803hdr {
+       u8 dest_addr[6];
+       u8 src_addr[6];
+       u16 h803_len;
+} __packed;
+
+struct rfc1042hdr {
+       u8 llc_dsap;
+       u8 llc_ssap;
+       u8 llc_ctrl;
+       u8 snap_oui[3];
+       u16 snap_type;
+} __packed;
+
+struct rxpackethdr {
+       struct eth803hdr eth803_hdr;
+       struct rfc1042hdr rfc1042_hdr;
+} __packed;
+
+struct rx80211packethdr {
+       struct rxpd rx_pd;
+       void *eth80211_hdr;
+} __packed;
+
+static int process_rxed_802_11_packet(struct lbs_private *priv,
+       struct sk_buff *skb);
+
+/**
+ * lbs_process_rxed_packet - processes received packet and forwards it
+ * to kernel/upper layer
+ *
+ * @priv:      A pointer to &struct lbs_private
+ * @skb:       A pointer to skb which includes the received packet
+ * returns:    0 or -1
+ */
+int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
+{
+       int ret = 0;
+       struct net_device *dev = priv->dev;
+       struct rxpackethdr *p_rx_pkt;
+       struct rxpd *p_rx_pd;
+       int hdrchop;
+       struct ethhdr *p_ethhdr;
+       static const u8 rfc1042_eth_hdr[] = {
+               0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00
+       };
+
+       lbs_deb_enter(LBS_DEB_RX);
+
+       BUG_ON(!skb);
+
+       skb->ip_summed = CHECKSUM_NONE;
+
+       if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
+               ret = process_rxed_802_11_packet(priv, skb);
+               goto done;
+       }
+
+       p_rx_pd = (struct rxpd *) skb->data;
+       p_rx_pkt = (struct rxpackethdr *) ((u8 *)p_rx_pd +
+               le32_to_cpu(p_rx_pd->pkt_ptr));
+
+       dev = lbs_mesh_set_dev(priv, dev, p_rx_pd);
+
+       lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data,
+                min_t(unsigned int, skb->len, 100));
+
+       if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
+               lbs_deb_rx("rx err: frame received with bad length\n");
+               dev->stats.rx_length_errors++;
+               ret = -EINVAL;
+               dev_kfree_skb(skb);
+               goto done;
+       }
+
+       lbs_deb_rx("rx data: skb->len - pkt_ptr = %d-%zd = %zd\n",
+               skb->len, (size_t)le32_to_cpu(p_rx_pd->pkt_ptr),
+               skb->len - (size_t)le32_to_cpu(p_rx_pd->pkt_ptr));
+
+       lbs_deb_hex(LBS_DEB_RX, "RX Data: Dest", p_rx_pkt->eth803_hdr.dest_addr,
+               sizeof(p_rx_pkt->eth803_hdr.dest_addr));
+       lbs_deb_hex(LBS_DEB_RX, "RX Data: Src", p_rx_pkt->eth803_hdr.src_addr,
+               sizeof(p_rx_pkt->eth803_hdr.src_addr));
+
+       if (memcmp(&p_rx_pkt->rfc1042_hdr,
+                  rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) {
+               /*
+                *  Replace the 803 header and rfc1042 header (llc/snap) with an
+                *    EthernetII header, keep the src/dst and snap_type (ethertype)
+                *
+                *  The firmware only passes up SNAP frames converting
+                *    all RX Data from 802.11 to 802.2/LLC/SNAP frames.
+                *
+                *  To create the Ethernet II, just move the src, dst address right
+                *    before the snap_type.
+                */
+               p_ethhdr = (struct ethhdr *)
+                   ((u8 *) &p_rx_pkt->eth803_hdr
+                    + sizeof(p_rx_pkt->eth803_hdr) + sizeof(p_rx_pkt->rfc1042_hdr)
+                    - sizeof(p_rx_pkt->eth803_hdr.dest_addr)
+                    - sizeof(p_rx_pkt->eth803_hdr.src_addr)
+                    - sizeof(p_rx_pkt->rfc1042_hdr.snap_type));
+
+               memcpy(p_ethhdr->h_source, p_rx_pkt->eth803_hdr.src_addr,
+                      sizeof(p_ethhdr->h_source));
+               memcpy(p_ethhdr->h_dest, p_rx_pkt->eth803_hdr.dest_addr,
+                      sizeof(p_ethhdr->h_dest));
+
+               /* Chop off the rxpd + the excess memory from the 802.2/llc/snap header
+                *   that was removed
+                */
+               hdrchop = (u8 *)p_ethhdr - (u8 *)p_rx_pd;
+       } else {
+               lbs_deb_hex(LBS_DEB_RX, "RX Data: LLC/SNAP",
+                       (u8 *) &p_rx_pkt->rfc1042_hdr,
+                       sizeof(p_rx_pkt->rfc1042_hdr));
+
+               /* Chop off the rxpd */
+               hdrchop = (u8 *)&p_rx_pkt->eth803_hdr - (u8 *)p_rx_pd;
+       }
+
+       /* Chop off the leading header bytes so the skb points to the start of
+        *   either the reconstructed EthII frame or the 802.2/llc/snap frame
+        */
+       skb_pull(skb, hdrchop);
+
+       priv->cur_rate = lbs_fw_index_to_data_rate(p_rx_pd->rx_rate);
+
+       lbs_deb_rx("rx data: size of actual packet %d\n", skb->len);
+       dev->stats.rx_bytes += skb->len;
+       dev->stats.rx_packets++;
+
+       skb->protocol = eth_type_trans(skb, dev);
+       if (in_interrupt())
+               netif_rx(skb);
+       else
+               netif_rx_ni(skb);
+
+       ret = 0;
+done:
+       lbs_deb_leave_args(LBS_DEB_RX, "ret %d", ret);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(lbs_process_rxed_packet);
+
+/**
+ * convert_mv_rate_to_radiotap - converts Tx/Rx rates from Marvell WLAN format
+ * (see Table 2 in Section 3.1) to IEEE80211_RADIOTAP_RATE units (500 Kb/s)
+ *
+ * @rate:      Input rate
+ * returns:    Output Rate (0 if invalid)
+ */
+static u8 convert_mv_rate_to_radiotap(u8 rate)
+{
+       switch (rate) {
+       case 0:         /*   1 Mbps */
+               return 2;
+       case 1:         /*   2 Mbps */
+               return 4;
+       case 2:         /* 5.5 Mbps */
+               return 11;
+       case 3:         /*  11 Mbps */
+               return 22;
+       /* case 4: reserved */
+       case 5:         /*   6 Mbps */
+               return 12;
+       case 6:         /*   9 Mbps */
+               return 18;
+       case 7:         /*  12 Mbps */
+               return 24;
+       case 8:         /*  18 Mbps */
+               return 36;
+       case 9:         /*  24 Mbps */
+               return 48;
+       case 10:                /*  36 Mbps */
+               return 72;
+       case 11:                /*  48 Mbps */
+               return 96;
+       case 12:                /*  54 Mbps */
+               return 108;
+       }
+       pr_alert("Invalid Marvell WLAN rate %i\n", rate);
+       return 0;
+}
+
+/**
+ * process_rxed_802_11_packet - processes a received 802.11 packet and forwards
+ * it to kernel/upper layer
+ *
+ * @priv:      A pointer to &struct lbs_private
+ * @skb:       A pointer to skb which includes the received packet
+ * returns:    0 or -1
+ */
+static int process_rxed_802_11_packet(struct lbs_private *priv,
+       struct sk_buff *skb)
+{
+       int ret = 0;
+       struct net_device *dev = priv->dev;
+       struct rx80211packethdr *p_rx_pkt;
+       struct rxpd *prxpd;
+       struct rx_radiotap_hdr radiotap_hdr;
+       struct rx_radiotap_hdr *pradiotap_hdr;
+
+       lbs_deb_enter(LBS_DEB_RX);
+
+       p_rx_pkt = (struct rx80211packethdr *) skb->data;
+       prxpd = &p_rx_pkt->rx_pd;
+
+       /* lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data, min(skb->len, 100)); */
+
+       if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
+               lbs_deb_rx("rx err: frame received with bad length\n");
+               dev->stats.rx_length_errors++;
+               ret = -EINVAL;
+               kfree_skb(skb);
+               goto done;
+       }
+
+       lbs_deb_rx("rx data: skb->len-sizeof(RxPd) = %d-%zd = %zd\n",
+              skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
+
+       /* create the exported radio header */
+
+       /* radiotap header */
+       memset(&radiotap_hdr, 0, sizeof(radiotap_hdr));
+       /* XXX must check radiotap_hdr.hdr.it_pad for pad */
+       radiotap_hdr.hdr.it_len = cpu_to_le16 (sizeof(struct rx_radiotap_hdr));
+       radiotap_hdr.hdr.it_present = cpu_to_le32 (RX_RADIOTAP_PRESENT);
+       radiotap_hdr.rate = convert_mv_rate_to_radiotap(prxpd->rx_rate);
+       /* XXX must check no carryout */
+       radiotap_hdr.antsignal = prxpd->snr + prxpd->nf;
+
+       /* chop the rxpd */
+       skb_pull(skb, sizeof(struct rxpd));
+
+       /* add space for the new radio header */
+       if ((skb_headroom(skb) < sizeof(struct rx_radiotap_hdr)) &&
+           pskb_expand_head(skb, sizeof(struct rx_radiotap_hdr), 0, GFP_ATOMIC)) {
+               netdev_alert(dev, "%s: couldn't pskb_expand_head\n", __func__);
+               ret = -ENOMEM;
+               kfree_skb(skb);
+               goto done;
+       }
+
+       pradiotap_hdr = (void *)skb_push(skb, sizeof(struct rx_radiotap_hdr));
+       memcpy(pradiotap_hdr, &radiotap_hdr, sizeof(struct rx_radiotap_hdr));
+
+       priv->cur_rate = lbs_fw_index_to_data_rate(prxpd->rx_rate);
+
+       lbs_deb_rx("rx data: size of actual packet %d\n", skb->len);
+       dev->stats.rx_bytes += skb->len;
+       dev->stats.rx_packets++;
+
+       skb->protocol = eth_type_trans(skb, priv->dev);
+
+       if (in_interrupt())
+               netif_rx(skb);
+       else
+               netif_rx_ni(skb);
+
+       ret = 0;
+
+done:
+       lbs_deb_leave_args(LBS_DEB_RX, "ret %d", ret);
+       return ret;
+}
diff --git a/drivers/net/wireless/marvell/libertas/tx.c b/drivers/net/wireless/marvell/libertas/tx.c
new file mode 100644 (file)
index 0000000..c025f9c
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * This file contains the handling of TX in wlan driver.
+ */
+#include <linux/hardirq.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/sched.h>
+#include <linux/export.h>
+#include <net/cfg80211.h>
+
+#include "host.h"
+#include "radiotap.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "mesh.h"
+
+/**
+ * convert_radiotap_rate_to_mv - converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE
+ * units (500 Kb/s) into Marvell WLAN format (see Table 8 in Section 3.2.1)
+ *
+ * @rate:      Input rate
+ * returns:    Output Rate (0 if invalid)
+ */
+static u32 convert_radiotap_rate_to_mv(u8 rate)
+{
+       switch (rate) {
+       case 2:         /*   1 Mbps */
+               return 0 | (1 << 4);
+       case 4:         /*   2 Mbps */
+               return 1 | (1 << 4);
+       case 11:                /* 5.5 Mbps */
+               return 2 | (1 << 4);
+       case 22:                /*  11 Mbps */
+               return 3 | (1 << 4);
+       case 12:                /*   6 Mbps */
+               return 4 | (1 << 4);
+       case 18:                /*   9 Mbps */
+               return 5 | (1 << 4);
+       case 24:                /*  12 Mbps */
+               return 6 | (1 << 4);
+       case 36:                /*  18 Mbps */
+               return 7 | (1 << 4);
+       case 48:                /*  24 Mbps */
+               return 8 | (1 << 4);
+       case 72:                /*  36 Mbps */
+               return 9 | (1 << 4);
+       case 96:                /*  48 Mbps */
+               return 10 | (1 << 4);
+       case 108:               /*  54 Mbps */
+               return 11 | (1 << 4);
+       }
+       return 0;
+}
+
+/**
+ * lbs_hard_start_xmit - checks the conditions and sends packet to IF
+ * layer if everything is ok
+ *
+ * @skb:       A pointer to skb which includes TX packet
+ * @dev:       A pointer to the &struct net_device
+ * returns:    0 or -1
+ */
+netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       unsigned long flags;
+       struct lbs_private *priv = dev->ml_priv;
+       struct txpd *txpd;
+       char *p802x_hdr;
+       uint16_t pkt_len;
+       netdev_tx_t ret = NETDEV_TX_OK;
+
+       lbs_deb_enter(LBS_DEB_TX);
+
+       /* We need to protect against the queues being restarted before
+          we get round to stopping them */
+       spin_lock_irqsave(&priv->driver_lock, flags);
+
+       if (priv->surpriseremoved)
+               goto free;
+
+       if (!skb->len || (skb->len > MRVDRV_ETH_TX_PACKET_BUFFER_SIZE)) {
+               lbs_deb_tx("tx err: skb length %d 0 or > %zd\n",
+                      skb->len, MRVDRV_ETH_TX_PACKET_BUFFER_SIZE);
+               /* We'll never manage to send this one; drop it and return 'OK' */
+
+               dev->stats.tx_dropped++;
+               dev->stats.tx_errors++;
+               goto free;
+       }
+
+
+       netif_stop_queue(priv->dev);
+       if (priv->mesh_dev)
+               netif_stop_queue(priv->mesh_dev);
+
+       if (priv->tx_pending_len) {
+               /* This can happen if packets come in on the mesh and eth
+                  device simultaneously -- there's no mutual exclusion on
+                  hard_start_xmit() calls between devices. */
+               lbs_deb_tx("Packet on %s while busy\n", dev->name);
+               ret = NETDEV_TX_BUSY;
+               goto unlock;
+       }
+
+       priv->tx_pending_len = -1;
+       spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+       lbs_deb_hex(LBS_DEB_TX, "TX Data", skb->data, min_t(unsigned int, skb->len, 100));
+
+       txpd = (void *)priv->tx_pending_buf;
+       memset(txpd, 0, sizeof(struct txpd));
+
+       p802x_hdr = skb->data;
+       pkt_len = skb->len;
+
+       if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
+               struct tx_radiotap_hdr *rtap_hdr = (void *)skb->data;
+
+               /* set txpd fields from the radiotap header */
+               txpd->tx_control = cpu_to_le32(convert_radiotap_rate_to_mv(rtap_hdr->rate));
+
+               /* skip the radiotap header */
+               p802x_hdr += sizeof(*rtap_hdr);
+               pkt_len -= sizeof(*rtap_hdr);
+
+               /* copy destination address from 802.11 header */
+               memcpy(txpd->tx_dest_addr_high, p802x_hdr + 4, ETH_ALEN);
+       } else {
+               /* copy destination address from 802.3 header */
+               memcpy(txpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN);
+       }
+
+       txpd->tx_packet_length = cpu_to_le16(pkt_len);
+       txpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd));
+
+       lbs_mesh_set_txpd(priv, dev, txpd);
+
+       lbs_deb_hex(LBS_DEB_TX, "txpd", (u8 *) &txpd, sizeof(struct txpd));
+
+       lbs_deb_hex(LBS_DEB_TX, "Tx Data", (u8 *) p802x_hdr, le16_to_cpu(txpd->tx_packet_length));
+
+       memcpy(&txpd[1], p802x_hdr, le16_to_cpu(txpd->tx_packet_length));
+
+       spin_lock_irqsave(&priv->driver_lock, flags);
+       priv->tx_pending_len = pkt_len + sizeof(struct txpd);
+
+       lbs_deb_tx("%s lined up packet\n", __func__);
+
+       dev->stats.tx_packets++;
+       dev->stats.tx_bytes += skb->len;
+
+       if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
+               /* Keep the skb to echo it back once Tx feedback is
+                  received from FW */
+               skb_orphan(skb);
+
+               /* Keep the skb around for when we get feedback */
+               priv->currenttxskb = skb;
+       } else {
+ free:
+               dev_kfree_skb_any(skb);
+       }
+
+ unlock:
+       spin_unlock_irqrestore(&priv->driver_lock, flags);
+       wake_up(&priv->waitq);
+
+       lbs_deb_leave_args(LBS_DEB_TX, "ret %d", ret);
+       return ret;
+}
+
+/**
+ * lbs_send_tx_feedback - sends to the host the last transmitted packet,
+ * filling the radiotap headers with transmission information.
+ *
+ * @priv:      A pointer to &struct lbs_private structure
+ * @try_count: A 32-bit value containing transmission retry status.
+ *
+ * returns:    void
+ */
+void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count)
+{
+       struct tx_radiotap_hdr *radiotap_hdr;
+
+       if (priv->wdev->iftype != NL80211_IFTYPE_MONITOR ||
+           priv->currenttxskb == NULL)
+               return;
+
+       radiotap_hdr = (struct tx_radiotap_hdr *)priv->currenttxskb->data;
+
+       radiotap_hdr->data_retries = try_count ?
+               (1 + priv->txretrycount - try_count) : 0;
+
+       priv->currenttxskb->protocol = eth_type_trans(priv->currenttxskb,
+                                                     priv->dev);
+       netif_rx(priv->currenttxskb);
+
+       priv->currenttxskb = NULL;
+
+       if (priv->connect_status == LBS_CONNECTED)
+               netif_wake_queue(priv->dev);
+
+       if (priv->mesh_dev && netif_running(priv->mesh_dev))
+               netif_wake_queue(priv->mesh_dev);
+}
+EXPORT_SYMBOL_GPL(lbs_send_tx_feedback);
diff --git a/drivers/net/wireless/marvell/libertas/types.h b/drivers/net/wireless/marvell/libertas/types.h
new file mode 100644 (file)
index 0000000..cf1d9b0
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * This header file contains definition for global types
+ */
+#ifndef _LBS_TYPES_H_
+#define _LBS_TYPES_H_
+
+#include <linux/if_ether.h>
+#include <linux/ieee80211.h>
+#include <asm/byteorder.h>
+
+struct ieee_ie_header {
+       u8 id;
+       u8 len;
+} __packed;
+
+struct ieee_ie_cf_param_set {
+       struct ieee_ie_header header;
+
+       u8 cfpcnt;
+       u8 cfpperiod;
+       __le16 cfpmaxduration;
+       __le16 cfpdurationremaining;
+} __packed;
+
+
+struct ieee_ie_ibss_param_set {
+       struct ieee_ie_header header;
+
+       __le16 atimwindow;
+} __packed;
+
+union ieee_ss_param_set {
+       struct ieee_ie_cf_param_set cf;
+       struct ieee_ie_ibss_param_set ibss;
+} __packed;
+
+struct ieee_ie_fh_param_set {
+       struct ieee_ie_header header;
+
+       __le16 dwelltime;
+       u8 hopset;
+       u8 hoppattern;
+       u8 hopindex;
+} __packed;
+
+struct ieee_ie_ds_param_set {
+       struct ieee_ie_header header;
+
+       u8 channel;
+} __packed;
+
+union ieee_phy_param_set {
+       struct ieee_ie_fh_param_set fh;
+       struct ieee_ie_ds_param_set ds;
+} __packed;
+
+/* TLV  type ID definition */
+#define PROPRIETARY_TLV_BASE_ID                0x0100
+
+/* Terminating TLV type */
+#define MRVL_TERMINATE_TLV_ID          0xffff
+
+#define TLV_TYPE_SSID                          0x0000
+#define TLV_TYPE_RATES                         0x0001
+#define TLV_TYPE_PHY_FH                                0x0002
+#define TLV_TYPE_PHY_DS                                0x0003
+#define TLV_TYPE_CF                                0x0004
+#define TLV_TYPE_IBSS                          0x0006
+
+#define TLV_TYPE_DOMAIN                                0x0007
+
+#define TLV_TYPE_POWER_CAPABILITY      0x0021
+
+#define TLV_TYPE_KEY_MATERIAL       (PROPRIETARY_TLV_BASE_ID + 0)
+#define TLV_TYPE_CHANLIST           (PROPRIETARY_TLV_BASE_ID + 1)
+#define TLV_TYPE_NUMPROBES          (PROPRIETARY_TLV_BASE_ID + 2)
+#define TLV_TYPE_RSSI_LOW           (PROPRIETARY_TLV_BASE_ID + 4)
+#define TLV_TYPE_SNR_LOW            (PROPRIETARY_TLV_BASE_ID + 5)
+#define TLV_TYPE_FAILCOUNT          (PROPRIETARY_TLV_BASE_ID + 6)
+#define TLV_TYPE_BCNMISS            (PROPRIETARY_TLV_BASE_ID + 7)
+#define TLV_TYPE_LED_GPIO           (PROPRIETARY_TLV_BASE_ID + 8)
+#define TLV_TYPE_LEDBEHAVIOR        (PROPRIETARY_TLV_BASE_ID + 9)
+#define TLV_TYPE_PASSTHROUGH        (PROPRIETARY_TLV_BASE_ID + 10)
+#define TLV_TYPE_REASSOCAP          (PROPRIETARY_TLV_BASE_ID + 11)
+#define TLV_TYPE_POWER_TBL_2_4GHZ   (PROPRIETARY_TLV_BASE_ID + 12)
+#define TLV_TYPE_POWER_TBL_5GHZ     (PROPRIETARY_TLV_BASE_ID + 13)
+#define TLV_TYPE_BCASTPROBE        (PROPRIETARY_TLV_BASE_ID + 14)
+#define TLV_TYPE_NUMSSID_PROBE     (PROPRIETARY_TLV_BASE_ID + 15)
+#define TLV_TYPE_WMMQSTATUS        (PROPRIETARY_TLV_BASE_ID + 16)
+#define TLV_TYPE_CRYPTO_DATA       (PROPRIETARY_TLV_BASE_ID + 17)
+#define TLV_TYPE_WILDCARDSSID      (PROPRIETARY_TLV_BASE_ID + 18)
+#define TLV_TYPE_TSFTIMESTAMP      (PROPRIETARY_TLV_BASE_ID + 19)
+#define TLV_TYPE_RSSI_HIGH          (PROPRIETARY_TLV_BASE_ID + 22)
+#define TLV_TYPE_SNR_HIGH           (PROPRIETARY_TLV_BASE_ID + 23)
+#define TLV_TYPE_AUTH_TYPE          (PROPRIETARY_TLV_BASE_ID + 31)
+#define TLV_TYPE_MESH_ID            (PROPRIETARY_TLV_BASE_ID + 37)
+#define TLV_TYPE_OLD_MESH_ID        (PROPRIETARY_TLV_BASE_ID + 291)
+
+/* TLV related data structures */
+struct mrvl_ie_header {
+       __le16 type;
+       __le16 len;
+} __packed;
+
+struct mrvl_ie_data {
+       struct mrvl_ie_header header;
+       u8 Data[1];
+} __packed;
+
+struct mrvl_ie_rates_param_set {
+       struct mrvl_ie_header header;
+       u8 rates[1];
+} __packed;
+
+struct mrvl_ie_ssid_param_set {
+       struct mrvl_ie_header header;
+       u8 ssid[1];
+} __packed;
+
+struct mrvl_ie_wildcard_ssid_param_set {
+       struct mrvl_ie_header header;
+       u8 MaxSsidlength;
+       u8 ssid[1];
+} __packed;
+
+struct chanscanmode {
+#ifdef __BIG_ENDIAN_BITFIELD
+       u8 reserved_2_7:6;
+       u8 disablechanfilt:1;
+       u8 passivescan:1;
+#else
+       u8 passivescan:1;
+       u8 disablechanfilt:1;
+       u8 reserved_2_7:6;
+#endif
+} __packed;
+
+struct chanscanparamset {
+       u8 radiotype;
+       u8 channumber;
+       struct chanscanmode chanscanmode;
+       __le16 minscantime;
+       __le16 maxscantime;
+} __packed;
+
+struct mrvl_ie_chanlist_param_set {
+       struct mrvl_ie_header header;
+       struct chanscanparamset chanscanparam[1];
+} __packed;
+
+struct mrvl_ie_cf_param_set {
+       struct mrvl_ie_header header;
+       u8 cfpcnt;
+       u8 cfpperiod;
+       __le16 cfpmaxduration;
+       __le16 cfpdurationremaining;
+} __packed;
+
+struct mrvl_ie_ds_param_set {
+       struct mrvl_ie_header header;
+       u8 channel;
+} __packed;
+
+struct mrvl_ie_rsn_param_set {
+       struct mrvl_ie_header header;
+       u8 rsnie[1];
+} __packed;
+
+struct mrvl_ie_tsf_timestamp {
+       struct mrvl_ie_header header;
+       __le64 tsftable[1];
+} __packed;
+
+/* v9 and later firmware only */
+struct mrvl_ie_auth_type {
+       struct mrvl_ie_header header;
+       __le16 auth;
+} __packed;
+
+/*  Local Power capability */
+struct mrvl_ie_power_capability {
+       struct mrvl_ie_header header;
+       s8 minpower;
+       s8 maxpower;
+} __packed;
+
+/* used in CMD_802_11_SUBSCRIBE_EVENT for SNR, RSSI and Failure */
+struct mrvl_ie_thresholds {
+       struct mrvl_ie_header header;
+       u8 value;
+       u8 freq;
+} __packed;
+
+struct mrvl_ie_beacons_missed {
+       struct mrvl_ie_header header;
+       u8 beaconmissed;
+       u8 reserved;
+} __packed;
+
+struct mrvl_ie_num_probes {
+       struct mrvl_ie_header header;
+       __le16 numprobes;
+} __packed;
+
+struct mrvl_ie_bcast_probe {
+       struct mrvl_ie_header header;
+       __le16 bcastprobe;
+} __packed;
+
+struct mrvl_ie_num_ssid_probe {
+       struct mrvl_ie_header header;
+       __le16 numssidprobe;
+} __packed;
+
+struct led_pin {
+       u8 led;
+       u8 pin;
+} __packed;
+
+struct mrvl_ie_ledgpio {
+       struct mrvl_ie_header header;
+       struct led_pin ledpin[1];
+} __packed;
+
+struct led_bhv {
+       uint8_t firmwarestate;
+       uint8_t led;
+       uint8_t ledstate;
+       uint8_t ledarg;
+} __packed;
+
+
+struct mrvl_ie_ledbhv {
+       struct mrvl_ie_header header;
+       struct led_bhv ledbhv[1];
+} __packed;
+
+/*
+ * Meant to be packed as the value member of a struct ieee80211_info_element.
+ * Note that the len member of the ieee80211_info_element varies depending on
+ * the mesh_id_len
+ */
+struct mrvl_meshie_val {
+       uint8_t oui[3];
+       uint8_t type;
+       uint8_t subtype;
+       uint8_t version;
+       uint8_t active_protocol_id;
+       uint8_t active_metric_id;
+       uint8_t mesh_capability;
+       uint8_t mesh_id_len;
+       uint8_t mesh_id[IEEE80211_MAX_SSID_LEN];
+} __packed;
+
+struct mrvl_meshie {
+       u8 id, len;
+       struct mrvl_meshie_val val;
+} __packed;
+
+struct mrvl_mesh_defaults {
+       __le32 bootflag;
+       uint8_t boottime;
+       uint8_t reserved;
+       __le16 channel;
+       struct mrvl_meshie meshie;
+} __packed;
+
+#endif