aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@suse.de>2008-10-02 11:29:28 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2008-10-10 15:31:10 -0700
commit00b3ed1685089ff52169a715de11106ed37df087 (patch)
tree27fff3d6498ca0f5975f8b0ac1c09beda5f9b1da
parent66101de10957e07a6fd0365d5af9adf650246d14 (diff)
Staging: add wlan-ng prism2 usb driver
This adds the wlan-ng prism2 USB driver to the drivers/staging tree. The code was originally written by the linux-wlan-ng team, patched by some Novell engineers to properly work on newer kernels, and then hacked into place in order to get it to build properly in a single subdirectory within the kernel tree by me. It supports a wide range of older USB prism2 devices, and contains a 80211 stack to support this single driver. Cc: Christian Zoz <zoz@suse.de> Cc: Andreas Gruenbacher <agruen@suse.de> Cc: linux-wireless <linux-wireless@vger.kernel.org> Cc: John Linville <linville@tuxdriver.com> Cc: Helmut Schaa <helmut.schaa@googlemail.com> Cc: linux-wlan-ng <solomon@linux-wlan.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/staging/Kconfig2
-rw-r--r--drivers/staging/Makefile1
-rw-r--r--drivers/staging/wlan-ng/Kconfig10
-rw-r--r--drivers/staging/wlan-ng/Makefile9
-rw-r--r--drivers/staging/wlan-ng/README8
-rw-r--r--drivers/staging/wlan-ng/hfa384x.c4018
-rw-r--r--drivers/staging/wlan-ng/hfa384x.h3067
-rw-r--r--drivers/staging/wlan-ng/hfa384x_usb.c5027
-rw-r--r--drivers/staging/wlan-ng/p80211conv.c683
-rw-r--r--drivers/staging/wlan-ng/p80211conv.h186
-rw-r--r--drivers/staging/wlan-ng/p80211hdr.h299
-rw-r--r--drivers/staging/wlan-ng/p80211ioctl.h123
-rw-r--r--drivers/staging/wlan-ng/p80211meta.h169
-rw-r--r--drivers/staging/wlan-ng/p80211metadef.h2524
-rw-r--r--drivers/staging/wlan-ng/p80211metamib.h105
-rw-r--r--drivers/staging/wlan-ng/p80211metamsg.h105
-rw-r--r--drivers/staging/wlan-ng/p80211metastruct.h644
-rw-r--r--drivers/staging/wlan-ng/p80211mgmt.h575
-rw-r--r--drivers/staging/wlan-ng/p80211mod.c216
-rw-r--r--drivers/staging/wlan-ng/p80211msg.h102
-rw-r--r--drivers/staging/wlan-ng/p80211netdev.c1502
-rw-r--r--drivers/staging/wlan-ng/p80211netdev.h336
-rw-r--r--drivers/staging/wlan-ng/p80211req.c329
-rw-r--r--drivers/staging/wlan-ng/p80211req.h68
-rw-r--r--drivers/staging/wlan-ng/p80211types.h675
-rw-r--r--drivers/staging/wlan-ng/p80211wep.c317
-rw-r--r--drivers/staging/wlan-ng/p80211wext.c2048
-rw-r--r--drivers/staging/wlan-ng/prism2_cs.c1487
-rw-r--r--drivers/staging/wlan-ng/prism2_pci.c332
-rw-r--r--drivers/staging/wlan-ng/prism2_plx.c472
-rw-r--r--drivers/staging/wlan-ng/prism2_usb.c361
-rw-r--r--drivers/staging/wlan-ng/prism2mgmt.c2956
-rw-r--r--drivers/staging/wlan-ng/prism2mgmt.h182
-rw-r--r--drivers/staging/wlan-ng/prism2mib.c3799
-rw-r--r--drivers/staging/wlan-ng/prism2sta.c2502
-rw-r--r--drivers/staging/wlan-ng/version.h64
-rw-r--r--drivers/staging/wlan-ng/wlan_compat.h757
37 files changed, 36060 insertions, 0 deletions
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index fdbdf84e307..762b471fded 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -37,4 +37,6 @@ source "drivers/staging/usbip/Kconfig"
source "drivers/staging/winbond/Kconfig"
+source "drivers/staging/wlan-ng/Kconfig"
+
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 9b576c91b15..574198479d6 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_ME4000) += me4000/
obj-$(CONFIG_VIDEO_GO7007) += go7007/
obj-$(CONFIG_USB_IP_COMMON) += usbip/
obj-$(CONFIG_W35UND) += winbond/
+obj-$(CONFIG_PRISM2_USB) += wlan-ng/
diff --git a/drivers/staging/wlan-ng/Kconfig b/drivers/staging/wlan-ng/Kconfig
new file mode 100644
index 00000000000..10b1f0f634d
--- /dev/null
+++ b/drivers/staging/wlan-ng/Kconfig
@@ -0,0 +1,10 @@
+config PRISM2_USB
+ tristate "Prism2.5 USB driver"
+ depends on USB
+ default n
+ ---help---
+ This is the wlan-ng prism 2.5 USB driver for a wide range of
+ old USB wireless devices.
+
+ To compile this driver as a module, choose M here: the module
+ will be called prism2_usb.
diff --git a/drivers/staging/wlan-ng/Makefile b/drivers/staging/wlan-ng/Makefile
new file mode 100644
index 00000000000..777b5111b3d
--- /dev/null
+++ b/drivers/staging/wlan-ng/Makefile
@@ -0,0 +1,9 @@
+obj-$(CONFIG_PRISM2_USB) += prism2_usb.o
+obj-$(CONFIG_PRISM2_USB) += p80211.o
+
+p80211-objs := p80211mod.o \
+ p80211conv.o \
+ p80211req.o \
+ p80211wep.o \
+ p80211wext.o \
+ p80211netdev.o
diff --git a/drivers/staging/wlan-ng/README b/drivers/staging/wlan-ng/README
new file mode 100644
index 00000000000..f50e4eb6c27
--- /dev/null
+++ b/drivers/staging/wlan-ng/README
@@ -0,0 +1,8 @@
+TODO:
+ - checkpatch.pl cleanups
+ - sparse warnings
+ - Lindent cleanups
+ - move to use the in-kernel wireless stack
+ - possible enable the pcmcia and pci portions of the driver
+
+Please send all patches to Greg Kroah-Hartman <greg@kroah.com>
diff --git a/drivers/staging/wlan-ng/hfa384x.c b/drivers/staging/wlan-ng/hfa384x.c
new file mode 100644
index 00000000000..04df3fd9c52
--- /dev/null
+++ b/drivers/staging/wlan-ng/hfa384x.c
@@ -0,0 +1,4018 @@
+/* src/prism2/driver/hfa384x.c
+*
+* Implements the functions of the Intersil hfa384x MAC
+*
+* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
+* --------------------------------------------------------------------
+*
+* linux-wlan
+*
+* The contents of this file are subject to the Mozilla Public
+* License Version 1.1 (the "License"); you may not use this file
+* except in compliance with the License. You may obtain a copy of
+* the License at http://www.mozilla.org/MPL/
+*
+* Software distributed under the License is distributed on an "AS
+* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+* implied. See the License for the specific language governing
+* rights and limitations under the License.
+*
+* Alternatively, the contents of this file may be used under the
+* terms of the GNU Public License version 2 (the "GPL"), in which
+* case the provisions of the GPL are applicable instead of the
+* above. If you wish to allow the use of your version of this file
+* only under the terms of the GPL and not to allow others to use
+* your version of this file under the MPL, indicate your decision
+* by deleting the provisions above and replace them with the notice
+* and other provisions required by the GPL. If you do not delete
+* the provisions above, a recipient may use your version of this
+* file under either the MPL or the GPL.
+*
+* --------------------------------------------------------------------
+*
+* Inquiries regarding the linux-wlan Open Source project can be
+* made directly to:
+*
+* AbsoluteValue Systems Inc.
+* info@linux-wlan.com
+* http://www.linux-wlan.com
+*
+* --------------------------------------------------------------------
+*
+* Portions of the development of this software were funded by
+* Intersil Corporation as part of PRISM(R) chipset product development.
+*
+* --------------------------------------------------------------------
+*
+* This file implements functions that correspond to the prism2/hfa384x
+* 802.11 MAC hardware and firmware host interface.
+*
+* The functions can be considered to represent several levels of
+* abstraction. The lowest level functions are simply C-callable wrappers
+* around the register accesses. The next higher level represents C-callable
+* prism2 API functions that match the Intersil documentation as closely
+* as is reasonable. The next higher layer implements common sequences
+* of invokations of the API layer (e.g. write to bap, followed by cmd).
+*
+* Common sequences:
+* hfa384x_drvr_xxx Highest level abstractions provided by the
+* hfa384x code. They are driver defined wrappers
+* for common sequences. These functions generally
+* use the services of the lower levels.
+*
+* hfa384x_drvr_xxxconfig An example of the drvr level abstraction. These
+* functions are wrappers for the RID get/set
+* sequence. They call copy_[to|from]_bap() and
+* cmd_access(). These functions operate on the
+* RIDs and buffers without validation. The caller
+* is responsible for that.
+*
+* API wrapper functions:
+* hfa384x_cmd_xxx functions that provide access to the f/w commands.
+* The function arguments correspond to each command
+* argument, even command arguments that get packed
+* into single registers. These functions _just_
+* issue the command by setting the cmd/parm regs
+* & reading the status/resp regs. Additional
+* activities required to fully use a command
+* (read/write from/to bap, get/set int status etc.)
+* are implemented separately. Think of these as
+* C-callable prism2 commands.
+*
+* Lowest Layer Functions:
+* hfa384x_docmd_xxx These functions implement the sequence required
+* to issue any prism2 command. Primarily used by the
+* hfa384x_cmd_xxx functions.
+*
+* hfa384x_bap_xxx BAP read/write access functions.
+* Note: we usually use BAP0 for non-interrupt context
+* and BAP1 for interrupt context.
+*
+* hfa384x_dl_xxx download related functions.
+*
+* Driver State Issues:
+* Note that there are two pairs of functions that manage the
+* 'initialized' and 'running' states of the hw/MAC combo. The four
+* functions are create(), destroy(), start(), and stop(). create()
+* sets up the data structures required to support the hfa384x_*
+* functions and destroy() cleans them up. The start() function gets
+* the actual hardware running and enables the interrupts. The stop()
+* function shuts the hardware down. The sequence should be:
+* create()
+* .
+* . Self contained test routines can run here, particularly
+* . corereset() and test_hostif().
+* .
+* start()
+* .
+* . Do interesting things w/ the hardware
+* .
+* stop()
+* destroy()
+*
+* Note that destroy() can be called without calling stop() first.
+* --------------------------------------------------------------------
+*/
+
+/*================================================================*/
+
+/* System Includes */
+#define WLAN_DBVAR prism2_debug
+#include "version.h"
+
+
+#include <linux/version.h>
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/wireless.h>
+#include <linux/netdevice.h>
+#include <linux/timer.h>
+#include <asm/semaphore.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <asm/byteorder.h>
+#include <linux/list.h>
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+#include <linux/tqueue.h>
+#else
+#include <linux/workqueue.h>
+#endif
+
+#if (WLAN_HOSTIF == WLAN_PCMCIA)
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13) )
+#include <pcmcia/version.h>
+#endif
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/cisreg.h>
+#endif
+
+#if ((WLAN_HOSTIF == WLAN_PLX) || (WLAN_HOSTIF == WLAN_PCI))
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#endif
+
+#include "wlan_compat.h"
+
+// XXXX #define CMD_IRQ
+
+/*================================================================*/
+/* Project Includes */
+
+#include "p80211types.h"
+#include "p80211hdr.h"
+#include "p80211mgmt.h"
+#include "p80211conv.h"
+#include "p80211msg.h"
+#include "p80211netdev.h"
+#include "p80211req.h"
+#include "p80211metadef.h"
+#include "p80211metastruct.h"
+#include "hfa384x.h"
+#include "prism2mgmt.h"
+
+/*================================================================*/
+/* Local Constants */
+
+static const UINT16 crc16tab[256] =
+{
+ 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
+ 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
+ 0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
+ 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
+ 0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
+ 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
+ 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
+ 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
+ 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
+ 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
+ 0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
+ 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
+ 0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
+ 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
+ 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
+ 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
+ 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
+ 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
+ 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
+ 0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
+ 0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
+ 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
+ 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
+ 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
+ 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
+ 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
+ 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
+ 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
+ 0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
+ 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
+ 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
+ 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040
+};
+
+/*================================================================*/
+/* Local Macros */
+
+/*================================================================*/
+/* Local Types */
+
+/*================================================================*/
+/* Local Static Definitions */
+extern int prism2_debug;
+
+/*================================================================*/
+/* Local Function Declarations */
+
+static void hfa384x_int_dtim(wlandevice_t *wlandev);
+static void hfa384x_int_infdrop(wlandevice_t *wlandev);
+
+static void hfa384x_bap_tasklet(unsigned long data);
+
+static void hfa384x_int_info(wlandevice_t *wlandev);
+static void hfa384x_int_txexc(wlandevice_t *wlandev);
+static void hfa384x_int_tx(wlandevice_t *wlandev);
+static void hfa384x_int_rx(wlandevice_t *wlandev);
+
+#ifdef CMD_IRQ
+static void hfa384x_int_cmd(wlandevice_t *wlandev);
+#endif
+static void hfa384x_int_rxmonitor( wlandevice_t *wlandev,
+ UINT16 rxfid, hfa384x_rx_frame_t *rxdesc);
+static void hfa384x_int_alloc(wlandevice_t *wlandev);
+
+static int hfa384x_docmd_wait( hfa384x_t *hw, hfa384x_metacmd_t *cmd);
+
+static int hfa384x_dl_docmd_wait( hfa384x_t *hw, hfa384x_metacmd_t *cmd);
+
+static UINT16
+hfa384x_mkcrc16(UINT8 *p, int len);
+
+int hfa384x_copy_to_bap4(hfa384x_t *hw, UINT16 bap, UINT16 id, UINT16 offset,
+ void *buf, UINT len, void* buf2, UINT len2,
+ void *buf3, UINT len3, void* buf4, UINT len4);
+
+/*================================================================*/
+/* Function Definitions */
+
+static UINT16
+txfid_queue_empty(hfa384x_t *hw)
+{
+ return (hw->txfid_head == hw->txfid_tail) ? 1 : 0;
+}
+
+static UINT16
+txfid_queue_remove(hfa384x_t *hw)
+{
+ UINT16 result= 0;
+
+ if (txfid_queue_empty(hw)) {
+ WLAN_LOG_DEBUG(3,"queue empty.\n");
+ } else {
+ result = hw->txfid_queue[hw->txfid_head];
+ hw->txfid_head = (hw->txfid_head + 1) % hw->txfid_N;
+ }
+
+ return (UINT16)result;
+}
+
+static INT16
+txfid_queue_add(hfa384x_t *hw, UINT16 val)
+{
+ INT16 result = 0;
+
+ if (hw->txfid_head == ((hw->txfid_tail + 1) % hw->txfid_N)) {
+ result = -1;
+ WLAN_LOG_DEBUG(3,"queue full.\n");
+ } else {
+ hw->txfid_queue[hw->txfid_tail] = val;
+ result = hw->txfid_tail;
+ hw->txfid_tail = (hw->txfid_tail + 1) % hw->txfid_N;
+ }
+
+ return result;
+}
+
+/*----------------------------------------------------------------
+* hfa384x_create
+*
+* Initializes the hfa384x_t data structure for use. Note this
+* does _not_ intialize the actual hardware, just the data structures
+* we use to keep track of its state.
+*
+* Arguments:
+* hw device structure
+* irq device irq number
+* iobase [pcmcia] i/o base address for register access
+* [pci] zero
+* [plx] i/o base address for register access
+* membase [pcmcia] pcmcia_cs "link" pointer
+* [pci] memory base address for register access
+* [plx] memory base address for card attribute memory
+*
+* Returns:
+* nothing
+*
+* Side effects:
+*
+* Call context:
+* process thread
+----------------------------------------------------------------*/
+void hfa384x_create(hfa384x_t *hw, UINT irq, UINT32 iobase,
+ UINT8 __iomem *membase)
+{
+ DBFENTER;
+ memset(hw, 0, sizeof(hfa384x_t));
+ hw->irq = irq;
+ hw->iobase = iobase;
+ hw->membase = membase;
+ spin_lock_init(&(hw->cmdlock));
+
+ /* BAP setup */
+ spin_lock_init(&(hw->baplock));
+ tasklet_init(&hw->bap_tasklet,
+ hfa384x_bap_tasklet,
+ (unsigned long) hw);
+
+ init_waitqueue_head(&hw->cmdq);
+ sema_init(&hw->infofid_sem, 1);
+
+ hw->txfid_head = 0;
+ hw->txfid_tail = 0;
+ hw->txfid_N = HFA384x_DRVR_FIDSTACKLEN_MAX;
+ memset(hw->txfid_queue, 0, sizeof(hw->txfid_queue));
+
+ hw->isram16 = 1;
+
+ /* Init the auth queue head */
+ skb_queue_head_init(&hw->authq);
+
+ INIT_WORK2(&hw->link_bh, prism2sta_processing_defer);
+
+ INIT_WORK2(&hw->commsqual_bh, prism2sta_commsqual_defer);
+
+ init_timer(&hw->commsqual_timer);
+ hw->commsqual_timer.data = (unsigned long) hw;
+ hw->commsqual_timer.function = prism2sta_commsqual_timer;
+
+ hw->link_status = HFA384x_LINK_NOTCONNECTED;
+ hw->state = HFA384x_STATE_INIT;
+
+ DBFEXIT;
+}
+
+/*----------------------------------------------------------------
+* hfa384x_destroy
+*
+* Partner to hfa384x_create(). This function cleans up the hw
+* structure so that it can be freed by the caller using a simple
+* kfree. Currently, this function is just a placeholder. If, at some
+* point in the future, an hw in the 'shutdown' state requires a 'deep'
+* kfree, this is where it should be done. Note that if this function
+* is called on a _running_ hw structure, the drvr_stop() function is
+* called.
+*
+* Arguments:
+* hw device structure
+*
+* Returns:
+* nothing, this function is not allowed to fail.
+*
+* Side effects:
+*
+* Call context:
+* process
+----------------------------------------------------------------*/
+void
+hfa384x_destroy( hfa384x_t *hw)
+{
+ struct sk_buff *skb;
+
+ DBFENTER;
+
+ if ( hw->state == HFA384x_STATE_RUNNING ) {
+ hfa384x_drvr_stop(hw);
+ }
+ hw->state = HFA384x_STATE_PREINIT;
+
+ if (hw->scanresults) {
+ kfree(hw->scanresults);
+ hw->scanresults = NULL;
+ }
+
+ /* Now to clean out the auth queue */
+ while ( (skb = skb_dequeue(&hw->authq)) ) {
+ dev_kfree_skb(skb);
+ }
+
+ DBFEXIT;
+ return;
+}
+
+/*----------------------------------------------------------------
+* hfa384x_drvr_getconfig
+*
+* Performs the sequence necessary to read a config/info item.
+*
+* Arguments:
+* hw device structure
+* rid config/info record id (host order)
+* buf host side record buffer. Upon return it will
+* contain the body portion of the record (minus the
+* RID and len).
+* len buffer length (in bytes, should match record length)
+*
+* Returns:
+* 0 success
+* >0 f/w reported error - f/w status code
+* <0 driver reported error
+* -ENODATA length mismatch between argument and retrieved
+* record.
+*
+* Side effects:
+*
+* Call context:
+* process thread
+----------------------------------------------------------------*/
+int hfa384x_drvr_getconfig(hfa384x_t *hw, UINT16 rid, void *buf, UINT16 len)
+{
+ int result = 0;
+ DBFENTER;
+
+ result = hfa384x_cmd_access( hw, 0, rid, buf, len);
+
+ DBFEXIT;
+ return result;
+}
+
+
+/*----------------------------------------------------------------
+* hfa384x_drvr_setconfig
+*
+* Performs the sequence necessary to write a config/info item.
+*
+* Arguments:
+* hw device structure
+* rid config/info record id (in host order)
+* buf host side record buffer
+* len buffer length (in bytes)
+*
+* Returns:
+* 0 success
+* >0 f/w reported error - f/w status code
+* <0 driver reported error
+*
+* Side effects:
+*
+* Call context:
+* process thread
+----------------------------------------------------------------*/
+int hfa384x_drvr_setconfig(hfa384x_t *hw, UINT16 rid, void *buf, UINT16 len)
+{
+ int result = 0;
+ DBFENTER;
+
+ result = hfa384x_cmd_access( hw, 1, rid, buf, len);
+
+ DBFEXIT;
+ return result;
+}
+
+
+/*----------------------------------------------------------------
+* hfa384x_drvr_readpda
+*
+* Performs the sequence to read the PDA space. Note there is no
+* drvr_writepda() function. Writing a PDA is
+* generally implemented by a calling component via calls to
+* cmd_download and writing to the flash download buffer via the
+* aux regs.
+*
+* Arguments:
+* hw device structure
+* buf buffer to store PDA in
+* len buffer length
+*
+* Returns:
+* 0 success
+* >0 f/w reported error - f/w status code
+* <0 driver reported error
+* -ETIMEOUT timout waiting for the cmd regs to become
+* available, or waiting for the control reg
+* to indicate the Aux port is enabled.
+* -ENODATA the buffer does NOT contain a valid PDA.
+* Either the card PDA is bad, or the auxdata
+* reads are giving us garbage.
+
+*
+* Side effects:
+*
+* Call context:
+* process thread or non-card interrupt.
+----------------------------------------------------------------*/
+int hfa384x_drvr_readpda(hfa384x_t *hw, void *buf, UINT len)
+{
+ int result = 0;
+ UINT16 *pda = buf;
+ int pdaok = 0;
+ int morepdrs = 1;
+ int currpdr = 0; /* word offset of the current pdr */
+ int i;
+ UINT16 pdrlen; /* pdr length in bytes, host order */
+ UINT16 pdrcode; /* pdr code, host order */
+ UINT16 crc;
+ UINT16 pdacrc;
+ struct pdaloc {
+ UINT32 cardaddr;
+ UINT16 auxctl;
+ } pdaloc[] =
+ {
+ { HFA3842_PDA_BASE, HFA384x_AUX_CTL_NV},
+ { HFA3842_PDA_BASE, HFA384x_AUX_CTL_EXTDS},
+ { HFA3841_PDA_BASE, HFA384x_AUX_CTL_NV},
+ { HFA3841_PDA_BASE, HFA384x_AUX_CTL_EXTDS},
+ { HFA3841_PDA_BOGUS_BASE, HFA384x_AUX_CTL_NV}
+ };
+
+ DBFENTER;
+ /* Check for aux available */
+ result = hfa384x_cmd_aux_enable(hw, 0);
+ if ( result ) {
+ WLAN_LOG_DEBUG(1,"aux_enable() failed. result=%d\n", result);
+ goto failed;
+ }
+
+ /* Read the pda from each known address. */
+ for ( i = 0; i < (sizeof(pdaloc)/sizeof(pdaloc[0])); i++) {
+ WLAN_LOG_DEBUG( 3, "Checking PDA@(0x%08x,%s)\n",
+ pdaloc[i].cardaddr,
+ pdaloc[i].auxctl == HFA384x_AUX_CTL_NV ?
+ "CTL_NV" : "CTL_EXTDS");
+
+ /* Copy bufsize bytes from our current pdaloc */
+ hfa384x_copy_from_aux(hw,
+ pdaloc[i].cardaddr,
+ pdaloc[i].auxctl,
+ buf,
+ len);
+
+ /* Test for garbage */
+ /* Traverse the PDR list Looking for PDA-END */
+ pdaok = 1; /* intially assume good */
+ morepdrs = 1;
+ currpdr = 0;
+ while ( pdaok && morepdrs ) {
+ pdrlen = hfa384x2host_16(pda[currpdr]) * 2;
+ pdrcode = hfa384x2host_16(pda[currpdr+1]);
+
+ /* Test for completion at END record */
+ if ( pdrcode == HFA384x_PDR_END_OF_PDA ) {
+ if ( pdrlen == 4 ) {
+ morepdrs = 0;
+ /* Calculate CRC-16 and compare to PDA
+ * value. Note the addition of 2 words
+ * for ENDREC.len and ENDREC.code
+ * fields.
+ */
+ crc = hfa384x_mkcrc16( (UINT8*)pda,
+ (currpdr + 2) * sizeof(UINT16));
+ pdacrc =hfa384x2host_16(pda[currpdr+2]);
+ if ( crc != pdacrc ) {
+ WLAN_LOG_DEBUG(3,
+ "PDA crc failed:"
+ "calc_crc=0x%04x,"
+ "pdr_crc=0x%04x.\n",
+ crc, pdacrc);
+ pdaok = 0;
+ }
+ } else {
+ WLAN_LOG_DEBUG(3,
+ "END record detected w/ "
+ "len(%d) != 2, assuming bad PDA\n",
+ pdrlen);
+ pdaok = 0;
+
+ }
+ break;
+ }
+
+ /* Test the record length */
+ if ( pdrlen > HFA384x_PDR_LEN_MAX || pdrlen == 0) {
+ WLAN_LOG_DEBUG(3,
+ "pdrlen for address #%d "
+ "at %#x:%#x:%d\n",
+ i, pdaloc[i].cardaddr,
+ pdaloc[i].auxctl, pdrlen);
+ WLAN_LOG_DEBUG(3,"pdrlen invalid=%d\n",
+ pdrlen);
+ pdaok = 0;
+ break;
+ }
+
+ /* Move to the next pdr */
+ if ( morepdrs ) {
+ /* note the access to pda[], we need words */
+ currpdr += hfa384x2host_16(pda[currpdr]) + 1;
+ if (currpdr*sizeof(UINT16) > len) {
+ WLAN_LOG_DEBUG(3,
+ "Didn't find PDA_END in buffer, "
+ "trying next location.\n");
+ pdaok = 0;
+ break;
+ }
+ }
+ }
+ if ( pdaok ) {
+ WLAN_LOG_INFO(
+ "PDA Read from 0x%08x in %s space.\n",
+ pdaloc[i].cardaddr,
+ pdaloc[i].auxctl == 0 ? "EXTDS" :
+ pdaloc[i].auxctl == 1 ? "NV" :
+ pdaloc[i].auxctl == 2 ? "PHY" :
+ pdaloc[i].auxctl == 3 ? "ICSRAM" :
+ "<bogus auxctl>");
+ break;
+ }
+ }
+ result = pdaok ? 0 : -ENODATA;
+
+ if ( result ) {
+ WLAN_LOG_DEBUG(3,"Failure: pda is not okay\n");
+ }
+
+ hfa384x_cmd_aux_disable(hw);
+failed:
+ DBFEXIT;
+ return result;
+}
+
+
+
+/*----------------------------------------------------------------
+* mkpda_crc
+*
+* Calculates the CRC16 for the given PDA and inserts the value
+* into the end record.
+*
+* Arguments:
+* pda ptr to the PDA data structure.
+*
+* Returns:
+* 0 - success
+* ~0 - failure (probably an errno)
+----------------------------------------------------------------*/
+static UINT16
+hfa384x_mkcrc16(UINT8 *p, int len)
+{
+ UINT16 crc = 0;
+ UINT8 *lim = p + len;
+
+ while (p < lim) {
+ crc = (crc >> 8 ) ^ crc16tab[(crc & 0xff) ^ *p++];
+ }
+
+ return crc;
+}
+
+
+/*----------------------------------------------------------------
+* hfa384x_drvr_ramdl_enable
+*
+* Begins the ram download state. Checks to see that we're not
+* already in a download state and that a port isn't enabled.
+* Sets the download state and calls cmd_download with the
+* ENABLE_VOLATILE subcommand and the exeaddr argument.
+*
+* Arguments:
+* hw device structure
+* exeaddr the card execution address that will be
+* jumped to when ramdl_disable() is called
+* (host order).
+*
+* Returns:
+* 0 success
+* >0 f/w reported error - f/w status code
+* <0 driver reported error
+*
+* Side effects:
+*
+* Call context:
+* process thread
+----------------------------------------------------------------*/
+int hfa384x_drvr_ramdl_enable(hfa384x_t *hw, UINT32 exeaddr)
+{
+ int result = 0;
+ UINT16 lowaddr;
+ UINT16 hiaddr;
+ int i;
+ DBFENTER;
+ /* Check that a port isn't active */
+ for ( i = 0; i < HFA384x_PORTID_MAX; i++) {
+ if ( hw->port_enabled[i] ) {
+ WLAN_LOG_DEBUG(1,"Can't download with a port enabled.\n");
+ result = -EINVAL;
+ goto done;
+ }
+ }
+
+ /* Check that we're not already in a download state */
+ if ( hw->dlstate != HFA384x_DLSTATE_DISABLED ) {
+ WLAN_LOG_DEBUG(1,"Download state not disabled.\n");
+ result = -EINVAL;
+ goto done;
+ }
+
+ /* Are we supposed to go into genesis mode? */
+ if (exeaddr == 0x3f0000) {
+ UINT16 initseq[2] = { 0xe100, 0xffa1 };
+ UINT16 readbuf[2];
+ UINT8 hcr = 0x0f; /* Default to x16 SRAM */
+ hw->isram16 = 1;
+
+ WLAN_LOG_DEBUG(1, "Dropping into Genesis mode\n");
+
+ /* Issue card reset and enable aux port */
+ hfa384x_corereset(hw, prism2_reset_holdtime,
+ prism2_reset_settletime, 0);
+ hfa384x_cmd_aux_enable(hw, 1);
+
+ /* Genesis set */
+ hfa384x_copy_to_aux(hw, 0x7E0038, HFA384x_AUX_CTL_EXTDS,
+ initseq, sizeof(initseq));
+
+ hfa384x_corereset(hw, prism2_reset_holdtime,
+ prism2_reset_settletime, hcr);
+