|
@@ -1,4018 +0,0 @@
|
|
|
-/* 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);
|
|
|
-
|
|
|
- /* Validate memory config */
|
|
|
- hfa384x_copy_to_aux(hw, 0x7E0038, HFA384x_AUX_CTL_EXTDS,
|
|
|
- initseq, sizeof(initseq));
|
|
|
- hfa384x_copy_from_aux(hw, 0x7E0038, HFA384x_AUX_CTL_EXTDS,
|
|
|
- readbuf, sizeof(initseq));
|
|
|
- WLAN_HEX_DUMP(3, "readback", readbuf, sizeof(readbuf));
|
|
|
-
|
|
|
- if (memcmp(initseq, readbuf, sizeof(readbuf))) {
|
|
|
- hcr = 0x1f; /* x8 SRAM */
|
|
|
- hw->isram16 = 0;
|
|
|
-
|
|
|
- hfa384x_copy_to_aux(hw, 0x7E0038, HFA384x_AUX_CTL_EXTDS,
|
|
|
- initseq, sizeof(initseq));
|
|
|
- hfa384x_corereset(hw, prism2_reset_holdtime,
|
|
|
- prism2_reset_settletime, hcr);
|
|
|
-
|
|
|
- hfa384x_copy_to_aux(hw, 0x7E0038, HFA384x_AUX_CTL_EXTDS,
|
|
|
- initseq, sizeof(initseq));
|
|
|
- hfa384x_copy_from_aux(hw, 0x7E0038, HFA384x_AUX_CTL_EXTDS,
|
|
|
- readbuf, sizeof(initseq));
|
|
|
- WLAN_HEX_DUMP(2, "readback", readbuf, sizeof(readbuf));
|
|
|
-
|
|
|
- if (memcmp(initseq, readbuf, sizeof(readbuf))) {
|
|
|
- WLAN_LOG_ERROR("Genesis mode failed\n");
|
|
|
- result = -1;
|
|
|
- goto done;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /* Now we're in genesis mode */
|
|
|
- hw->dlstate = HFA384x_DLSTATE_GENESIS;
|
|
|
- goto done;
|
|
|
- }
|
|
|
-
|
|
|
- /* Retrieve the buffer loc&size and timeout */
|
|
|
- if ( (result = hfa384x_drvr_getconfig(hw, HFA384x_RID_DOWNLOADBUFFER,
|
|
|
- &(hw->bufinfo), sizeof(hw->bufinfo))) ) {
|
|
|
- goto done;
|
|
|
- }
|
|
|
- hw->bufinfo.page = hfa384x2host_16(hw->bufinfo.page);
|
|
|
- hw->bufinfo.offset = hfa384x2host_16(hw->bufinfo.offset);
|
|
|
- hw->bufinfo.len = hfa384x2host_16(hw->bufinfo.len);
|
|
|
- if ( (result = hfa384x_drvr_getconfig16(hw, HFA384x_RID_MAXLOADTIME,
|
|
|
- &(hw->dltimeout))) ) {
|
|
|
- goto done;
|
|
|
- }
|
|
|
- hw->dltimeout = hfa384x2host_16(hw->dltimeout);
|
|
|
-
|
|
|
- /* Enable the aux port */
|
|
|
- if ( (result = hfa384x_cmd_aux_enable(hw, 0)) ) {
|
|
|
- WLAN_LOG_DEBUG(1,"Aux enable failed, result=%d.\n", result);
|
|
|
- goto done;
|
|
|
- }
|
|
|
-
|
|
|
- /* Call the download(1,addr) function */
|
|
|
- lowaddr = HFA384x_ADDR_CMD_MKOFF(exeaddr);
|
|
|
- hiaddr = HFA384x_ADDR_CMD_MKPAGE(exeaddr);
|
|
|
-
|
|
|
- result = hfa384x_cmd_download(hw, HFA384x_PROGMODE_RAM,
|
|
|
- lowaddr, hiaddr, 0);
|
|
|
- if ( result == 0) {
|
|
|
- /* Set the download state */
|
|
|
- hw->dlstate = HFA384x_DLSTATE_RAMENABLED;
|
|
|
- } else {
|
|
|
- WLAN_LOG_DEBUG(1,"cmd_download(0x%04x, 0x%04x) failed, result=%d.\n",
|
|
|
- lowaddr,hiaddr, result);
|
|
|
- /* Disable the aux port */
|
|
|
- hfa384x_cmd_aux_disable(hw);
|
|
|
- }
|
|
|
-
|
|
|
- done:
|
|
|
- DBFEXIT;
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_drvr_ramdl_disable
|
|
|
-*
|
|
|
-* Ends the ram download state.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* hw device structure
|
|
|
-*
|
|
|
-* 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_disable(hfa384x_t *hw)
|
|
|
-{
|
|
|
- DBFENTER;
|
|
|
- /* Check that we're already in the download state */
|
|
|
- if ( ( hw->dlstate != HFA384x_DLSTATE_RAMENABLED ) &&
|
|
|
- ( hw->dlstate != HFA384x_DLSTATE_GENESIS ) ) {
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
- if (hw->dlstate == HFA384x_DLSTATE_GENESIS) {
|
|
|
- hfa384x_corereset(hw, prism2_reset_holdtime,
|
|
|
- prism2_reset_settletime,
|
|
|
- hw->isram16 ? 0x07: 0x17);
|
|
|
- goto done;
|
|
|
- }
|
|
|
-
|
|
|
- /* Disable the aux port */
|
|
|
- hfa384x_cmd_download(hw, HFA384x_PROGMODE_DISABLE, 0, 0 , 0);
|
|
|
-
|
|
|
- done:
|
|
|
- hw->dlstate = HFA384x_DLSTATE_DISABLED;
|
|
|
- hfa384x_cmd_aux_disable(hw);
|
|
|
-
|
|
|
- DBFEXIT;
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_drvr_ramdl_write
|
|
|
-*
|
|
|
-* Performs a RAM download of a chunk of data. First checks to see
|
|
|
-* that we're in the RAM download state, then uses the aux functions
|
|
|
-* to 1) copy the data, 2) readback and compare. The download
|
|
|
-* state is unaffected. When all data has been written using
|
|
|
-* this function, call drvr_ramdl_disable() to end the download state
|
|
|
-* and restart the MAC.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* hw device structure
|
|
|
-* daddr Card address to write to. (host order)
|
|
|
-* buf Ptr to data to write.
|
|
|
-* len Length of data (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_write(hfa384x_t *hw, UINT32 daddr, void* buf, UINT32 len)
|
|
|
-{
|
|
|
- int result = 0;
|
|
|
- UINT8 *verbuf;
|
|
|
- DBFENTER;
|
|
|
- /* Check that we're in the ram download state */
|
|
|
- if ( ( hw->dlstate != HFA384x_DLSTATE_RAMENABLED ) &&
|
|
|
- ( hw->dlstate != HFA384x_DLSTATE_GENESIS ) ) {
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
- WLAN_LOG_INFO("Writing %d bytes to ram @0x%06x\n", len, daddr);
|
|
|
-#if 0
|
|
|
-WLAN_HEX_DUMP(1, "dldata", buf, len);
|
|
|
-#endif
|
|
|
- /* Copy the data via the aux port */
|
|
|
- hfa384x_copy_to_aux(hw, daddr, HFA384x_AUX_CTL_EXTDS, buf, len);
|
|
|
-
|
|
|
- /* Create a buffer for the verify */
|
|
|
- verbuf = kmalloc(len, GFP_KERNEL);
|
|
|
- if (verbuf == NULL ) return 1;
|
|
|
-
|
|
|
- /* Read back and compare */
|
|
|
- hfa384x_copy_from_aux(hw, daddr, HFA384x_AUX_CTL_EXTDS, verbuf, len);
|
|
|
-
|
|
|
- if ( memcmp(buf, verbuf, len) ) {
|
|
|
- WLAN_LOG_DEBUG(1,"ramdl verify failed!\n");
|
|
|
- result = -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
- kfree_s(verbuf, len);
|
|
|
- DBFEXIT;
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_drvr_flashdl_enable
|
|
|
-*
|
|
|
-* Begins the flash 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 retrieves the flash download
|
|
|
-* buffer location, buffer size, and timeout length.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* hw device structure
|
|
|
-*
|
|
|
-* 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_flashdl_enable(hfa384x_t *hw)
|
|
|
-{
|
|
|
- int result = 0;
|
|
|
- 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,"called when port enabled.\n");
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /* Check that we're not already in a download state */
|
|
|
- if ( hw->dlstate != HFA384x_DLSTATE_DISABLED ) {
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
- /* Retrieve the buffer loc&size and timeout */
|
|
|
- if ( (result = hfa384x_drvr_getconfig(hw, HFA384x_RID_DOWNLOADBUFFER,
|
|
|
- &(hw->bufinfo), sizeof(hw->bufinfo))) ) {
|
|
|
- return result;
|
|
|
- }
|
|
|
- hw->bufinfo.page = hfa384x2host_16(hw->bufinfo.page);
|
|
|
- hw->bufinfo.offset = hfa384x2host_16(hw->bufinfo.offset);
|
|
|
- hw->bufinfo.len = hfa384x2host_16(hw->bufinfo.len);
|
|
|
- if ( (result = hfa384x_drvr_getconfig16(hw, HFA384x_RID_MAXLOADTIME,
|
|
|
- &(hw->dltimeout))) ) {
|
|
|
- return result;
|
|
|
- }
|
|
|
- hw->dltimeout = hfa384x2host_16(hw->dltimeout);
|
|
|
-
|
|
|
- /* Enable the aux port */
|
|
|
- if ( (result = hfa384x_cmd_aux_enable(hw, 0)) ) {
|
|
|
- return result;
|
|
|
- }
|
|
|
-
|
|
|
- hw->dlstate = HFA384x_DLSTATE_FLASHENABLED;
|
|
|
- DBFEXIT;
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_drvr_flashdl_disable
|
|
|
-*
|
|
|
-* Ends the flash download state. Note that this will cause the MAC
|
|
|
-* firmware to restart.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* hw device structure
|
|
|
-*
|
|
|
-* 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_flashdl_disable(hfa384x_t *hw)
|
|
|
-{
|
|
|
- DBFENTER;
|
|
|
- /* Check that we're already in the download state */
|
|
|
- if ( hw->dlstate != HFA384x_DLSTATE_FLASHENABLED ) {
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
- /* There isn't much we can do at this point, so I don't */
|
|
|
- /* bother w/ the return value */
|
|
|
- hfa384x_cmd_download(hw, HFA384x_PROGMODE_DISABLE, 0, 0 , 0);
|
|
|
- hw->dlstate = HFA384x_DLSTATE_DISABLED;
|
|
|
-
|
|
|
- /* Disable the aux port */
|
|
|
- hfa384x_cmd_aux_disable(hw);
|
|
|
-
|
|
|
- DBFEXIT;
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_drvr_flashdl_write
|
|
|
-*
|
|
|
-* Performs a FLASH download of a chunk of data. First checks to see
|
|
|
-* that we're in the FLASH download state, then sets the download
|
|
|
-* mode, uses the aux functions to 1) copy the data to the flash
|
|
|
-* buffer, 2) sets the download 'write flash' mode, 3) readback and
|
|
|
-* compare. Lather rinse, repeat as many times an necessary to get
|
|
|
-* all the given data into flash.
|
|
|
-* When all data has been written using this function (possibly
|
|
|
-* repeatedly), call drvr_flashdl_disable() to end the download state
|
|
|
-* and restart the MAC.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* hw device structure
|
|
|
-* daddr Card address to write to. (host order)
|
|
|
-* buf Ptr to data to write.
|
|
|
-* len Length of data (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_flashdl_write(hfa384x_t *hw, UINT32 daddr, void* buf, UINT32 len)
|
|
|
-{
|
|
|
- int result = 0;
|
|
|
- UINT8 *verbuf;
|
|
|
- UINT32 dlbufaddr;
|
|
|
- UINT32 currlen;
|
|
|
- UINT32 currdaddr;
|
|
|
- UINT16 destlo;
|
|
|
- UINT16 desthi;
|
|
|
- int nwrites;
|
|
|
- int i;
|
|
|
-
|
|
|
- DBFENTER;
|
|
|
- /* Check that we're in the flash download state */
|
|
|
- if ( hw->dlstate != HFA384x_DLSTATE_FLASHENABLED ) {
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
- WLAN_LOG_INFO("Download %d bytes to flash @0x%06x\n", len, daddr);
|
|
|
-
|
|
|
- /* Need a flat address for arithmetic */
|
|
|
- dlbufaddr = HFA384x_ADDR_AUX_MKFLAT(
|
|
|
- hw->bufinfo.page,
|
|
|
- hw->bufinfo.offset);
|
|
|
- verbuf = kmalloc(hw->bufinfo.len, GFP_KERNEL);
|
|
|
-
|
|
|
-#if 0
|
|
|
-WLAN_LOG_WARNING("dlbuf@0x%06lx len=%d to=%d\n", dlbufaddr, hw->bufinfo.len, hw->dltimeout);
|
|
|
-#endif
|
|
|
- /* Figure out how many times to to the flash prog */
|
|
|
- nwrites = len / hw->bufinfo.len;
|
|
|
- nwrites += (len % hw->bufinfo.len) ? 1 : 0;
|
|
|
-
|
|
|
- if ( verbuf == NULL ) {
|
|
|
- WLAN_LOG_ERROR("Failed to allocate flash verify buffer\n");
|
|
|
- return 1;
|
|
|
- }
|
|
|
- /* For each */
|
|
|
- for ( i = 0; i < nwrites; i++) {
|
|
|
- /* Get the dest address and len */
|
|
|
- currlen = (len - (hw->bufinfo.len * i)) > hw->bufinfo.len ?
|
|
|
- hw->bufinfo.len :
|
|
|
- (len - (hw->bufinfo.len * i));
|
|
|
- currdaddr = daddr + (hw->bufinfo.len * i);
|
|
|
- destlo = HFA384x_ADDR_CMD_MKOFF(currdaddr);
|
|
|
- desthi = HFA384x_ADDR_CMD_MKPAGE(currdaddr);
|
|
|
- WLAN_LOG_INFO("Writing %d bytes to flash @0x%06x\n", currlen, currdaddr);
|
|
|
-#if 0
|
|
|
-WLAN_HEX_DUMP(1, "dldata", buf+(hw->bufinfo.len*i), currlen);
|
|
|
-#endif
|
|
|
- /* Set the download mode */
|
|
|
- result = hfa384x_cmd_download(hw, HFA384x_PROGMODE_NV,
|
|
|
- destlo, desthi, currlen);
|
|
|
- if ( result ) {
|
|
|
- WLAN_LOG_ERROR("download(NV,lo=%x,hi=%x,len=%x) "
|
|
|
- "cmd failed, result=%d. Aborting d/l\n",
|
|
|
- destlo, desthi, currlen, result);
|
|
|
- goto exit_proc;
|
|
|
- }
|
|
|
- /* copy the data to the flash buffer */
|
|
|
- hfa384x_copy_to_aux(hw, dlbufaddr, HFA384x_AUX_CTL_EXTDS,
|
|
|
- buf+(hw->bufinfo.len*i), currlen);
|
|
|
- /* set the download 'write flash' mode */
|
|
|
- result = hfa384x_cmd_download(hw, HFA384x_PROGMODE_NVWRITE, 0,0,0);
|
|
|
- if ( result ) {
|
|
|
- WLAN_LOG_ERROR(
|
|
|
- "download(NVWRITE,lo=%x,hi=%x,len=%x) "
|
|
|
- "cmd failed, result=%d. Aborting d/l\n",
|
|
|
- destlo, desthi, currlen, result);
|
|
|
- goto exit_proc;
|
|
|
- }
|
|
|
- /* readback and compare, if fail...bail */
|
|
|
- hfa384x_copy_from_aux(hw,
|
|
|
- currdaddr, HFA384x_AUX_CTL_NV,
|
|
|
- verbuf, currlen);
|
|
|
-
|
|
|
- if ( memcmp(buf+(hw->bufinfo.len*i), verbuf, currlen) ) {
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-exit_proc:
|
|
|
- /* DOH! This kfree's for you Mark :-) My forehead hurts... */
|
|
|
- kfree(verbuf);
|
|
|
-
|
|
|
- /* Leave the firmware in the 'post-prog' mode. flashdl_disable will */
|
|
|
- /* actually disable programming mode. Remember, that will cause the */
|
|
|
- /* the firmware to effectively reset itself. */
|
|
|
-
|
|
|
- DBFEXIT;
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_cmd_initialize
|
|
|
-*
|
|
|
-* Issues the initialize command and sets the hw->state based
|
|
|
-* on the result.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* hw device structure
|
|
|
-*
|
|
|
-* Returns:
|
|
|
-* 0 success
|
|
|
-* >0 f/w reported error - f/w status code
|
|
|
-* <0 driver reported error
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* process thread
|
|
|
-----------------------------------------------------------------*/
|
|
|
-int hfa384x_cmd_initialize(hfa384x_t *hw)
|
|
|
-{
|
|
|
- int result = 0;
|
|
|
- int i;
|
|
|
- hfa384x_metacmd_t cmd;
|
|
|
-
|
|
|
- DBFENTER;
|
|
|
-
|
|
|
- /* we don't want to be interrupted during the reset */
|
|
|
- hfa384x_setreg(hw, 0, HFA384x_INTEN);
|
|
|
- hfa384x_setreg(hw, 0xffff, HFA384x_EVACK);
|
|
|
-
|
|
|
- cmd.cmd = HFA384x_CMDCODE_INIT;
|
|
|
- cmd.parm0 = 0;
|
|
|
- cmd.parm1 = 0;
|
|
|
- cmd.parm2 = 0;
|
|
|
-
|
|
|
- spin_lock_bh(&hw->cmdlock);
|
|
|
- result = hfa384x_docmd_wait(hw, &cmd);
|
|
|
- spin_unlock_bh(&hw->cmdlock);
|
|
|
-
|
|
|
- if ( result == 0 ) {
|
|
|
- for ( i = 0; i < HFA384x_NUMPORTS_MAX; i++) {
|
|
|
- hw->port_enabled[i] = 0;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- hw->link_status = HFA384x_LINK_NOTCONNECTED;
|
|
|
-
|
|
|
- DBFEXIT;
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_drvr_commtallies
|
|
|
-*
|
|
|
-* Send a commtallies inquiry to the MAC. Note that this is an async
|
|
|
-* call that will result in an info frame arriving sometime later.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* hw device structure
|
|
|
-*
|
|
|
-* Returns:
|
|
|
-* zero success.
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* process
|
|
|
-----------------------------------------------------------------*/
|
|
|
-int hfa384x_drvr_commtallies( hfa384x_t *hw )
|
|
|
-{
|
|
|
- hfa384x_metacmd_t cmd;
|
|
|
- int result;
|
|
|
-
|
|
|
- DBFENTER;
|
|
|
-
|
|
|
- cmd.cmd = HFA384x_CMDCODE_INQ;
|
|
|
- cmd.parm0 = HFA384x_IT_COMMTALLIES;
|
|
|
- cmd.parm1 = 0;
|
|
|
- cmd.parm2 = 0;
|
|
|
-
|
|
|
- spin_lock_bh(&hw->cmdlock);
|
|
|
- result = hfa384x_docmd_wait(hw, &cmd);
|
|
|
- spin_unlock_bh(&hw->cmdlock);
|
|
|
-
|
|
|
- DBFEXIT;
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_drvr_enable
|
|
|
-*
|
|
|
-* Issues the enable command to enable communications on one of
|
|
|
-* the MACs 'ports'. Only macport 0 is valid for stations.
|
|
|
-* APs may also enable macports 1-6. Only ports that are currently
|
|
|
-* disabled may be enabled.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* hw device structure
|
|
|
-* macport MAC port number
|
|
|
-*
|
|
|
-* Returns:
|
|
|
-* 0 success
|
|
|
-* >0 f/w reported failure - f/w status code
|
|
|
-* <0 driver reported error (timeout|bad arg)
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* process thread
|
|
|
-----------------------------------------------------------------*/
|
|
|
-int hfa384x_drvr_enable(hfa384x_t *hw, UINT16 macport)
|
|
|
-{
|
|
|
- int result = 0;
|
|
|
-
|
|
|
- DBFENTER;
|
|
|
- if ((!hw->isap && macport != 0) ||
|
|
|
- (hw->isap && !(macport <= HFA384x_PORTID_MAX)) ||
|
|
|
- (hw->port_enabled[macport]) ){
|
|
|
- result = -EINVAL;
|
|
|
- } else {
|
|
|
- result = hfa384x_cmd_enable(hw, macport);
|
|
|
- if ( result == 0 ) {
|
|
|
- hw->port_enabled[macport] = 1;
|
|
|
- }
|
|
|
- }
|
|
|
- DBFEXIT;
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_cmd_enable
|
|
|
-*
|
|
|
-* Issues the the enable command to enable communications on one of the
|
|
|
-* MACs 'ports'.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* hw device structure
|
|
|
-* macport MAC port number
|
|
|
-*
|
|
|
-* Returns:
|
|
|
-* 0 success
|
|
|
-* >0 f/w reported failure - f/w status code
|
|
|
-* <0 driver reported error (timeout|bad arg)
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* process thread
|
|
|
-----------------------------------------------------------------*/
|
|
|
-int hfa384x_cmd_enable(hfa384x_t *hw, UINT16 macport)
|
|
|
-{
|
|
|
- int result = 0;
|
|
|
- hfa384x_metacmd_t cmd;
|
|
|
-
|
|
|
- DBFENTER;
|
|
|
-
|
|
|
- cmd.cmd = HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_ENABLE) |
|
|
|
- HFA384x_CMD_MACPORT_SET(macport);
|
|
|
- cmd.parm0 = 0;
|
|
|
- cmd.parm1 = 0;
|
|
|
- cmd.parm2 = 0;
|
|
|
-
|
|
|
- spin_lock_bh(&hw->cmdlock);
|
|
|
- result = hfa384x_docmd_wait(hw, &cmd);
|
|
|
- spin_unlock_bh(&hw->cmdlock);
|
|
|
-
|
|
|
- DBFEXIT;
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_drvr_disable
|
|
|
-*
|
|
|
-* Issues the disable command to stop communications on one of
|
|
|
-* the MACs 'ports'. Only macport 0 is valid for stations.
|
|
|
-* APs may also disable macports 1-6. Only ports that have been
|
|
|
-* previously enabled may be disabled.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* hw device structure
|
|
|
-* macport MAC port number (host order)
|
|
|
-*
|
|
|
-* Returns:
|
|
|
-* 0 success
|
|
|
-* >0 f/w reported failure - f/w status code
|
|
|
-* <0 driver reported error (timeout|bad arg)
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* process thread
|
|
|
-----------------------------------------------------------------*/
|
|
|
-int hfa384x_drvr_disable(hfa384x_t *hw, UINT16 macport)
|
|
|
-{
|
|
|
- int result = 0;
|
|
|
-
|
|
|
- DBFENTER;
|
|
|
- if ((!hw->isap && macport != 0) ||
|
|
|
- (hw->isap && !(macport <= HFA384x_PORTID_MAX)) ||
|
|
|
- !(hw->port_enabled[macport]) ){
|
|
|
- result = -EINVAL;
|
|
|
- } else {
|
|
|
- result = hfa384x_cmd_disable(hw, macport);
|
|
|
- if ( result == 0 ) {
|
|
|
- hw->port_enabled[macport] = 0;
|
|
|
- }
|
|
|
- }
|
|
|
- DBFEXIT;
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_cmd_disable
|
|
|
-*
|
|
|
-* Issues the command to disable a port.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* hw device structure
|
|
|
-* macport MAC port number (host order)
|
|
|
-*
|
|
|
-* Returns:
|
|
|
-* 0 success
|
|
|
-* >0 f/w reported failure - f/w status code
|
|
|
-* <0 driver reported error (timeout|bad arg)
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* process thread
|
|
|
-----------------------------------------------------------------*/
|
|
|
-int hfa384x_cmd_disable(hfa384x_t *hw, UINT16 macport)
|
|
|
-{
|
|
|
- int result = 0;
|
|
|
- hfa384x_metacmd_t cmd;
|
|
|
-
|
|
|
- DBFENTER;
|
|
|
-
|
|
|
- cmd.cmd = HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_DISABLE) |
|
|
|
- HFA384x_CMD_MACPORT_SET(macport);
|
|
|
- cmd.parm0 = 0;
|
|
|
- cmd.parm1 = 0;
|
|
|
- cmd.parm2 = 0;
|
|
|
-
|
|
|
- spin_lock_bh(&hw->cmdlock);
|
|
|
- result = hfa384x_docmd_wait(hw, &cmd);
|
|
|
- spin_unlock_bh(&hw->cmdlock);
|
|
|
-
|
|
|
- DBFEXIT;
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_cmd_diagnose
|
|
|
-*
|
|
|
-* Issues the diagnose command to test the: register interface,
|
|
|
-* MAC controller (including loopback), External RAM, Non-volatile
|
|
|
-* memory integrity, and synthesizers. Following execution of this
|
|
|
-* command, MAC/firmware are in the 'initial state'. Therefore,
|
|
|
-* the Initialize command should be issued after successful
|
|
|
-* completion of this command. This function may only be called
|
|
|
-* when the MAC is in the 'communication disabled' state.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* hw device structure
|
|
|
-*
|
|
|
-* Returns:
|
|
|
-* 0 success
|
|
|
-* >0 f/w reported failure - f/w status code
|
|
|
-* <0 driver reported error (timeout|bad arg)
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* process thread
|
|
|
-----------------------------------------------------------------*/
|
|
|
-#define DIAG_PATTERNA ((UINT16)0xaaaa)
|
|
|
-#define DIAG_PATTERNB ((UINT16)0x5555)
|
|
|
-
|
|
|
-int hfa384x_cmd_diagnose(hfa384x_t *hw)
|
|
|
-{
|
|
|
- int result = 0;
|
|
|
- hfa384x_metacmd_t cmd;
|
|
|
-
|
|
|
- DBFENTER;
|
|
|
-
|
|
|
- cmd.cmd = HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_DIAG);
|
|
|
- cmd.parm0 = DIAG_PATTERNA;
|
|
|
- cmd.parm1 = DIAG_PATTERNB;
|
|
|
- cmd.parm2 = 0;
|
|
|
-
|
|
|
- spin_lock_bh(&hw->cmdlock);
|
|
|
- result = hfa384x_docmd_wait(hw, &cmd);
|
|
|
- spin_unlock_bh(&hw->cmdlock);
|
|
|
-
|
|
|
- DBFEXIT;
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_cmd_allocate
|
|
|
-*
|
|
|
-* Issues the allocate command instructing the firmware to allocate
|
|
|
-* a 'frame structure buffer' in MAC controller RAM. This command
|
|
|
-* does not provide the result, it only initiates one of the f/w's
|
|
|
-* asynchronous processes to construct the buffer. When the
|
|
|
-* allocation is complete, it will be indicated via the Alloc
|
|
|
-* bit in the EvStat register and the FID identifying the allocated
|
|
|
-* space will be available from the AllocFID register. Some care
|
|
|
-* should be taken when waiting for the Alloc event. If a Tx or
|
|
|
-* Notify command w/ Reclaim has been previously executed, it's
|
|
|
-* possible the first Alloc event after execution of this command
|
|
|
-* will be for the reclaimed buffer and not the one you asked for.
|
|
|
-* This case must be handled in the Alloc event handler.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* hw device structure
|
|
|
-* len allocation length, must be an even value
|
|
|
-* in the range [4-2400]. (host order)
|
|
|
-*
|
|
|
-* Returns:
|
|
|
-* 0 success
|
|
|
-* >0 f/w reported failure - f/w status code
|
|
|
-* <0 driver reported error (timeout|bad arg)
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* process thread
|
|
|
-----------------------------------------------------------------*/
|
|
|
-int hfa384x_cmd_allocate(hfa384x_t *hw, UINT16 len)
|
|
|
-{
|
|
|
- int result = 0;
|
|
|
- hfa384x_metacmd_t cmd;
|
|
|
-
|
|
|
- DBFENTER;
|
|
|
-
|
|
|
- if ( (len % 2) ||
|
|
|
- len < HFA384x_CMD_ALLOC_LEN_MIN ||
|
|
|
- len > HFA384x_CMD_ALLOC_LEN_MAX ) {
|
|
|
- result = -EINVAL;
|
|
|
- } else {
|
|
|
- cmd.cmd = HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_ALLOC);
|
|
|
- cmd.parm0 = len;
|
|
|
- cmd.parm1 = 0;
|
|
|
- cmd.parm2 = 0;
|
|
|
-
|
|
|
- spin_lock_bh(&hw->cmdlock);
|
|
|
- result = hfa384x_docmd_wait(hw, &cmd);
|
|
|
- spin_unlock_bh(&hw->cmdlock);
|
|
|
- }
|
|
|
- DBFEXIT;
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_cmd_transmit
|
|
|
-*
|
|
|
-* Instructs the firmware to transmit a frame previously copied
|
|
|
-* to a given buffer. This function returns immediately, the Tx
|
|
|
-* results are available via the Tx or TxExc events (if the frame
|
|
|
-* control bits are set). The reclaim argument specifies if the
|
|
|
-* FID passed will be used by the f/w tx process or returned for
|
|
|
-* use w/ another transmit command. If reclaim is set, expect an
|
|
|
-* Alloc event signalling the availibility of the FID for reuse.
|
|
|
-*
|
|
|
-* NOTE: hw->cmdlock MUST BE HELD before calling this function!
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* hw device structure
|
|
|
-* reclaim [0|1] indicates whether the given FID will
|
|
|
-* be handed back (via Alloc event) for reuse.
|
|
|
-* (host order)
|
|
|
-* qos [0-3] Value to put in the QoS field of the
|
|
|
-* tx command, identifies a queue to place the
|
|
|
-* outgoing frame in.
|
|
|
-* (host order)
|
|
|
-* fid FID of buffer containing the frame that was
|
|
|
-* previously copied to MAC memory via the bap.
|
|
|
-* (host order)
|
|
|
-*
|
|
|
-* Returns:
|
|
|
-* 0 success
|
|
|
-* >0 f/w reported failure - f/w status code
|
|
|
-* <0 driver reported error (timeout|bad arg)
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-* hw->resp0 will contain the FID being used by async tx
|
|
|
-* process. If reclaim==0, resp0 will be the same as the fid
|
|
|
-* argument. If reclaim==1, resp0 will be the different and
|
|
|
-* is the value to watch for in the Tx|TxExc to indicate completion
|
|
|
-* of the frame passed in fid.
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* process thread
|
|
|
-----------------------------------------------------------------*/
|
|
|
-int hfa384x_cmd_transmit(hfa384x_t *hw, UINT16 reclaim, UINT16 qos, UINT16 fid)
|
|
|
-{
|
|
|
- int result = 0;
|
|
|
- hfa384x_metacmd_t cmd;
|
|
|
-
|
|
|
- DBFENTER;
|
|
|
- cmd.cmd = HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_TX) |
|
|
|
- HFA384x_CMD_RECL_SET(reclaim) |
|
|
|
- HFA384x_CMD_QOS_SET(qos);
|
|
|
- cmd.parm0 = fid;
|
|
|
- cmd.parm1 = 0;
|
|
|
- cmd.parm2 = 0;
|
|
|
-
|
|
|
- result = hfa384x_docmd_wait(hw, &cmd);
|
|
|
-
|
|
|
- DBFEXIT;
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_cmd_clearpersist
|
|
|
-*
|
|
|
-* Instructs the firmware to clear the persistence bit in a given
|
|
|
-* FID. This has the effect of telling the firmware to drop the
|
|
|
-* persistent frame. The FID must be one that was previously used
|
|
|
-* to transmit a PRST frame.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* hw device structure
|
|
|
-* fid FID of the persistent frame (host order)
|
|
|
-*
|
|
|
-* Returns:
|
|
|
-* 0 success
|
|
|
-* >0 f/w reported failure - f/w status code
|
|
|
-* <0 driver reported error (timeout|bad arg)
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* process thread
|
|
|
-----------------------------------------------------------------*/
|
|
|
-int hfa384x_cmd_clearpersist(hfa384x_t *hw, UINT16 fid)
|
|
|
-{
|
|
|
- int result = 0;
|
|
|
- hfa384x_metacmd_t cmd;
|
|
|
-
|
|
|
- DBFENTER;
|
|
|
-
|
|
|
- cmd.cmd = HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_CLRPRST);
|
|
|
- cmd.parm0 = fid;
|
|
|
- cmd.parm1 = 0;
|
|
|
- cmd.parm2 = 0;
|
|
|
-
|
|
|
- spin_lock_bh(&hw->cmdlock);
|
|
|
- result = hfa384x_docmd_wait(hw, &cmd);
|
|
|
- spin_unlock_bh(&hw->cmdlock);
|
|
|
-
|
|
|
- DBFEXIT;
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_cmd_notify
|
|
|
-*
|
|
|
-* Sends an info frame to the firmware to alter the behavior
|
|
|
-* of the f/w asynch processes. Can only be called when the MAC
|
|
|
-* is in the enabled state.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* hw device structure
|
|
|
-* reclaim [0|1] indicates whether the given FID will
|
|
|
-* be handed back (via Alloc event) for reuse.
|
|
|
-* (host order)
|
|
|
-* fid FID of buffer containing the frame that was
|
|
|
-* previously copied to MAC memory via the bap.
|
|
|
-* (host order)
|
|
|
-*
|
|
|
-* Returns:
|
|
|
-* 0 success
|
|
|
-* >0 f/w reported failure - f/w status code
|
|
|
-* <0 driver reported error (timeout|bad arg)
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-* hw->resp0 will contain the FID being used by async notify
|
|
|
-* process. If reclaim==0, resp0 will be the same as the fid
|
|
|
-* argument. If reclaim==1, resp0 will be the different.
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* process thread
|
|
|
-----------------------------------------------------------------*/
|
|
|
-int hfa384x_cmd_notify(hfa384x_t *hw, UINT16 reclaim, UINT16 fid,
|
|
|
- void *buf, UINT16 len)
|
|
|
-{
|
|
|
- int result = 0;
|
|
|
- hfa384x_metacmd_t cmd;
|
|
|
-
|
|
|
- DBFENTER;
|
|
|
- cmd.cmd = HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_NOTIFY) |
|
|
|
- HFA384x_CMD_RECL_SET(reclaim);
|
|
|
- cmd.parm0 = fid;
|
|
|
- cmd.parm1 = 0;
|
|
|
- cmd.parm2 = 0;
|
|
|
-
|
|
|
- spin_lock_bh(&hw->cmdlock);
|
|
|
-
|
|
|
- /* Copy the record to FID */
|
|
|
- result = hfa384x_copy_to_bap(hw, HFA384x_BAP_PROC, hw->infofid, 0, buf, len);
|
|
|
- if ( result ) {
|
|
|
- WLAN_LOG_DEBUG(1,
|
|
|
- "copy_to_bap(%04x, 0, %d) failed, result=0x%x\n",
|
|
|
- hw->infofid, len, result);
|
|
|
- result = -EIO;
|
|
|
- goto failed;
|
|
|
- }
|
|
|
-
|
|
|
- result = hfa384x_docmd_wait(hw, &cmd);
|
|
|
-
|
|
|
- failed:
|
|
|
- spin_unlock_bh(&hw->cmdlock);
|
|
|
-
|
|
|
- DBFEXIT;
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-#if 0
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_cmd_inquiry
|
|
|
-*
|
|
|
-* Requests an info frame from the firmware. The info frame will
|
|
|
-* be delivered asynchronously via the Info event.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* hw device structure
|
|
|
-* fid FID of the info frame requested. (host order)
|
|
|
-*
|
|
|
-* Returns:
|
|
|
-* 0 success
|
|
|
-* >0 f/w reported failure - f/w status code
|
|
|
-* <0 driver reported error (timeout|bad arg)
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* process thread
|
|
|
-----------------------------------------------------------------*/
|
|
|
-static int hfa384x_cmd_inquiry(hfa384x_t *hw, UINT16 fid)
|
|
|
-{
|
|
|
- int result = 0;
|
|
|
- hfa384x_metacmd_t cmd;
|
|
|
-
|
|
|
- DBFENTER;
|
|
|
-
|
|
|
- cmd.cmd = HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_INQ);
|
|
|
- cmd.parm0 = fid;
|
|
|
- cmd.parm1 = 0;
|
|
|
- cmd.parm2 = 0;
|
|
|
-
|
|
|
- spin_lock_bh(&hw->cmdlock);
|
|
|
- result = hfa384x_docmd_wait(hw, &cmd);
|
|
|
- spin_unlock_bh(&hw->cmdlock);
|
|
|
-
|
|
|
- DBFEXIT;
|
|
|
- return result;
|
|
|
-}
|
|
|
-#endif
|
|
|
-
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_cmd_access
|
|
|
-*
|
|
|
-* Requests that a given record be copied to/from the record
|
|
|
-* buffer. If we're writing from the record buffer, the contents
|
|
|
-* must previously have been written to the record buffer via the
|
|
|
-* bap. If we're reading into the record buffer, the record can
|
|
|
-* be read out of the record buffer after this call.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* hw device structure
|
|
|
-* write [0|1] copy the record buffer to the given
|
|
|
-* configuration record. (host order)
|
|
|
-* rid RID of the record to read/write. (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 failure - f/w status code
|
|
|
-* <0 driver reported error (timeout|bad arg)
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* process thread
|
|
|
-----------------------------------------------------------------*/
|
|
|
-int hfa384x_cmd_access(hfa384x_t *hw, UINT16 write, UINT16 rid,
|
|
|
- void* buf, UINT16 len)
|
|
|
-{
|
|
|
- int result = 0;
|
|
|
- hfa384x_metacmd_t cmd;
|
|
|
- hfa384x_rec_t rec;
|
|
|
-
|
|
|
- DBFENTER;
|
|
|
-
|
|
|
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0))
|
|
|
- /* This should NOT be called in interrupt context! */
|
|
|
- if (in_irq()) {
|
|
|
- WLAN_LOG_ERROR("Krap, in Interrupt context!");
|
|
|
-#ifdef WLAN_INCLUDE_DEBUG
|
|
|
- BUG();
|
|
|
-#endif
|
|
|
- }
|
|
|
-#endif
|
|
|
- spin_lock_bh(&hw->cmdlock);
|
|
|
-
|
|
|
- if (write) {
|
|
|
- rec.rid = host2hfa384x_16(rid);
|
|
|
- rec.reclen = host2hfa384x_16((len/2) + 1); /* note conversion to words, +1 for rid field */
|
|
|
- /* write the record */
|
|
|
- result = hfa384x_copy_to_bap4( hw, HFA384x_BAP_PROC, rid, 0,
|
|
|
- &rec, sizeof(rec),
|
|
|
- buf, len,
|
|
|
- NULL, 0, NULL, 0);
|
|
|
- if ( result ) {
|
|
|
- WLAN_LOG_DEBUG(3,"Failure writing record header+data\n");
|
|
|
- goto fail;
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- cmd.cmd = HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_ACCESS) |
|
|
|
- HFA384x_CMD_WRITE_SET(write);
|
|
|
- cmd.parm0 = rid;
|
|
|
- cmd.parm1 = 0;
|
|
|
- cmd.parm2 = 0;
|
|
|
-
|
|
|
- result = hfa384x_docmd_wait(hw, &cmd);
|
|
|
- if ( result ) {
|
|
|
- WLAN_LOG_ERROR("Call to hfa384x_docmd_wait failed (%d %d)\n",
|
|
|
- result, cmd.result.resp0);
|
|
|
- goto fail;
|
|
|
- }
|
|
|
-
|
|
|
- if (!write) {
|
|
|
- result = hfa384x_copy_from_bap( hw, HFA384x_BAP_PROC, rid, 0, &rec, sizeof(rec));
|
|
|
- if ( result ) {
|
|
|
- WLAN_LOG_DEBUG(3,"Call to hfa384x_copy_from_bap failed\n");
|
|
|
- goto fail;
|
|
|
- }
|
|
|
-
|
|
|
- /* Validate the record length */
|
|
|
- if ( ((hfa384x2host_16(rec.reclen)-1)*2) != len ) { /* note body len calculation in bytes */
|
|
|
- WLAN_LOG_DEBUG(1, "RID len mismatch, rid=0x%04x hlen=%d fwlen=%d\n",
|
|
|
- rid, len, (hfa384x2host_16(rec.reclen)-1)*2);
|
|
|
- result = -ENODATA;
|
|
|
- goto fail;
|
|
|
- }
|
|
|
-
|
|
|
- result = hfa384x_copy_from_bap( hw, HFA384x_BAP_PROC, rid, sizeof(rec), buf, len);
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- fail:
|
|
|
- spin_unlock_bh(&hw->cmdlock);
|
|
|
- DBFEXIT;
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_cmd_monitor
|
|
|
-*
|
|
|
-* Enables the 'monitor mode' of the MAC. Here's the description of
|
|
|
-* monitor mode that I've received thus far:
|
|
|
-*
|
|
|
-* "The "monitor mode" of operation is that the MAC passes all
|
|
|
-* frames for which the PLCP checks are correct. All received
|
|
|
-* MPDUs are passed to the host with MAC Port = 7, with a
|
|
|
-* receive status of good, FCS error, or undecryptable. Passing
|
|
|
-* certain MPDUs is a violation of the 802.11 standard, but useful
|
|
|
-* for a debugging tool." Normal communication is not possible
|
|
|
-* while monitor mode is enabled.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* hw device structure
|
|
|
-* enable a code (0x0b|0x0f) that enables/disables
|
|
|
-* monitor mode. (host order)
|
|
|
-*
|
|
|
-* Returns:
|
|
|
-* 0 success
|
|
|
-* >0 f/w reported failure - f/w status code
|
|
|
-* <0 driver reported error (timeout|bad arg)
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* process thread
|
|
|
-----------------------------------------------------------------*/
|
|
|
-int hfa384x_cmd_monitor(hfa384x_t *hw, UINT16 enable)
|
|
|
-{
|
|
|
- int result = 0;
|
|
|
- hfa384x_metacmd_t cmd;
|
|
|
-
|
|
|
- DBFENTER;
|
|
|
-
|
|
|
- cmd.cmd = HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_MONITOR) |
|
|
|
- HFA384x_CMD_AINFO_SET(enable);
|
|
|
- cmd.parm0 = 0;
|
|
|
- cmd.parm1 = 0;
|
|
|
- cmd.parm2 = 0;
|
|
|
-
|
|
|
- spin_lock_bh(&hw->cmdlock);
|
|
|
- result = hfa384x_docmd_wait(hw, &cmd);
|
|
|
- spin_unlock_bh(&hw->cmdlock);
|
|
|
-
|
|
|
- DBFEXIT;
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_cmd_download
|
|
|
-*
|
|
|
-* Sets the controls for the MAC controller code/data download
|
|
|
-* process. The arguments set the mode and address associated
|
|
|
-* with a download. Note that the aux registers should be enabled
|
|
|
-* prior to setting one of the download enable modes.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* hw device structure
|
|
|
-* mode 0 - Disable programming and begin code exec
|
|
|
-* 1 - Enable volatile mem programming
|
|
|
-* 2 - Enable non-volatile mem programming
|
|
|
-* 3 - Program non-volatile section from NV download
|
|
|
-* buffer.
|
|
|
-* (host order)
|
|
|
-* lowaddr
|
|
|
-* highaddr For mode 1, sets the high & low order bits of
|
|
|
-* the "destination address". This address will be
|
|
|
-* the execution start address when download is
|
|
|
-* subsequently disabled.
|
|
|
-* For mode 2, sets the high & low order bits of
|
|
|
-* the destination in NV ram.
|
|
|
-* For modes 0 & 3, should be zero. (host order)
|
|
|
-* NOTE: these address args are in CMD format
|
|
|
-* codelen Length of the data to write in mode 2,
|
|
|
-* zero otherwise. (host order)
|
|
|
-*
|
|
|
-* Returns:
|
|
|
-* 0 success
|
|
|
-* >0 f/w reported failure - f/w status code
|
|
|
-* <0 driver reported error (timeout|bad arg)
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* process thread
|
|
|
-----------------------------------------------------------------*/
|
|
|
-int hfa384x_cmd_download(hfa384x_t *hw, UINT16 mode, UINT16 lowaddr,
|
|
|
- UINT16 highaddr, UINT16 codelen)
|
|
|
-{
|
|
|
- int result = 0;
|
|
|
- hfa384x_metacmd_t cmd;
|
|
|
-
|
|
|
- DBFENTER;
|
|
|
-
|
|
|
- cmd.cmd = HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_DOWNLD) |
|
|
|
- HFA384x_CMD_PROGMODE_SET(mode);
|
|
|
- cmd.parm0 = lowaddr;
|
|
|
- cmd.parm1 = highaddr;
|
|
|
- cmd.parm2 = codelen;
|
|
|
-
|
|
|
- spin_lock_bh(&hw->cmdlock);
|
|
|
- result = hfa384x_dl_docmd_wait(hw, &cmd);
|
|
|
- spin_unlock_bh(&hw->cmdlock);
|
|
|
-
|
|
|
- DBFEXIT;
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_cmd_aux_enable
|
|
|
-*
|
|
|
-* Goes through the process of enabling the auxilary port. This
|
|
|
-* is necessary prior to raw reads/writes to card data space.
|
|
|
-* Direct access to the card data space is only used for downloading
|
|
|
-* code and debugging.
|
|
|
-* Note that a call to this function is required before attempting
|
|
|
-* a download.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* hw device structure
|
|
|
-*
|
|
|
-* Returns:
|
|
|
-* 0 success
|
|
|
-* >0 f/w reported failure - f/w status code
|
|
|
-* <0 driver reported error (timeout)
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* process thread
|
|
|
-----------------------------------------------------------------*/
|
|
|
-int hfa384x_cmd_aux_enable(hfa384x_t *hw, int force)
|
|
|
-{
|
|
|
- int result = -ETIMEDOUT;
|
|
|
- unsigned long flags;
|
|
|
- UINT32 retries_remaining;
|
|
|
- UINT16 reg;
|
|
|
- UINT auxen_mirror = hw->auxen;
|
|
|
-
|
|
|
- DBFENTER;
|
|
|
-
|
|
|
- /* Check for existing enable */
|
|
|
- if ( hw->auxen ) {
|
|
|
- hw->auxen++;
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
- /* acquire the lock */
|
|
|
- spin_lock_irqsave( &(hw->cmdlock), flags);
|
|
|
- /* wait for cmd register busy bit to clear */
|
|
|
- retries_remaining = 100000;
|
|
|
- do {
|
|
|
- reg = hfa384x_getreg(hw, HFA384x_CMD);
|
|
|
- udelay(10);
|
|
|
- }
|
|
|
- while (HFA384x_CMD_ISBUSY(reg) && --retries_remaining);
|
|
|
- if (retries_remaining != 0) {
|
|
|
- /* busy bit clear, it's OK to write to ParamX regs */
|
|
|
- hfa384x_setreg(hw, HFA384x_AUXPW0,
|
|
|
- HFA384x_PARAM0);
|
|
|
- hfa384x_setreg(hw, HFA384x_AUXPW1,
|
|
|
- HFA384x_PARAM1);
|
|
|
- hfa384x_setreg(hw, HFA384x_AUXPW2,
|
|
|
- HFA384x_PARAM2);
|
|
|
-
|
|
|
- /* Set the aux enable in the Control register */
|
|
|
- hfa384x_setreg(hw, HFA384x_CONTROL_AUX_DOENABLE,
|
|
|
- HFA384x_CONTROL);
|
|
|
-
|
|
|
- /* Now wait for completion */
|
|
|
- retries_remaining = 100000;
|
|
|
- do {
|
|
|
- reg = hfa384x_getreg(hw, HFA384x_CONTROL);
|
|
|
- udelay(10);
|
|
|
- }
|
|
|
- while ( ((reg & (BIT14|BIT15)) != HFA384x_CONTROL_AUX_ISENABLED) &&
|
|
|
- --retries_remaining );
|
|
|
- if (retries_remaining != 0) {
|
|
|
- result = 0;
|
|
|
- hw->auxen++;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /* Force it enabled even if the command failed, if told.. */
|
|
|
- if ((hw->auxen == auxen_mirror) && force)
|
|
|
- hw->auxen++;
|
|
|
-
|
|
|
- spin_unlock_irqrestore( &(hw->cmdlock), flags);
|
|
|
- DBFEXIT;
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_cmd_aux_disable
|
|
|
-*
|
|
|
-* Goes through the process of disabling the auxilary port
|
|
|
-* enabled with aux_enable().
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* hw device structure
|
|
|
-*
|
|
|
-* Returns:
|
|
|
-* 0 success
|
|
|
-* >0 f/w reported failure - f/w status code
|
|
|
-* <0 driver reported error (timeout)
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* process thread
|
|
|
-----------------------------------------------------------------*/
|
|
|
-int hfa384x_cmd_aux_disable(hfa384x_t *hw)
|
|
|
-{
|
|
|
- int result = -ETIMEDOUT;
|
|
|
- unsigned long timeout;
|
|
|
- UINT16 reg = 0;
|
|
|
-
|
|
|
- DBFENTER;
|
|
|
-
|
|
|
- /* See if there's more than one enable */
|
|
|
- if (hw->auxen) hw->auxen--;
|
|
|
- if (hw->auxen) return 0;
|
|
|
-
|
|
|
- /* Clear the aux enable in the Control register */
|
|
|
- hfa384x_setreg(hw, 0, HFA384x_PARAM0);
|
|
|
- hfa384x_setreg(hw, 0, HFA384x_PARAM1);
|
|
|
- hfa384x_setreg(hw, 0, HFA384x_PARAM2);
|
|
|
- hfa384x_setreg(hw, HFA384x_CONTROL_AUX_DODISABLE,
|
|
|
- HFA384x_CONTROL);
|
|
|
-
|
|
|
- /* Now wait for completion */
|
|
|
- timeout = jiffies + 1*HZ;
|
|
|
- reg = hfa384x_getreg(hw, HFA384x_CONTROL);
|
|
|
- while ( ((reg & (BIT14|BIT15)) != HFA384x_CONTROL_AUX_ISDISABLED) &&
|
|
|
- time_before(jiffies,timeout) ){
|
|
|
- udelay(10);
|
|
|
- reg = hfa384x_getreg(hw, HFA384x_CONTROL);
|
|
|
- }
|
|
|
- if ((reg & (BIT14|BIT15)) == HFA384x_CONTROL_AUX_ISDISABLED ) {
|
|
|
- result = 0;
|
|
|
- }
|
|
|
- DBFEXIT;
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_drvr_low_level
|
|
|
-*
|
|
|
-* Write test commands to the card. Some test commands don't make
|
|
|
-* sense without prior set-up. For example, continous TX isn't very
|
|
|
-* useful until you set the channel. That functionality should be
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* process thread
|
|
|
-* -----------------------------------------------------------------*/
|
|
|
-int hfa384x_drvr_low_level(hfa384x_t *hw, hfa384x_metacmd_t *cmd)
|
|
|
-{
|
|
|
- int result = 0;
|
|
|
- DBFENTER;
|
|
|
-
|
|
|
- /* Do i need a host2hfa... conversion ? */
|
|
|
-#if 0
|
|
|
- printk(KERN_INFO "%#x %#x %#x %#x\n", cmd->cmd, cmd->parm0, cmd->parm1, cmd->parm2);
|
|
|
-#endif
|
|
|
- spin_lock_bh(&hw->cmdlock);
|
|
|
- result = hfa384x_docmd_wait(hw, cmd);
|
|
|
- spin_unlock_bh(&hw->cmdlock);
|
|
|
-
|
|
|
- DBFEXIT;
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/* TODO: determine if these will ever be needed */
|
|
|
-#if 0
|
|
|
-int hfa384x_cmd_readmif(hfa384x_t *hw)
|
|
|
-{
|
|
|
- DBFENTER;
|
|
|
- DBFEXIT;
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-int hfa384x_cmd_writemif(hfa384x_t *hw)
|
|
|
-{
|
|
|
- DBFENTER;
|
|
|
- DBFEXIT;
|
|
|
- return 0;
|
|
|
-}
|
|
|
-#endif
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_drvr_mmi_read
|
|
|
-*
|
|
|
-* Read mmi registers. mmi is intersil-speak for the baseband
|
|
|
-* processor registers.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* hw device structure
|
|
|
-* register The test register to be accessed (must be even #).
|
|
|
-*
|
|
|
-* 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_mmi_read(hfa384x_t *hw, UINT32 addr, UINT32 *resp)
|
|
|
-{
|
|
|
- int result = 0;
|
|
|
- hfa384x_metacmd_t cmd;
|
|
|
-
|
|
|
- DBFENTER;
|
|
|
- cmd.cmd = (UINT16) 0x30;
|
|
|
- cmd.parm0 = (UINT16) addr;
|
|
|
- cmd.parm1 = 0;
|
|
|
- cmd.parm2 = 0;
|
|
|
-
|
|
|
- /* Do i need a host2hfa... conversion ? */
|
|
|
- spin_lock_bh(&hw->cmdlock);
|
|
|
- result = hfa384x_docmd_wait(hw, &cmd);
|
|
|
- spin_unlock_bh(&hw->cmdlock);
|
|
|
-
|
|
|
- *resp = (UINT32) cmd.result.resp0;
|
|
|
-
|
|
|
- DBFEXIT;
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_drvr_mmi_write
|
|
|
-*
|
|
|
-* Read mmi registers. mmi is intersil-speak for the baseband
|
|
|
-* processor registers.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* hw device structure
|
|
|
-* addr The test register to be accessed (must be even #).
|
|
|
-* data The data value to write to the register.
|
|
|
-*
|
|
|
-* 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_mmi_write(hfa384x_t *hw, UINT32 addr, UINT32 data)
|
|
|
-{
|
|
|
- int result = 0;
|
|
|
- hfa384x_metacmd_t cmd;
|
|
|
-
|
|
|
- DBFENTER;
|
|
|
- cmd.cmd = (UINT16) 0x31;
|
|
|
- cmd.parm0 = (UINT16) addr;
|
|
|
- cmd.parm1 = (UINT16) data;
|
|
|
- cmd.parm2 = 0;
|
|
|
-
|
|
|
- WLAN_LOG_DEBUG(1,"mmi write : addr = 0x%08x\n", addr);
|
|
|
- WLAN_LOG_DEBUG(1,"mmi write : data = 0x%08x\n", data);
|
|
|
-
|
|
|
- /* Do i need a host2hfa... conversion ? */
|
|
|
- spin_lock_bh(&hw->cmdlock);
|
|
|
- result = hfa384x_docmd_wait(hw, &cmd);
|
|
|
- spin_unlock_bh(&hw->cmdlock);
|
|
|
-
|
|
|
- DBFEXIT;
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/* TODO: determine if these will ever be needed */
|
|
|
-#if 0
|
|
|
-int hfa384x_cmd_readmif(hfa384x_t *hw)
|
|
|
-{
|
|
|
- DBFENTER;
|
|
|
- DBFEXIT;
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-int hfa384x_cmd_writemif(hfa384x_t *hw)
|
|
|
-{
|
|
|
- DBFENTER;
|
|
|
- DBFEXIT;
|
|
|
- return 0;
|
|
|
-}
|
|
|
-#endif
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_copy_from_bap
|
|
|
-*
|
|
|
-* Copies a collection of bytes from the MAC controller memory via
|
|
|
-* one set of BAP registers.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* hw device structure
|
|
|
-* bap [0|1] which BAP to use
|
|
|
-* id FID or RID, destined for the select register (host order)
|
|
|
-* offset An _even_ offset into the buffer for the given
|
|
|
-* FID/RID. We haven't the means to validate this,
|
|
|
-* so be careful. (host order)
|
|
|
-* buf ptr to array of bytes
|
|
|
-* len length of data to transfer in bytes
|
|
|
-*
|
|
|
-* Returns:
|
|
|
-* 0 success
|
|
|
-* >0 f/w reported failure - value of offset reg.
|
|
|
-* <0 driver reported error (timeout|bad arg)
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* process thread
|
|
|
-* interrupt
|
|
|
-----------------------------------------------------------------*/
|
|
|
-int hfa384x_copy_from_bap(hfa384x_t *hw, UINT16 bap, UINT16 id, UINT16 offset,
|
|
|
- void *buf, UINT len)
|
|
|
-{
|
|
|
- int result = 0;
|
|
|
- unsigned long flags = 0;
|
|
|
- UINT8 *d = (UINT8*)buf;
|
|
|
- UINT selectreg;
|
|
|
- UINT offsetreg;
|
|
|
- UINT datareg;
|
|
|
- UINT i;
|
|
|
- UINT16 reg = 0;
|
|
|
-
|
|
|
- DBFENTER;
|
|
|
-
|
|
|
- /* Validate bap, offset, buf, and len */
|
|
|
- if ( (bap > 1) ||
|
|
|
- (offset > HFA384x_BAP_OFFSET_MAX) ||
|
|
|
- (offset % 2) ||
|
|
|
- (buf == NULL) ||
|
|
|
- (len > HFA384x_BAP_DATALEN_MAX) ){
|
|
|
- result = -EINVAL;
|
|
|
- } else {
|
|
|
- selectreg = (bap == 1) ? HFA384x_SELECT1 : HFA384x_SELECT0 ;
|
|
|
- offsetreg = (bap == 1) ? HFA384x_OFFSET1 : HFA384x_OFFSET0 ;
|
|
|
- datareg = (bap == 1) ? HFA384x_DATA1 : HFA384x_DATA0 ;
|
|
|
-
|
|
|
- /* Obtain lock */
|
|
|
- spin_lock_irqsave( &(hw->baplock), flags);
|
|
|
-
|
|
|
- /* Write id to select reg */
|
|
|
- hfa384x_setreg(hw, id, selectreg);
|
|
|
- /* Write offset to offset reg */
|
|
|
- hfa384x_setreg(hw, offset, offsetreg);
|
|
|
- /* Wait for offset[busy] to clear (see BAP_TIMEOUT) */
|
|
|
- i = 0;
|
|
|
- do {
|
|
|
- reg = hfa384x_getreg(hw, offsetreg);
|
|
|
- if ( i > 0 ) udelay(10);
|
|
|
- i++;
|
|
|
- } while ( i < prism2_bap_timeout && HFA384x_OFFSET_ISBUSY(reg));
|
|
|
-#if (WLAN_HOSTIF != WLAN_PCI)
|
|
|
- /* Release lock */
|
|
|
- spin_unlock_irqrestore( &(hw->baplock), flags);
|
|
|
-#endif
|
|
|
-
|
|
|
- if ( HFA384x_OFFSET_ISBUSY(reg) ){
|
|
|
- /* If timeout, return -ETIMEDOUT */
|
|
|
- result = reg;
|
|
|
- } else if ( HFA384x_OFFSET_ISERR(reg) ){
|
|
|
- /* If offset[err] == 1, return -EINVAL */
|
|
|
- result = reg;
|
|
|
- } else {
|
|
|
- /* Read even(len) buf contents from data reg */
|
|
|
- for ( i = 0; i < (len & 0xfffe); i+=2 ) {
|
|
|
- *(UINT16*)(&(d[i])) =
|
|
|
- hfa384x_getreg_noswap(hw, datareg);
|
|
|
- }
|
|
|
- /* If len odd, handle last byte */
|
|
|
- if ( len % 2 ){
|
|
|
- reg = hfa384x_getreg_noswap(hw, datareg);
|
|
|
- d[len-1] = ((UINT8*)(®))[0];
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /* According to Intersil errata dated 9/16/02:
|
|
|
-
|
|
|
- "In PRISM PCI MAC host interface, if both BAPs are concurrently
|
|
|
- requesing memory access, both will accept the Ack. There is no
|
|
|
- firmware workaround possible. To prevent BAP access failures or
|
|
|
- hang conditions the host MUST NOT access both BAPs in sucession
|
|
|
- unless at least 5us elapses between accesses. The safest choice
|
|
|
- is to USE ONLY ONE BAP for all data movement operations."
|
|
|
-
|
|
|
- What this means:
|
|
|
-
|
|
|
- We have to serialize ALL BAP accesses, and furthermore, add a 5us
|
|
|
- delay after access if we're using a PCI platform.
|
|
|
-
|
|
|
- Unfortunately, this means we have to lock out interrupts througout
|
|
|
- the entire BAP copy.
|
|
|
-
|
|
|
- It remains to be seen if "BAP access" means "BAP setup" or the more
|
|
|
- literal definition of "copying data back and forth" I'm erring for
|
|
|
- the latter, safer definition. -- SLP.
|
|
|
-
|
|
|
- */
|
|
|
-
|
|
|
-#if (WLAN_HOSTIF == WLAN_PCI)
|
|
|
- udelay(5);
|
|
|
- /* Release lock */
|
|
|
- spin_unlock_irqrestore( &(hw->baplock), flags);
|
|
|
-#endif
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- if (result) {
|
|
|
- WLAN_LOG_DEBUG(1,
|
|
|
- "copy_from_bap(0x%04x, 0, %d) failed, result=0x%x\n",
|
|
|
- reg, len, result);
|
|
|
- }
|
|
|
- DBFEXIT;
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_copy_to_bap
|
|
|
-*
|
|
|
-* Copies a collection of bytes to the MAC controller memory via
|
|
|
-* one set of BAP registers.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* hw device structure
|
|
|
-* bap [0|1] which BAP to use
|
|
|
-* id FID or RID, destined for the select register (host order)
|
|
|
-* offset An _even_ offset into the buffer for the given
|
|
|
-* FID/RID. We haven't the means to validate this,
|
|
|
-* so be careful. (host order)
|
|
|
-* buf ptr to array of bytes
|
|
|
-* len length of data to transfer (in bytes)
|
|
|
-*
|
|
|
-* Returns:
|
|
|
-* 0 success
|
|
|
-* >0 f/w reported failure - value of offset reg.
|
|
|
-* <0 driver reported error (timeout|bad arg)
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* process thread
|
|
|
-* interrupt
|
|
|
-----------------------------------------------------------------*/
|
|
|
-int hfa384x_copy_to_bap(hfa384x_t *hw, UINT16 bap, UINT16 id, UINT16 offset,
|
|
|
- void *buf, UINT len)
|
|
|
-{
|
|
|
- return hfa384x_copy_to_bap4(hw, bap, id, offset, buf, len, NULL, 0, NULL, 0, NULL, 0);
|
|
|
-}
|
|
|
-
|
|
|
-int hfa384x_copy_to_bap4(hfa384x_t *hw, UINT16 bap, UINT16 id, UINT16 offset,
|
|
|
- void *buf, UINT len1, void* buf2, UINT len2,
|
|
|
- void *buf3, UINT len3, void *buf4, UINT len4)
|
|
|
-{
|
|
|
- int result = 0;
|
|
|
- unsigned long flags = 0;
|
|
|
- UINT8 *d;
|
|
|
- UINT selectreg;
|
|
|
- UINT offsetreg;
|
|
|
- UINT datareg;
|
|
|
- UINT i;
|
|
|
- UINT16 reg;
|
|
|
-
|
|
|
- DBFENTER;
|
|
|
-
|
|
|
-// printk(KERN_DEBUG "ctb1 %d id %04x o %d %d %d %d %d\n", bap, id, offset, len1, len2, len3, len4);
|
|
|
-
|
|
|
- /* Validate bap, offset, buf, and len */
|
|
|
- if ( (bap > 1) ||
|
|
|
- (offset > HFA384x_BAP_OFFSET_MAX) ||
|
|
|
- (offset % 2) ||
|
|
|
- (buf == NULL) ||
|
|
|
- (len1+len2+len3+len4 > HFA384x_BAP_DATALEN_MAX) ){
|
|
|
- result = -EINVAL;
|
|
|
- } else {
|
|
|
- selectreg = (bap == 1) ? HFA384x_SELECT1 : HFA384x_SELECT0;
|
|
|
- offsetreg = (bap == 1) ? HFA384x_OFFSET1 : HFA384x_OFFSET0;
|
|
|
- datareg = (bap == 1) ? HFA384x_DATA1 : HFA384x_DATA0;
|
|
|
- /* Obtain lock */
|
|
|
- spin_lock_irqsave( &(hw->baplock), flags);
|
|
|
-
|
|
|
- /* Write id to select reg */
|
|
|
- hfa384x_setreg(hw, id, selectreg);
|
|
|
- udelay(10);
|
|
|
- /* Write offset to offset reg */
|
|
|
- hfa384x_setreg(hw, offset, offsetreg);
|
|
|
- /* Wait for offset[busy] to clear (see BAP_TIMEOUT) */
|
|
|
- i = 0;
|
|
|
- do {
|
|
|
- reg = hfa384x_getreg(hw, offsetreg);
|
|
|
- if ( i > 0 ) udelay(10);
|
|
|
- i++;
|
|
|
- } while ( i < prism2_bap_timeout && HFA384x_OFFSET_ISBUSY(reg));
|
|
|
-
|
|
|
-#if (WLAN_HOSTIF != WLAN_PCI)
|
|
|
- /* Release lock */
|
|
|
- spin_unlock_irqrestore( &(hw->baplock), flags);
|
|
|
-#endif
|
|
|
-
|
|
|
- if ( HFA384x_OFFSET_ISBUSY(reg) ){
|
|
|
- /* If timeout, return reg */
|
|
|
- result = reg;
|
|
|
- } else if ( HFA384x_OFFSET_ISERR(reg) ){
|
|
|
- /* If offset[err] == 1, return reg */
|
|
|
- result = reg;
|
|
|
- } else {
|
|
|
- d = (UINT8*)buf;
|
|
|
- /* Write even(len1) buf contents to data reg */
|
|
|
- for ( i = 0; i < (len1 & 0xfffe); i+=2 ) {
|
|
|
- hfa384x_setreg_noswap(hw,
|
|
|
- *(UINT16*)(&(d[i])), datareg);
|
|
|
- }
|
|
|
- if (len1 & 1) {
|
|
|
- UINT16 data;
|
|
|
- UINT8 *b = (UINT8 *) &data;
|
|
|
- b[0] = d[len1-1];
|
|
|
- if (buf2 != NULL) {
|
|
|
- d = (UINT8*)buf2;
|
|
|
- b[1] = d[0];
|
|
|
- len2--;
|
|
|
- buf2++;
|
|
|
- }
|
|
|
- hfa384x_setreg_noswap(hw, data, datareg);
|
|
|
- }
|
|
|
- if ((buf2 != NULL) && (len2 > 0)) {
|
|
|
- /* Write even(len2) buf contents to data reg */
|
|
|
- d = (UINT8*)buf2;
|
|
|
- for ( i = 0; i < (len2 & 0xfffe); i+=2 ) {
|
|
|
- hfa384x_setreg_noswap(hw, *(UINT16*)(&(d[i])), datareg);
|
|
|
- }
|
|
|
- if (len2 & 1) {
|
|
|
- UINT16 data;
|
|
|
- UINT8 *b = (UINT8 *) &data;
|
|
|
- b[0] = d[len2-1];
|
|
|
- if (buf3 != NULL) {
|
|
|
- d = (UINT8*)buf3;
|
|
|
- b[1] = d[0];
|
|
|
- len3--;
|
|
|
- buf3++;
|
|
|
- }
|
|
|
- hfa384x_setreg_noswap(hw, data, datareg);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if ((buf3 != NULL) && (len3 > 0)) {
|
|
|
- /* Write even(len3) buf contents to data reg */
|
|
|
- d = (UINT8*)buf3;
|
|
|
- for ( i = 0; i < (len3 & 0xfffe); i+=2 ) {
|
|
|
- hfa384x_setreg_noswap(hw, *(UINT16*)(&(d[i])), datareg);
|
|
|
- }
|
|
|
- if (len3 & 1) {
|
|
|
- UINT16 data;
|
|
|
- UINT8 *b = (UINT8 *) &data;
|
|
|
- b[0] = d[len3-1];
|
|
|
- if (buf4 != NULL) {
|
|
|
- d = (UINT8*)buf4;
|
|
|
- b[1] = d[0];
|
|
|
- len4--;
|
|
|
- buf4++;
|
|
|
- }
|
|
|
- hfa384x_setreg_noswap(hw, data, datareg);
|
|
|
- }
|
|
|
- }
|
|
|
- if ((buf4 != NULL) && (len4 > 0)) {
|
|
|
- /* Write even(len4) buf contents to data reg */
|
|
|
- d = (UINT8*)buf4;
|
|
|
- for ( i = 0; i < (len4 & 0xfffe); i+=2 ) {
|
|
|
- hfa384x_setreg_noswap(hw, *(UINT16*)(&(d[i])), datareg);
|
|
|
- }
|
|
|
- if (len4 & 1) {
|
|
|
- UINT16 data;
|
|
|
- UINT8 *b = (UINT8 *) &data;
|
|
|
- b[0] = d[len4-1];
|
|
|
- b[1] = 0;
|
|
|
-
|
|
|
- hfa384x_setreg_noswap(hw, data, datareg);
|
|
|
- }
|
|
|
- }
|
|
|
-// printk(KERN_DEBUG "ctb2 %d id %04x o %d %d %d %d %d\n", bap, id, offset, len1, len2, len3, len4);
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
-#if (WLAN_HOSTIF == WLAN_PCI)
|
|
|
- udelay(5);
|
|
|
- /* Release lock */
|
|
|
- spin_unlock_irqrestore( &(hw->baplock), flags);
|
|
|
-#endif
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- if (result)
|
|
|
- WLAN_LOG_ERROR("copy_to_bap() failed.\n");
|
|
|
-
|
|
|
- DBFEXIT;
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_copy_from_aux
|
|
|
-*
|
|
|
-* Copies a collection of bytes from the controller memory. The
|
|
|
-* Auxiliary port MUST be enabled prior to calling this function.
|
|
|
-* We _might_ be in a download state.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* hw device structure
|
|
|
-* cardaddr address in hfa384x data space to read
|
|
|
-* auxctl address space select
|
|
|
-* buf ptr to destination host buffer
|
|
|
-* len length of data to transfer (in bytes)
|
|
|
-*
|
|
|
-* Returns:
|
|
|
-* nothing
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-* buf contains the data copied
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* process thread
|
|
|
-* interrupt
|
|
|
-----------------------------------------------------------------*/
|
|
|
-void
|
|
|
-hfa384x_copy_from_aux(
|
|
|
- hfa384x_t *hw, UINT32 cardaddr, UINT32 auxctl, void *buf, UINT len)
|
|
|
-{
|
|
|
- UINT16 currpage;
|
|
|
- UINT16 curroffset;
|
|
|
- UINT i = 0;
|
|
|
-
|
|
|
- DBFENTER;
|
|
|
-
|
|
|
- if ( !(hw->auxen) ) {
|
|
|
- WLAN_LOG_DEBUG(1,
|
|
|
- "Attempt to read 0x%04x when aux not enabled\n",
|
|
|
- cardaddr);
|
|
|
- return;
|
|
|
-
|
|
|
- }
|
|
|
- /* Build appropriate aux page and offset */
|
|
|
- currpage = HFA384x_AUX_MKPAGE(cardaddr);
|
|
|
- curroffset = HFA384x_AUX_MKOFF(cardaddr, auxctl);
|
|
|
- hfa384x_setreg(hw, currpage, HFA384x_AUXPAGE);
|
|
|
- hfa384x_setreg(hw, curroffset, HFA384x_AUXOFFSET);
|
|
|
- udelay(5); /* beat */
|
|
|
-
|
|
|
- /* read the data */
|
|
|
- while ( i < len) {
|
|
|
- *((UINT16*)(buf+i)) = hfa384x_getreg_noswap(hw, HFA384x_AUXDATA);
|
|
|
- i+=2;
|
|
|
- curroffset+=2;
|
|
|
- if ( (curroffset&HFA384x_ADDR_AUX_OFF_MASK) >
|
|
|
- HFA384x_ADDR_AUX_OFF_MAX ) {
|
|
|
- currpage++;
|
|
|
- curroffset = 0;
|
|
|
- curroffset = HFA384x_AUX_MKOFF(curroffset, auxctl);
|
|
|
- hfa384x_setreg(hw, currpage, HFA384x_AUXPAGE);
|
|
|
- hfa384x_setreg(hw, curroffset, HFA384x_AUXOFFSET);
|
|
|
- udelay(5); /* beat */
|
|
|
- }
|
|
|
- }
|
|
|
- /* Make sure the auxctl bits are clear */
|
|
|
- hfa384x_setreg(hw, 0, HFA384x_AUXOFFSET);
|
|
|
- DBFEXIT;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_copy_to_aux
|
|
|
-*
|
|
|
-* Copies a collection of bytes to the controller memory. The
|
|
|
-* Auxiliary port MUST be enabled prior to calling this function.
|
|
|
-* We _might_ be in a download state.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* hw device structure
|
|
|
-* cardaddr address in hfa384x data space to read
|
|
|
-* auxctl address space select
|
|
|
-* buf ptr to destination host buffer
|
|
|
-* len length of data to transfer (in bytes)
|
|
|
-*
|
|
|
-* Returns:
|
|
|
-* nothing
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-* Controller memory now contains a copy of buf
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* process thread
|
|
|
-* interrupt
|
|
|
-----------------------------------------------------------------*/
|
|
|
-void
|
|
|
-hfa384x_copy_to_aux(
|
|
|
- hfa384x_t *hw, UINT32 cardaddr, UINT32 auxctl, void *buf, UINT len)
|
|
|
-{
|
|
|
- UINT16 currpage;
|
|
|
- UINT16 curroffset;
|
|
|
- UINT i = 0;
|
|
|
-
|
|
|
- DBFENTER;
|
|
|
-
|
|
|
- if ( !(hw->auxen) ) {
|
|
|
- WLAN_LOG_DEBUG(1,
|
|
|
- "Attempt to read 0x%04x when aux not enabled\n",
|
|
|
- cardaddr);
|
|
|
- return;
|
|
|
-
|
|
|
- }
|
|
|
- /* Build appropriate aux page and offset */
|
|
|
- currpage = HFA384x_AUX_MKPAGE(cardaddr);
|
|
|
- curroffset = HFA384x_AUX_MKOFF(cardaddr, auxctl);
|
|
|
- hfa384x_setreg(hw, currpage, HFA384x_AUXPAGE);
|
|
|
- hfa384x_setreg(hw, curroffset, HFA384x_AUXOFFSET);
|
|
|
- udelay(5); /* beat */
|
|
|
-
|
|
|
- /* write the data */
|
|
|
- while ( i < len) {
|
|
|
- hfa384x_setreg_noswap(hw,
|
|
|
- *((UINT16*)(buf+i)), HFA384x_AUXDATA);
|
|
|
- i+=2;
|
|
|
- curroffset+=2;
|
|
|
- if ( curroffset > HFA384x_ADDR_AUX_OFF_MAX ) {
|
|
|
- currpage++;
|
|
|
- curroffset = 0;
|
|
|
- hfa384x_setreg(hw, currpage, HFA384x_AUXPAGE);
|
|
|
- hfa384x_setreg(hw, curroffset, HFA384x_AUXOFFSET);
|
|
|
- udelay(5); /* beat */
|
|
|
- }
|
|
|
- }
|
|
|
- DBFEXIT;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_cmd_wait
|
|
|
-*
|
|
|
-* Waits for availability of the Command register, then
|
|
|
-* issues the given command. Then polls the Evstat register
|
|
|
-* waiting for command completion. Timeouts shouldn't be
|
|
|
-* possible since we're preventing overlapping commands and all
|
|
|
-* commands should be cleared and acknowledged.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* wlandev device structure
|
|
|
-* cmd cmd structure. Includes all arguments and result
|
|
|
-* data points. All in host order.
|
|
|
-*
|
|
|
-* Returns:
|
|
|
-* 0 success
|
|
|
-* -ETIMEDOUT timed out waiting for register ready or
|
|
|
-* command completion
|
|
|
-* >0 command indicated error, Status and Resp0-2 are
|
|
|
-* in hw structure.
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-*
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* process thread
|
|
|
-----------------------------------------------------------------*/
|
|
|
-static int hfa384x_docmd_wait( hfa384x_t *hw, hfa384x_metacmd_t *cmd)
|
|
|
-{
|
|
|
- int result = -ETIMEDOUT;
|
|
|
- UINT16 reg = 0;
|
|
|
- UINT16 counter;
|
|
|
-
|
|
|
- DBFENTER;
|
|
|
-
|
|
|
- hw->cmdflag = 0;
|
|
|
- hw->cmddata = cmd;
|
|
|
-
|
|
|
- /* wait for the busy bit to clear */
|
|
|
- counter = 0;
|
|
|
- reg = hfa384x_getreg(hw, HFA384x_CMD);
|
|
|
- while ( HFA384x_CMD_ISBUSY(reg) &&
|
|
|
- (counter < 10)) {
|
|
|
- reg = hfa384x_getreg(hw, HFA384x_CMD);
|
|
|
- counter++;
|
|
|
- udelay(10);
|
|
|
- }
|
|
|
-
|
|
|
- if (HFA384x_CMD_ISBUSY(reg)) {
|
|
|
- WLAN_LOG_ERROR("hfa384x_cmd timeout(1), reg=0x%0hx.\n", reg);
|
|
|
- goto failed;
|
|
|
- }
|
|
|
- if (!HFA384x_CMD_ISBUSY(reg)) {
|
|
|
- /* busy bit clear, write command */
|
|
|
- hfa384x_setreg(hw, cmd->parm0, HFA384x_PARAM0);
|
|
|
- hfa384x_setreg(hw, cmd->parm1, HFA384x_PARAM1);
|
|
|
- hfa384x_setreg(hw, cmd->parm2, HFA384x_PARAM2);
|
|
|
- hfa384x_setreg(hw, cmd->cmd, HFA384x_CMD);
|
|
|
-
|
|
|
-#ifdef CMD_IRQ
|
|
|
-
|
|
|
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0))
|
|
|
- while (! hw->cmdflag)
|
|
|
- interruptible_sleep_on(&hw->cmdq);
|
|
|
-#else
|
|
|
- wait_event_interruptible(hw->cmdq, hw->cmdflag);
|
|
|
-#endif
|
|
|
- result = HFA384x_STATUS_RESULT_GET(cmd->status);
|
|
|
-#else // CMD_IRQ
|
|
|
- /* Now wait for completion */
|
|
|
- counter = 0;
|
|
|
- reg = hfa384x_getreg(hw, HFA384x_EVSTAT);
|
|
|
- /* Initialization is the problem. It takes about
|
|
|
- 100ms. "normal" commands are typically is about
|
|
|
- 200-400 us (I've never seen less than 200). Longer
|
|
|
- is better so that we're not hammering the bus. */
|
|
|
- while ( !HFA384x_EVSTAT_ISCMD(reg) &&
|
|
|
- (counter < 5000)) {
|
|
|
- reg = hfa384x_getreg(hw, HFA384x_EVSTAT);
|
|
|
- counter++;
|
|
|
- udelay(200);
|
|
|
- }
|
|
|
-
|
|
|
- if ( HFA384x_EVSTAT_ISCMD(reg) ) {
|
|
|
- result = 0;
|
|
|
- cmd->result.status = hfa384x_getreg(hw, HFA384x_STATUS);
|
|
|
- cmd->result.resp0 = hfa384x_getreg(hw, HFA384x_RESP0);
|
|
|
- cmd->result.resp1 = hfa384x_getreg(hw, HFA384x_RESP1);
|
|
|
- cmd->result.resp2 = hfa384x_getreg(hw, HFA384x_RESP2);
|
|
|
- hfa384x_setreg(hw, HFA384x_EVACK_CMD,
|
|
|
- HFA384x_EVACK);
|
|
|
- result = HFA384x_STATUS_RESULT_GET(cmd->result.status);
|
|
|
- } else {
|
|
|
- WLAN_LOG_ERROR("hfa384x_cmd timeout(2), reg=0x%0hx.\n", reg);
|
|
|
- }
|
|
|
-#endif /* CMD_IRQ */
|
|
|
- }
|
|
|
-
|
|
|
- failed:
|
|
|
- hw->cmdflag = 0;
|
|
|
- hw->cmddata = NULL;
|
|
|
-
|
|
|
- DBFEXIT;
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_dl_docmd_wait
|
|
|
-*
|
|
|
-* Waits for availability of the Command register, then
|
|
|
-* issues the given command. Then polls the Evstat register
|
|
|
-* waiting for command completion. Timeouts shouldn't be
|
|
|
-* possible since we're preventing overlapping commands and all
|
|
|
-* commands should be cleared and acknowledged.
|
|
|
-*
|
|
|
-* This routine is only used for downloads. Since it doesn't lock out
|
|
|
-* interrupts the system response is much better.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* wlandev device structure
|
|
|
-* cmd cmd structure. Includes all arguments and result
|
|
|
-* data points. All in host order.
|
|
|
-*
|
|
|
-* Returns:
|
|
|
-* 0 success
|
|
|
-* -ETIMEDOUT timed out waiting for register ready or
|
|
|
-* command completion
|
|
|
-* >0 command indicated error, Status and Resp0-2 are
|
|
|
-* in hw structure.
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-*
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* process thread
|
|
|
-----------------------------------------------------------------*/
|
|
|
-static int hfa384x_dl_docmd_wait( hfa384x_t *hw, hfa384x_metacmd_t *cmd)
|
|
|
-{
|
|
|
- int result = -ETIMEDOUT;
|
|
|
- unsigned long timeout;
|
|
|
- UINT16 reg = 0;
|
|
|
-
|
|
|
- DBFENTER;
|
|
|
- /* wait for the busy bit to clear */
|
|
|
- timeout = jiffies + 1*HZ;
|
|
|
- reg = hfa384x_getreg(hw, HFA384x_CMD);
|
|
|
- while ( HFA384x_CMD_ISBUSY(reg) && time_before( jiffies, timeout) ) {
|
|
|
- reg = hfa384x_getreg(hw, HFA384x_CMD);
|
|
|
- udelay(10);
|
|
|
- }
|
|
|
- if (HFA384x_CMD_ISBUSY(reg)) {
|
|
|
- WLAN_LOG_WARNING("Timed out waiting for cmd register.\n");
|
|
|
- goto failed;
|
|
|
- }
|
|
|
-
|
|
|
- if (!HFA384x_CMD_ISBUSY(reg)) {
|
|
|
- /* busy bit clear, write command */
|
|
|
- hfa384x_setreg(hw, cmd->parm0, HFA384x_PARAM0);
|
|
|
- hfa384x_setreg(hw, cmd->parm1, HFA384x_PARAM1);
|
|
|
- hfa384x_setreg(hw, cmd->parm2, HFA384x_PARAM2);
|
|
|
- hfa384x_setreg(hw, cmd->cmd, HFA384x_CMD);
|
|
|
-
|
|
|
- /* Now wait for completion */
|
|
|
- if ( (HFA384x_CMD_CMDCODE_GET(cmd->cmd) == HFA384x_CMDCODE_DOWNLD) ) {
|
|
|
- /* dltimeout is in ms */
|
|
|
- timeout = (((UINT32)hw->dltimeout) / 1000UL) * HZ;
|
|
|
- if ( timeout > 0 ) {
|
|
|
- timeout += jiffies;
|
|
|
- } else {
|
|
|
- timeout = jiffies + 1*HZ;
|
|
|
- }
|
|
|
- } else {
|
|
|
- timeout = jiffies + 1*HZ;
|
|
|
- }
|
|
|
- reg = hfa384x_getreg(hw, HFA384x_EVSTAT);
|
|
|
- while ( !HFA384x_EVSTAT_ISCMD(reg) && time_before(jiffies,timeout) ) {
|
|
|
- udelay(100);
|
|
|
- reg = hfa384x_getreg(hw, HFA384x_EVSTAT);
|
|
|
- }
|
|
|
- if ( HFA384x_EVSTAT_ISCMD(reg) ) {
|
|
|
- result = 0;
|
|
|
- cmd->result.status = hfa384x_getreg(hw, HFA384x_STATUS);
|
|
|
- cmd->result.resp0 = hfa384x_getreg(hw, HFA384x_RESP0);
|
|
|
- cmd->result.resp1 = hfa384x_getreg(hw, HFA384x_RESP1);
|
|
|
- cmd->result.resp2 = hfa384x_getreg(hw, HFA384x_RESP2);
|
|
|
- hfa384x_setreg(hw, HFA384x_EVACK_CMD, HFA384x_EVACK);
|
|
|
- result = HFA384x_STATUS_RESULT_GET(cmd->result.status);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-failed:
|
|
|
- DBFEXIT;
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_drvr_start
|
|
|
-*
|
|
|
-* Issues the MAC initialize command, sets up some data structures,
|
|
|
-* and enables the interrupts. After this function completes, the
|
|
|
-* low-level stuff should be ready for any/all commands.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* hw device structure
|
|
|
-* 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_start(hfa384x_t *hw)
|
|
|
-{
|
|
|
- int result = 0;
|
|
|
- UINT16 reg;
|
|
|
- int i;
|
|
|
- int j;
|
|
|
- DBFENTER;
|
|
|
-
|
|
|
- /* call initialize */
|
|
|
- result = hfa384x_cmd_initialize(hw);
|
|
|
- if (result != 0) {
|
|
|
- WLAN_LOG_ERROR("Initialize command failed.\n");
|
|
|
- goto failed;
|
|
|
- }
|
|
|
-
|
|
|
- /* make sure interrupts are disabled and any layabout events cleared */
|
|
|
- hfa384x_setreg(hw, 0, HFA384x_INTEN);
|
|
|
- hfa384x_setreg(hw, 0xffff, HFA384x_EVACK);
|
|
|
-
|
|
|
- hw->txfid_head = 0;
|
|
|
- hw->txfid_tail = 0;
|
|
|
- hw->txfid_N = HFA384x_DRVR_FIDSTACKLEN_MAX;
|
|
|
- memset(hw->txfid_queue, 0, sizeof(hw->txfid_queue));
|
|
|
-
|
|
|
- /* Allocate tx and notify FIDs */
|
|
|
- /* First, tx */
|
|
|
- for ( i = 0; i < HFA384x_DRVR_FIDSTACKLEN_MAX-1; i++) {
|
|
|
- result = hfa384x_cmd_allocate(hw, HFA384x_DRVR_TXBUF_MAX);
|
|
|
- if (result != 0) {
|
|
|
- WLAN_LOG_ERROR("Allocate(tx) command failed.\n");
|
|
|
- goto failed;
|
|
|
- }
|
|
|
- j = 0;
|
|
|
- do {
|
|
|
- reg = hfa384x_getreg(hw, HFA384x_EVSTAT);
|
|
|
- udelay(10);
|
|
|
- j++;
|
|
|
- } while ( !HFA384x_EVSTAT_ISALLOC(reg) && j < 50); /* 50 is timeout */
|
|
|
- if ( j >= 50 ) {
|
|
|
- WLAN_LOG_ERROR("Timed out waiting for evalloc(tx).\n");
|
|
|
- result = -ETIMEDOUT;
|
|
|
- goto failed;
|
|
|
- }
|
|
|
- reg = hfa384x_getreg(hw, HFA384x_ALLOCFID);
|
|
|
-
|
|
|
- txfid_queue_add(hw, reg);
|
|
|
-
|
|
|
- WLAN_LOG_DEBUG(4,"hw->txfid_queue[%d]=0x%04x\n",i,reg);
|
|
|
-
|
|
|
- reg = HFA384x_EVACK_ALLOC_SET(1);
|
|
|
- hfa384x_setreg(hw, reg, HFA384x_EVACK);
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- /* Now, the info frame fid */
|
|
|
- result = hfa384x_cmd_allocate(hw, HFA384x_INFOFRM_MAXLEN);
|
|
|
- if (result != 0) {
|
|
|
- WLAN_LOG_ERROR("Allocate(tx) command failed.\n");
|
|
|
- goto failed;
|
|
|
- }
|
|
|
- i = 0;
|
|
|
- do {
|
|
|
- reg = hfa384x_getreg(hw, HFA384x_EVSTAT);
|
|
|
- udelay(10);
|
|
|
- i++;
|
|
|
- } while ( !HFA384x_EVSTAT_ISALLOC(reg) && i < 50); /* 50 is timeout */
|
|
|
- if ( i >= 50 ) {
|
|
|
- WLAN_LOG_ERROR("Timed out waiting for evalloc(info).\n");
|
|
|
- result = -ETIMEDOUT;
|
|
|
- goto failed;
|
|
|
- }
|
|
|
- hw->infofid = hfa384x_getreg(hw, HFA384x_ALLOCFID);
|
|
|
- reg = HFA384x_EVACK_ALLOC_SET(1);
|
|
|
- hfa384x_setreg(hw, reg, HFA384x_EVACK);
|
|
|
- WLAN_LOG_DEBUG(4,"hw->infofid=0x%04x\n", hw->infofid);
|
|
|
-
|
|
|
- /* Set swsupport regs to magic # for card presence detection */
|
|
|
- hfa384x_setreg(hw, HFA384x_DRVR_MAGIC, HFA384x_SWSUPPORT0);
|
|
|
-
|
|
|
- /* Now enable the interrupts and set the running state */
|
|
|
- hfa384x_setreg(hw, 0xffff, HFA384x_EVSTAT);
|
|
|
- hfa384x_events_all(hw);
|
|
|
-
|
|
|
- hw->state = HFA384x_STATE_RUNNING;
|
|
|
-
|
|
|
- goto done;
|
|
|
-failed:
|
|
|
- WLAN_LOG_ERROR("Failed, result=%d\n", result);
|
|
|
-done:
|
|
|
- DBFEXIT;
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_drvr_stop
|
|
|
-*
|
|
|
-* Issues the initialize command to leave us in the 'reset' state.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* hw device structure
|
|
|
-* 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_stop(hfa384x_t *hw)
|
|
|
-{
|
|
|
- int result = 0;
|
|
|
- int i;
|
|
|
- DBFENTER;
|
|
|
-
|
|
|
- del_timer_sync(&hw->commsqual_timer);
|
|
|
-
|
|
|
- if ( hw->wlandev->hwremoved ) {
|
|
|
- /* only flush when we're shutting down for good */
|
|
|
- flush_scheduled_work();
|
|
|
- }
|
|
|
-
|
|
|
- if (hw->state == HFA384x_STATE_RUNNING) {
|
|
|
- /*
|
|
|
- * Send the MAC initialize cmd.
|
|
|
- */
|
|
|
- hfa384x_cmd_initialize(hw);
|
|
|
-
|
|
|
- /*
|
|
|
- * Make absolutely sure interrupts are disabled and any
|
|
|
- * layabout events cleared
|
|
|
- */
|
|
|
- hfa384x_setreg(hw, 0, HFA384x_INTEN);
|
|
|
- hfa384x_setreg(hw, 0xffff, HFA384x_EVACK);
|
|
|
- }
|
|
|
-
|
|
|
- tasklet_kill(&hw->bap_tasklet);
|
|
|
-
|
|
|
- hw->link_status = HFA384x_LINK_NOTCONNECTED;
|
|
|
- hw->state = HFA384x_STATE_INIT;
|
|
|
-
|
|
|
- /* Clear all the port status */
|
|
|
- for ( i = 0; i < HFA384x_NUMPORTS_MAX; i++) {
|
|
|
- hw->port_enabled[i] = 0;
|
|
|
- }
|
|
|
-
|
|
|
- DBFEXIT;
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_drvr_txframe
|
|
|
-*
|
|
|
-* Takes a frame from prism2sta and queues it for transmission.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* hw device structure
|
|
|
-* skb packet buffer struct. Contains an 802.11
|
|
|
-* data frame.
|
|
|
-* p80211_hdr points to the 802.11 header for the packet.
|
|
|
-* Returns:
|
|
|
-* 0 Success and more buffs available
|
|
|
-* 1 Success but no more buffs
|
|
|
-* 2 Allocation failure
|
|
|
-* 3 MAC Tx command failed
|
|
|
-* 4 Buffer full or queue busy
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* process thread
|
|
|
-----------------------------------------------------------------*/
|
|
|
-int hfa384x_drvr_txframe(hfa384x_t *hw, struct sk_buff *skb, p80211_hdr_t *p80211_hdr, p80211_metawep_t *p80211_wep)
|
|
|
-{
|
|
|
- hfa384x_tx_frame_t txdesc;
|
|
|
- UINT16 macq = 0;
|
|
|
- UINT16 fid;
|
|
|
- int result;
|
|
|
-
|
|
|
- DBFENTER;
|
|
|
-
|
|
|
- /* Build Tx frame structure */
|
|
|
- /* Set up the control field */
|
|
|
- memset(&txdesc, 0, sizeof(txdesc));
|
|
|
-
|
|
|
-/* Tx complete and Tx exception disable per dleach. Might be causing
|
|
|
- * buf depletion
|
|
|
- */
|
|
|
-#define DOBOTH 1
|
|
|
-#if DOBOTH
|
|
|
- txdesc.tx_control =
|
|
|
- HFA384x_TX_MACPORT_SET(0) | HFA384x_TX_STRUCTYPE_SET(1) |
|
|
|
- HFA384x_TX_TXEX_SET(1) | HFA384x_TX_TXOK_SET(1);
|
|
|
-#elif DOEXC
|
|
|
- txdesc.tx_control =
|
|
|
- HFA384x_TX_MACPORT_SET(0) | HFA384x_TX_STRUCTYPE_SET(1) |
|
|
|
- HFA384x_TX_TXEX_SET(1) | HFA384x_TX_TXOK_SET(0);
|
|
|
-#else
|
|
|
- txdesc.tx_control =
|
|
|
- HFA384x_TX_MACPORT_SET(0) | HFA384x_TX_STRUCTYPE_SET(1) |
|
|
|
- HFA384x_TX_TXEX_SET(0) | HFA384x_TX_TXOK_SET(0);
|
|
|
-#endif
|
|
|
-
|
|
|
- /* if we're using host WEP, increase size by IV+ICV */
|
|
|
- if (p80211_wep->data) {
|
|
|
- txdesc.data_len = host2hfa384x_16(skb->len+8);
|
|
|
- // txdesc.tx_control |= HFA384x_TX_NOENCRYPT_SET(1);
|
|
|
- } else {
|
|
|
- txdesc.data_len = host2hfa384x_16(skb->len);
|
|
|
- }
|
|
|
-
|
|
|
- txdesc.tx_control = host2hfa384x_16(txdesc.tx_control);
|
|
|
- /* copy the header over to the txdesc */
|
|
|
- memcpy(&(txdesc.frame_control), p80211_hdr, sizeof(p80211_hdr_t));
|
|
|
-
|
|
|
- /* Since tbusy is set whenever the stack is empty, there should
|
|
|
- * always be something on the stack if we get to this point.
|
|
|
- * [MSM]: NOT TRUE!!!!! so I added the test of fid below.
|
|
|
- */
|
|
|
-
|
|
|
- /* Allocate FID */
|
|
|
-
|
|
|
- fid = txfid_queue_remove(hw);
|
|
|
-
|
|
|
- if ( fid == 0 ) { /* stack or queue was empty */
|
|
|
- return 4;
|
|
|
- }
|
|
|
-
|
|
|
- /* now let's get the cmdlock */
|
|
|
- spin_lock(&hw->cmdlock);
|
|
|
-
|
|
|
- /* Copy descriptor+payload to FID */
|
|
|
- if (p80211_wep->data) {
|
|
|
- result = hfa384x_copy_to_bap4(hw, HFA384x_BAP_PROC, fid, 0,
|
|
|
- &txdesc, sizeof(txdesc),
|
|
|
- p80211_wep->iv, sizeof(p80211_wep->iv),
|
|
|
- p80211_wep->data, skb->len,
|
|
|
- p80211_wep->icv, sizeof(p80211_wep->icv));
|
|
|
- } else {
|
|
|
- result = hfa384x_copy_to_bap4(hw, HFA384x_BAP_PROC, fid, 0,
|
|
|
- &txdesc, sizeof(txdesc),
|
|
|
- skb->data, skb->len,
|
|
|
- NULL, 0, NULL, 0);
|
|
|
- }
|
|
|
-
|
|
|
- if ( result ) {
|
|
|
- WLAN_LOG_DEBUG(1,
|
|
|
- "copy_to_bap(%04x, %d, %d) failed, result=0x%x\n",
|
|
|
- fid,
|
|
|
- sizeof(txdesc),
|
|
|
- skb->len,
|
|
|
- result);
|
|
|
-
|
|
|
- /* put the fid back in the queue */
|
|
|
- txfid_queue_add(hw, fid);
|
|
|
-
|
|
|
- result = 3;
|
|
|
- goto failed;
|
|
|
- }
|
|
|
-
|
|
|
- /* Issue Tx command */
|
|
|
- result = hfa384x_cmd_transmit(hw, HFA384x_TXCMD_RECL, macq, fid);
|
|
|
-
|
|
|
- if ( result != 0 ) {
|
|
|
- txfid_queue_add(hw, fid);
|
|
|
-
|
|
|
- WLAN_LOG_DEBUG(1,"cmd_tx(%04x) failed, result=%d\n",
|
|
|
- fid, result);
|
|
|
- result = 3;
|
|
|
- goto failed;
|
|
|
- }
|
|
|
-
|
|
|
- /* indicate we haven't any buffers, int_alloc will clear */
|
|
|
- result = txfid_queue_empty(hw);
|
|
|
-failed:
|
|
|
-
|
|
|
- spin_unlock(&hw->cmdlock);
|
|
|
-
|
|
|
- DBFEXIT;
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_interrupt
|
|
|
-*
|
|
|
-* Driver interrupt handler.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* irq irq number
|
|
|
-* dev_id pointer to the device
|
|
|
-* regs registers
|
|
|
-*
|
|
|
-* Returns:
|
|
|
-* nothing
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-* May result in a frame being passed up the stack or an info
|
|
|
-* frame being handled.
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* Ummm, could it be interrupt?
|
|
|
-----------------------------------------------------------------*/
|
|
|
-irqreturn_t hfa384x_interrupt(int irq, void *dev_id PT_REGS)
|
|
|
-{
|
|
|
- int reg;
|
|
|
- wlandevice_t *wlandev = (wlandevice_t*)dev_id;
|
|
|
- hfa384x_t *hw = wlandev->priv;
|
|
|
- int ev_read = 0;
|
|
|
- DBFENTER;
|
|
|
-
|
|
|
- if (!wlandev || wlandev->hwremoved)
|
|
|
- return IRQ_NONE; /* Not much we can do w/o hardware */
|
|
|
-#if (WLAN_HOSTIF == WLAN_PCMCIA)
|
|
|
- if (hw->iobase == 0) /* XXX FIXME Properly */
|
|
|
- return IRQ_NONE;
|
|
|
-#endif
|
|
|
-
|
|
|
- for (;;ev_read++) {
|
|
|
- if (ev_read >= prism2_irq_evread_max)
|
|
|
- break;
|
|
|
-
|
|
|
- /* Check swsupport reg magic # for card presence */
|
|
|
- reg = hfa384x_getreg(hw, HFA384x_SWSUPPORT0);
|
|
|
- if ( reg != HFA384x_DRVR_MAGIC) {
|
|
|
- WLAN_LOG_DEBUG(2, "irq=%d, no magic. Card removed?.\n", irq);
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- /* read the EvStat register for interrupt enabled events */
|
|
|
- reg = hfa384x_getreg(hw, HFA384x_EVSTAT);
|
|
|
-
|
|
|
- /* AND with the enabled interrupts */
|
|
|
- reg &= hfa384x_getreg(hw, HFA384x_INTEN);
|
|
|
-
|
|
|
- /* Handle the events */
|
|
|
- if ( HFA384x_EVSTAT_ISWTERR(reg) ){
|
|
|
- WLAN_LOG_ERROR(
|
|
|
- "Error: WTERR interrupt received (unhandled).\n");
|
|
|
- hfa384x_setreg(hw, HFA384x_EVACK_WTERR_SET(1),
|
|
|
- HFA384x_EVACK);
|
|
|
- }
|
|
|
-
|
|
|
- if ( HFA384x_EVSTAT_ISINFDROP(reg) ){
|
|
|
- hfa384x_int_infdrop(wlandev);
|
|
|
- hfa384x_setreg(hw, HFA384x_EVACK_INFDROP_SET(1),
|
|
|
- HFA384x_EVACK);
|
|
|
- }
|
|
|
-
|
|
|
- if (HFA384x_EVSTAT_ISBAP_OP(reg)) {
|
|
|
- /* Disable the BAP interrupts */
|
|
|
- hfa384x_events_nobap(hw);
|
|
|
- tasklet_schedule(&hw->bap_tasklet);
|
|
|
- }
|
|
|
-
|
|
|
- if ( HFA384x_EVSTAT_ISALLOC(reg) ){
|
|
|
- hfa384x_int_alloc(wlandev);
|
|
|
- hfa384x_setreg(hw, HFA384x_EVACK_ALLOC_SET(1),
|
|
|
- HFA384x_EVACK);
|
|
|
- }
|
|
|
-
|
|
|
- if ( HFA384x_EVSTAT_ISDTIM(reg) ){
|
|
|
- hfa384x_int_dtim(wlandev);
|
|
|
- hfa384x_setreg(hw, HFA384x_EVACK_DTIM_SET(1),
|
|
|
- HFA384x_EVACK);
|
|
|
- }
|
|
|
-#ifdef CMD_IRQ
|
|
|
- if ( HFA384x_EVSTAT_ISCMD(reg) ){
|
|
|
- hfa384x_int_cmd(wlandev);
|
|
|
- hfa384x_setreg(hw, HFA384x_EVACK_CMD_SET(1),
|
|
|
- HFA384x_EVACK);
|
|
|
- }
|
|
|
-#endif
|
|
|
-
|
|
|
- /* allow the evstat to be updated after the evack */
|
|
|
- udelay(20);
|
|
|
- }
|
|
|
-
|
|
|
- DBFEXIT;
|
|
|
- return IRQ_HANDLED;
|
|
|
-}
|
|
|
-
|
|
|
-#ifdef CMD_IRQ
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_int_cmd
|
|
|
-*
|
|
|
-* Handles command completion event.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* wlandev wlan device structure
|
|
|
-*
|
|
|
-* Returns:
|
|
|
-* nothing
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* interrupt
|
|
|
-----------------------------------------------------------------*/
|
|
|
-void hfa384x_int_cmd(wlandevice_t *wlandev)
|
|
|
-{
|
|
|
- hfa384x_t *hw = wlandev->priv;
|
|
|
- DBFENTER;
|
|
|
-
|
|
|
- // check to make sure it's the right command?
|
|
|
- if (hw->cmddata) {
|
|
|
- hw->cmddata->status = hfa384x_getreg(hw, HFA384x_STATUS);
|
|
|
- hw->cmddata->resp0 = hfa384x_getreg(hw, HFA384x_RESP0);
|
|
|
- hw->cmddata->resp1 = hfa384x_getreg(hw, HFA384x_RESP1);
|
|
|
- hw->cmddata->resp2 = hfa384x_getreg(hw, HFA384x_RESP2);
|
|
|
- }
|
|
|
- hw->cmdflag = 1;
|
|
|
-
|
|
|
- printk(KERN_INFO "um. int_cmd\n");
|
|
|
-
|
|
|
- wake_up_interruptible(&hw->cmdq);
|
|
|
-
|
|
|
- // XXXX perform a bap copy too?
|
|
|
-
|
|
|
- DBFEXIT;
|
|
|
- return;
|
|
|
-}
|
|
|
-#endif
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_int_dtim
|
|
|
-*
|
|
|
-* Handles the DTIM early warning event.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* wlandev wlan device structure
|
|
|
-*
|
|
|
-* Returns:
|
|
|
-* nothing
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* interrupt
|
|
|
-----------------------------------------------------------------*/
|
|
|
-static void hfa384x_int_dtim(wlandevice_t *wlandev)
|
|
|
-{
|
|
|
-#if 0
|
|
|
- hfa384x_t *hw = wlandev->priv;
|
|
|
-#endif
|
|
|
- DBFENTER;
|
|
|
- prism2sta_ev_dtim(wlandev);
|
|
|
- DBFEXIT;
|
|
|
- return;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_int_infdrop
|
|
|
-*
|
|
|
-* Handles the InfDrop event.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* wlandev wlan device structure
|
|
|
-*
|
|
|
-* Returns:
|
|
|
-* nothing
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* interrupt
|
|
|
-----------------------------------------------------------------*/
|
|
|
-static void hfa384x_int_infdrop(wlandevice_t *wlandev)
|
|
|
-{
|
|
|
-#if 0
|
|
|
- hfa384x_t *hw = wlandev->priv;
|
|
|
-#endif
|
|
|
- DBFENTER;
|
|
|
- prism2sta_ev_infdrop(wlandev);
|
|
|
- DBFEXIT;
|
|
|
- return;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_int_info
|
|
|
-*
|
|
|
-* Handles the Info event.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* wlandev wlan device structure
|
|
|
-*
|
|
|
-* Returns:
|
|
|
-* nothing
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* tasklet
|
|
|
-----------------------------------------------------------------*/
|
|
|
-static void hfa384x_int_info(wlandevice_t *wlandev)
|
|
|
-{
|
|
|
- hfa384x_t *hw = wlandev->priv;
|
|
|
- UINT16 reg;
|
|
|
- hfa384x_InfFrame_t inf;
|
|
|
- int result;
|
|
|
- DBFENTER;
|
|
|
- /* Retrieve the FID */
|
|
|
- reg = hfa384x_getreg(hw, HFA384x_INFOFID);
|
|
|
-
|
|
|
- /* Retrieve the length */
|
|
|
- result = hfa384x_copy_from_bap( hw,
|
|
|
- HFA384x_BAP_INT, reg, 0, &inf.framelen, sizeof(UINT16));
|
|
|
- if ( result ) {
|
|
|
- WLAN_LOG_DEBUG(1,
|
|
|
- "copy_from_bap(0x%04x, 0, %d) failed, result=0x%x\n",
|
|
|
- reg, sizeof(inf), result);
|
|
|
- goto failed;
|
|
|
- }
|
|
|
- inf.framelen = hfa384x2host_16(inf.framelen);
|
|
|
-
|
|
|
- /* Retrieve the rest */
|
|
|
- result = hfa384x_copy_from_bap( hw,
|
|
|
- HFA384x_BAP_INT, reg, sizeof(UINT16),
|
|
|
- &(inf.infotype), inf.framelen * sizeof(UINT16));
|
|
|
- if ( result ) {
|
|
|
- WLAN_LOG_DEBUG(1,
|
|
|
- "copy_from_bap(0x%04x, 0, %d) failed, result=0x%x\n",
|
|
|
- reg, sizeof(inf), result);
|
|
|
- goto failed;
|
|
|
- }
|
|
|
-
|
|
|
- prism2sta_ev_info(wlandev, &inf);
|
|
|
-failed:
|
|
|
- DBFEXIT;
|
|
|
- return;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_int_txexc
|
|
|
-*
|
|
|
-* Handles the TxExc event. A Transmit Exception event indicates
|
|
|
-* that the MAC's TX process was unsuccessful - so the packet did
|
|
|
-* not get transmitted.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* wlandev wlan device structure
|
|
|
-*
|
|
|
-* Returns:
|
|
|
-* nothing
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* tasklet
|
|
|
-----------------------------------------------------------------*/
|
|
|
-static void hfa384x_int_txexc(wlandevice_t *wlandev)
|
|
|
-{
|
|
|
- hfa384x_t *hw = wlandev->priv;
|
|
|
- UINT16 status;
|
|
|
- UINT16 fid;
|
|
|
- int result = 0;
|
|
|
- DBFENTER;
|
|
|
- /* Collect the status and display */
|
|
|
- fid = hfa384x_getreg(hw, HFA384x_TXCOMPLFID);
|
|
|
- result = hfa384x_copy_from_bap(hw, HFA384x_BAP_INT, fid, 0, &status, sizeof(status));
|
|
|
- if ( result ) {
|
|
|
- WLAN_LOG_DEBUG(1,
|
|
|
- "copy_from_bap(0x%04x, 0, %d) failed, result=0x%x\n",
|
|
|
- fid, sizeof(status), result);
|
|
|
- goto failed;
|
|
|
- }
|
|
|
- status = hfa384x2host_16(status);
|
|
|
- prism2sta_ev_txexc(wlandev, status);
|
|
|
-failed:
|
|
|
- DBFEXIT;
|
|
|
- return;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_int_tx
|
|
|
-*
|
|
|
-* Handles the Tx event.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* wlandev wlan device structure
|
|
|
-*
|
|
|
-* Returns:
|
|
|
-* nothing
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* tasklet
|
|
|
-----------------------------------------------------------------*/
|
|
|
-static void hfa384x_int_tx(wlandevice_t *wlandev)
|
|
|
-{
|
|
|
- hfa384x_t *hw = wlandev->priv;
|
|
|
- UINT16 fid;
|
|
|
- UINT16 status;
|
|
|
- int result = 0;
|
|
|
- DBFENTER;
|
|
|
- fid = hfa384x_getreg(hw, HFA384x_TXCOMPLFID);
|
|
|
- result = hfa384x_copy_from_bap(hw, HFA384x_BAP_INT, fid, 0, &status, sizeof(status));
|
|
|
- if ( result ) {
|
|
|
- WLAN_LOG_DEBUG(1,
|
|
|
- "copy_from_bap(0x%04x, 0, %d) failed, result=0x%x\n",
|
|
|
- fid, sizeof(status), result);
|
|
|
- goto failed;
|
|
|
- }
|
|
|
- status = hfa384x2host_16(status);
|
|
|
- prism2sta_ev_tx(wlandev, status);
|
|
|
-failed:
|
|
|
- DBFEXIT;
|
|
|
- return;
|
|
|
-}
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_int_rx
|
|
|
-*
|
|
|
-* Handles the Rx event.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* wlandev wlan device structure
|
|
|
-*
|
|
|
-* Returns:
|
|
|
-* nothing
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* tasklet
|
|
|
-----------------------------------------------------------------*/
|
|
|
-static void hfa384x_int_rx(wlandevice_t *wlandev)
|
|
|
-{
|
|
|
- hfa384x_t *hw = wlandev->priv;
|
|
|
- UINT16 rxfid;
|
|
|
- hfa384x_rx_frame_t rxdesc;
|
|
|
- int result;
|
|
|
- int hdrlen;
|
|
|
- UINT16 fc;
|
|
|
- p80211_rxmeta_t *rxmeta;
|
|
|
- struct sk_buff *skb = NULL;
|
|
|
- UINT8 *datap;
|
|
|
-
|
|
|
- DBFENTER;
|
|
|
-
|
|
|
- /* Get the FID */
|
|
|
- rxfid = hfa384x_getreg(hw, HFA384x_RXFID);
|
|
|
- /* Get the descriptor (including headers) */
|
|
|
- result = hfa384x_copy_from_bap(hw,
|
|
|
- HFA384x_BAP_INT,
|
|
|
- rxfid,
|
|
|
- 0,
|
|
|
- &rxdesc,
|
|
|
- sizeof(rxdesc));
|
|
|
- if ( result ) {
|
|
|
- WLAN_LOG_DEBUG(1,
|
|
|
- "copy_from_bap(0x%04x, %d, %d) failed, result=0x%x\n",
|
|
|
- rxfid,
|
|
|
- 0,
|
|
|
- sizeof(rxdesc),
|
|
|
- result);
|
|
|
- goto done;
|
|
|
- }
|
|
|
-
|
|
|
- /* Byte order convert once up front. */
|
|
|
- rxdesc.status = hfa384x2host_16(rxdesc.status);
|
|
|
- rxdesc.time = hfa384x2host_32(rxdesc.time);
|
|
|
-
|
|
|
- /* drop errors and whatnot in promisc mode */
|
|
|
- if (( wlandev->netdev->flags & IFF_PROMISC ) &&
|
|
|
- (HFA384x_RXSTATUS_ISFCSERR(rxdesc.status) ||
|
|
|
- HFA384x_RXSTATUS_ISUNDECR(rxdesc.status)))
|
|
|
- goto done;
|
|
|
-
|
|
|
- /* Now handle frame based on port# */
|
|
|
- switch( HFA384x_RXSTATUS_MACPORT_GET(rxdesc.status) )
|
|
|
- {
|
|
|
- case 0:
|
|
|
-
|
|
|
- fc = ieee2host16(rxdesc.frame_control);
|
|
|
-
|
|
|
- /* If exclude and we receive an unencrypted, drop it */
|
|
|
- if ( (wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED) &&
|
|
|
- !WLAN_GET_FC_ISWEP(fc)) {
|
|
|
- goto done;
|
|
|
- }
|
|
|
-
|
|
|
- hdrlen = p80211_headerlen(fc);
|
|
|
-
|
|
|
- /* Allocate the buffer, note CRC (aka FCS). pballoc */
|
|
|
- /* assumes there needs to be space for one */
|
|
|
- skb = dev_alloc_skb(hfa384x2host_16(rxdesc.data_len) + hdrlen + WLAN_CRC_LEN + 2); /* a little extra */
|
|
|
-
|
|
|
- if ( ! skb ) {
|
|
|
- WLAN_LOG_ERROR("alloc_skb failed.\n");
|
|
|
- goto done;
|
|
|
- }
|
|
|
-
|
|
|
- skb->dev = wlandev->netdev;
|
|
|
-
|
|
|
- /* theoretically align the IP header on a 32-bit word. */
|
|
|
- if ( hdrlen == WLAN_HDR_A4_LEN )
|
|
|
- skb_reserve(skb, 2);
|
|
|
-
|
|
|
- /* Copy the 802.11 hdr to the buffer */
|
|
|
- datap = skb_put(skb, WLAN_HDR_A3_LEN);
|
|
|
- memcpy(datap, &rxdesc.frame_control, WLAN_HDR_A3_LEN);
|
|
|
-
|
|
|
- /* Snag the A4 address if present */
|
|
|
- if (hdrlen == WLAN_HDR_A4_LEN) {
|
|
|
- datap = skb_put(skb, WLAN_ADDR_LEN);
|
|
|
- memcpy(datap, &rxdesc.address4, WLAN_HDR_A3_LEN);
|
|
|
- }
|
|
|
-
|
|
|
- /* we can convert the data_len as we passed the original on */
|
|
|
- rxdesc.data_len = hfa384x2host_16(rxdesc.data_len);
|
|
|
-
|
|
|
- /* Copy the payload data to the buffer */
|
|
|
- if ( rxdesc.data_len > 0 ) {
|
|
|
- datap = skb_put(skb, rxdesc.data_len);
|
|
|
- result = hfa384x_copy_from_bap(hw,
|
|
|
- HFA384x_BAP_INT, rxfid, HFA384x_RX_DATA_OFF,
|
|
|
- datap, rxdesc.data_len);
|
|
|
- if ( result ) {
|
|
|
- WLAN_LOG_DEBUG(1,
|
|
|
- "copy_from_bap(0x%04x, %d, %d) failed, result=0x%x\n",
|
|
|
- rxfid,
|
|
|
- HFA384x_RX_DATA_OFF,
|
|
|
- rxdesc.data_len,
|
|
|
- result);
|
|
|
- goto failed;
|
|
|
- }
|
|
|
- }
|
|
|
- /* the prism2 cards don't return the FCS */
|
|
|
- datap = skb_put(skb, WLAN_CRC_LEN);
|
|
|
- memset (datap, 0xff, WLAN_CRC_LEN);
|
|
|
- skb_reset_mac_header(skb);
|
|
|
-
|
|
|
- /* Attach the rxmeta, set some stuff */
|
|
|
- p80211skb_rxmeta_attach(wlandev, skb);
|
|
|
- rxmeta = P80211SKB_RXMETA(skb);
|
|
|
- rxmeta->mactime = rxdesc.time;
|
|
|
- rxmeta->rxrate = rxdesc.rate;
|
|
|
- rxmeta->signal = rxdesc.signal - hw->dbmadjust;
|
|
|
- rxmeta->noise = rxdesc.silence - hw->dbmadjust;
|
|
|
-
|
|
|
- prism2sta_ev_rx(wlandev, skb);
|
|
|
- goto done;
|
|
|
- case 7:
|
|
|
-
|
|
|
- if ( ! HFA384x_RXSTATUS_ISFCSERR(rxdesc.status) ) {
|
|
|
- hfa384x_int_rxmonitor( wlandev, rxfid, &rxdesc);
|
|
|
- } else {
|
|
|
- WLAN_LOG_DEBUG(3,"Received monitor frame: FCSerr set\n");
|
|
|
- }
|
|
|
- goto done;
|
|
|
-
|
|
|
- default:
|
|
|
-
|
|
|
- WLAN_LOG_WARNING("Received frame on unsupported port=%d\n",
|
|
|
- HFA384x_RXSTATUS_MACPORT_GET(rxdesc.status) );
|
|
|
- goto done;
|
|
|
- }
|
|
|
-
|
|
|
- failed:
|
|
|
- dev_kfree_skb(skb);
|
|
|
-
|
|
|
- done:
|
|
|
- DBFEXIT;
|
|
|
- return;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_int_rxmonitor
|
|
|
-*
|
|
|
-* Helper function for int_rx. Handles monitor frames.
|
|
|
-* Note that this function allocates space for the FCS and sets it
|
|
|
-* to 0xffffffff. The hfa384x doesn't give us the FCS value but the
|
|
|
-* higher layers expect it. 0xffffffff is used as a flag to indicate
|
|
|
-* the FCS is bogus.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* wlandev wlan device structure
|
|
|
-* rxfid received FID
|
|
|
-* rxdesc rx descriptor read from card in int_rx
|
|
|
-*
|
|
|
-* Returns:
|
|
|
-* nothing
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-* Allocates an skb and passes it up via the PF_PACKET interface.
|
|
|
-* Call context:
|
|
|
-* interrupt
|
|
|
-----------------------------------------------------------------*/
|
|
|
-static void hfa384x_int_rxmonitor( wlandevice_t *wlandev, UINT16 rxfid,
|
|
|
- hfa384x_rx_frame_t *rxdesc)
|
|
|
-{
|
|
|
- hfa384x_t *hw = wlandev->priv;
|
|
|
- UINT hdrlen = 0;
|
|
|
- UINT datalen = 0;
|
|
|
- UINT skblen = 0;
|
|
|
- UINT truncated = 0;
|
|
|
- UINT8 *datap;
|
|
|
- UINT16 fc;
|
|
|
- struct sk_buff *skb;
|
|
|
-
|
|
|
- DBFENTER;
|
|
|
- /* Don't forget the status, time, and data_len fields are in host order */
|
|
|
- /* Figure out how big the frame is */
|
|
|
- fc = ieee2host16(rxdesc->frame_control);
|
|
|
- hdrlen = p80211_headerlen(fc);
|
|
|
- datalen = hfa384x2host_16(rxdesc->data_len);
|
|
|
-
|
|
|
- /* Allocate an ind message+framesize skb */
|
|
|
- skblen = sizeof(p80211msg_lnxind_wlansniffrm_t) +
|
|
|
- hdrlen + datalen + WLAN_CRC_LEN;
|
|
|
-
|
|
|
- /* sanity check the length */
|
|
|
- if ( skblen >
|
|
|
- (sizeof(p80211msg_lnxind_wlansniffrm_t) +
|
|
|
- WLAN_HDR_A4_LEN + WLAN_DATA_MAXLEN + WLAN_CRC_LEN) ) {
|
|
|
- WLAN_LOG_DEBUG(1, "overlen frm: len=%d\n",
|
|
|
- skblen - sizeof(p80211msg_lnxind_wlansniffrm_t));
|
|
|
- }
|
|
|
-
|
|
|
- if ( (skb = dev_alloc_skb(skblen)) == NULL ) {
|
|
|
- WLAN_LOG_ERROR("alloc_skb failed trying to allocate %d bytes\n", skblen);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- /* only prepend the prism header if in the right mode */
|
|
|
- if ((wlandev->netdev->type == ARPHRD_IEEE80211_PRISM) &&
|
|
|
- (hw->sniffhdr == 0)) {
|
|
|
- p80211msg_lnxind_wlansniffrm_t *msg;
|
|
|
- datap = skb_put(skb, sizeof(p80211msg_lnxind_wlansniffrm_t));
|
|
|
- msg = (p80211msg_lnxind_wlansniffrm_t*) datap;
|
|
|
-
|
|
|
- /* Initialize the message members */
|
|
|
- msg->msgcode = DIDmsg_lnxind_wlansniffrm;
|
|
|
- msg->msglen = sizeof(p80211msg_lnxind_wlansniffrm_t);
|
|
|
- strcpy(msg->devname, wlandev->name);
|
|
|
-
|
|
|
- msg->hosttime.did = DIDmsg_lnxind_wlansniffrm_hosttime;
|
|
|
- msg->hosttime.status = 0;
|
|
|
- msg->hosttime.len = 4;
|
|
|
- msg->hosttime.data = jiffies;
|
|
|
-
|
|
|
- msg->mactime.did = DIDmsg_lnxind_wlansniffrm_mactime;
|
|
|
- msg->mactime.status = 0;
|
|
|
- msg->mactime.len = 4;
|
|
|
- msg->mactime.data = rxdesc->time * 1000;
|
|
|
-
|
|
|
- msg->channel.did = DIDmsg_lnxind_wlansniffrm_channel;
|
|
|
- msg->channel.status = 0;
|
|
|
- msg->channel.len = 4;
|
|
|
- msg->channel.data = hw->sniff_channel;
|
|
|
-
|
|
|
- msg->rssi.did = DIDmsg_lnxind_wlansniffrm_rssi;
|
|
|
- msg->rssi.status = P80211ENUM_msgitem_status_no_value;
|
|
|
- msg->rssi.len = 4;
|
|
|
- msg->rssi.data = 0;
|
|
|
-
|
|
|
- msg->sq.did = DIDmsg_lnxind_wlansniffrm_sq;
|
|
|
- msg->sq.status = P80211ENUM_msgitem_status_no_value;
|
|
|
- msg->sq.len = 4;
|
|
|
- msg->sq.data = 0;
|
|
|
-
|
|
|
- msg->signal.did = DIDmsg_lnxind_wlansniffrm_signal;
|
|
|
- msg->signal.status = 0;
|
|
|
- msg->signal.len = 4;
|
|
|
- msg->signal.data = rxdesc->signal;
|
|
|
-
|
|
|
- msg->noise.did = DIDmsg_lnxind_wlansniffrm_noise;
|
|
|
- msg->noise.status = 0;
|
|
|
- msg->noise.len = 4;
|
|
|
- msg->noise.data = rxdesc->silence;
|
|
|
-
|
|
|
- msg->rate.did = DIDmsg_lnxind_wlansniffrm_rate;
|
|
|
- msg->rate.status = 0;
|
|
|
- msg->rate.len = 4;
|
|
|
- msg->rate.data = rxdesc->rate / 5; /* set to 802.11 units */
|
|
|
-
|
|
|
- msg->istx.did = DIDmsg_lnxind_wlansniffrm_istx;
|
|
|
- msg->istx.status = 0;
|
|
|
- msg->istx.len = 4;
|
|
|
- msg->istx.data = P80211ENUM_truth_false;
|
|
|
-
|
|
|
- msg->frmlen.did = DIDmsg_lnxind_wlansniffrm_frmlen;
|
|
|
- msg->frmlen.status = 0;
|
|
|
- msg->frmlen.len = 4;
|
|
|
- msg->frmlen.data = hdrlen + datalen + WLAN_CRC_LEN;
|
|
|
- } else if ((wlandev->netdev->type == ARPHRD_IEEE80211_PRISM) &&
|
|
|
- (hw->sniffhdr != 0)) {
|
|
|
- p80211_caphdr_t *caphdr;
|
|
|
- /* The NEW header format! */
|
|
|
- datap = skb_put(skb, sizeof(p80211_caphdr_t));
|
|
|
- caphdr = (p80211_caphdr_t*) datap;
|
|
|
-
|
|
|
- caphdr->version = htonl(P80211CAPTURE_VERSION);
|
|
|
- caphdr->length = htonl(sizeof(p80211_caphdr_t));
|
|
|
- caphdr->mactime = __cpu_to_be64(rxdesc->time);
|
|
|
- caphdr->hosttime = __cpu_to_be64(jiffies);
|
|
|
- caphdr->phytype = htonl(4); /* dss_dot11_b */
|
|
|
- caphdr->channel = htonl(hw->sniff_channel);
|
|
|
- caphdr->datarate = htonl(rxdesc->rate);
|
|
|
- caphdr->antenna = htonl(0); /* unknown */
|
|
|
- caphdr->priority = htonl(0); /* unknown */
|
|
|
- caphdr->ssi_type = htonl(3); /* rssi_raw */
|
|
|
- caphdr->ssi_signal = htonl(rxdesc->signal);
|
|
|
- caphdr->ssi_noise = htonl(rxdesc->silence);
|
|
|
- caphdr->preamble = htonl(0); /* unknown */
|
|
|
- caphdr->encoding = htonl(1); /* cck */
|
|
|
- }
|
|
|
- /* Copy the 802.11 header to the skb (ctl frames may be less than a full header) */
|
|
|
- datap = skb_put(skb, hdrlen);
|
|
|
- memcpy( datap, &(rxdesc->frame_control), hdrlen);
|
|
|
-
|
|
|
- /* If any, copy the data from the card to the skb */
|
|
|
- if ( datalen > 0 )
|
|
|
- {
|
|
|
- /* Truncate the packet if the user wants us to */
|
|
|
- UINT dataread = datalen;
|
|
|
- if(hw->sniff_truncate > 0 && dataread > hw->sniff_truncate) {
|
|
|
- dataread = hw->sniff_truncate;
|
|
|
- truncated = 1;
|
|
|
- }
|
|
|
-
|
|
|
- datap = skb_put(skb, dataread);
|
|
|
- hfa384x_copy_from_bap(hw,
|
|
|
- HFA384x_BAP_INT, rxfid, HFA384x_RX_DATA_OFF,
|
|
|
- datap, dataread);
|
|
|
-
|
|
|
- /* check for unencrypted stuff if WEP bit set. */
|
|
|
- if (*(datap - hdrlen + 1) & 0x40) // wep set
|
|
|
- if ((*(datap) == 0xaa) && (*(datap+1) == 0xaa))
|
|
|
- *(datap - hdrlen + 1) &= 0xbf; // clear wep; it's the 802.2 header!
|
|
|
- }
|
|
|
-
|
|
|
- if (!truncated && hw->sniff_fcs) {
|
|
|
- /* Set the FCS */
|
|
|
- datap = skb_put(skb, WLAN_CRC_LEN);
|
|
|
- memset( datap, 0xff, WLAN_CRC_LEN);
|
|
|
- }
|
|
|
-
|
|
|
- /* pass it back up */
|
|
|
- prism2sta_ev_rx(wlandev, skb);
|
|
|
-
|
|
|
- DBFEXIT;
|
|
|
- return;
|
|
|
-}
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_int_alloc
|
|
|
-*
|
|
|
-* Handles the Alloc event.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* wlandev wlan device structure
|
|
|
-*
|
|
|
-* Returns:
|
|
|
-* nothing
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* interrupt
|
|
|
-----------------------------------------------------------------*/
|
|
|
-static void hfa384x_int_alloc(wlandevice_t *wlandev)
|
|
|
-{
|
|
|
- hfa384x_t *hw = wlandev->priv;
|
|
|
- UINT16 fid;
|
|
|
- INT16 result;
|
|
|
-
|
|
|
- DBFENTER;
|
|
|
-
|
|
|
- /* Handle the reclaimed FID */
|
|
|
- /* collect the FID and push it onto the stack */
|
|
|
- fid = hfa384x_getreg(hw, HFA384x_ALLOCFID);
|
|
|
-
|
|
|
- if ( fid != hw->infofid ) { /* It's a transmit fid */
|
|
|
- WLAN_LOG_DEBUG(5, "int_alloc(%#x)\n", fid);
|
|
|
- result = txfid_queue_add(hw, fid);
|
|
|
- if (result != -1) {
|
|
|
- prism2sta_ev_alloc(wlandev);
|
|
|
- WLAN_LOG_DEBUG(5, "q_add.\n");
|
|
|
- } else {
|
|
|
- WLAN_LOG_DEBUG(5, "q_full.\n");
|
|
|
- }
|
|
|
- } else {
|
|
|
- /* unlock the info fid */
|
|
|
- up(&hw->infofid_sem);
|
|
|
- }
|
|
|
-
|
|
|
- DBFEXIT;
|
|
|
- return;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*----------------------------------------------------------------
|
|
|
-* hfa384x_drvr_handover
|
|
|
-*
|
|
|
-* Sends a handover notification to the MAC.
|
|
|
-*
|
|
|
-* Arguments:
|
|
|
-* hw device structure
|
|
|
-* addr address of station that's left
|
|
|
-*
|
|
|
-* Returns:
|
|
|
-* zero success.
|
|
|
-* -ERESTARTSYS received signal while waiting for semaphore.
|
|
|
-* -EIO failed to write to bap, or failed in cmd.
|
|
|
-*
|
|
|
-* Side effects:
|
|
|
-*
|
|
|
-* Call context:
|
|
|
-* process thread, NOTE: this call may block on a semaphore!
|
|
|
-----------------------------------------------------------------*/
|
|
|
-int hfa384x_drvr_handover( hfa384x_t *hw, UINT8 *addr)
|
|
|
-{
|
|
|
- int result = 0;
|
|
|
- hfa384x_HandoverAddr_t rec;
|
|
|
- UINT len;
|
|
|
- DBFENTER;
|
|
|
-
|
|
|
- /* Acquire the infofid */
|
|
|
- if ( down_interruptible(&hw->infofid_sem) ) {
|
|
|
- result = -ERESTARTSYS;
|
|
|
- goto failed;
|
|
|
- }
|
|
|
-
|
|
|
- /* Set up the record */
|
|
|
- len = sizeof(hfa384x_HandoverAddr_t);
|
|
|
- rec.framelen = host2hfa384x_16(len/2 - 1);
|
|
|
- rec.infotype = host2hfa384x_16(HFA384x_IT_HANDOVERADDR);
|
|
|
- memcpy(rec.handover_addr, addr, sizeof(rec.handover_addr));
|
|
|
-
|
|
|
- /* Issue the command */
|
|
|
- result = hfa384x_cmd_notify(hw, 1, hw->infofid, &rec, len);
|
|
|
-
|
|
|
- if ( result != 0 ) {
|
|
|
- WLAN_LOG_DEBUG(1,"cmd_notify(%04x) failed, result=%d",
|
|
|
- hw->infofid, result);
|
|
|
- result = -EIO;
|
|
|
- goto failed;
|
|
|
- }
|
|
|
-
|
|
|
-failed:
|
|
|
- DBFEXIT;
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-void hfa384x_tx_timeout(wlandevice_t *wlandev)
|
|
|
-{
|
|
|
- DBFENTER;
|
|
|
-
|
|
|
- WLAN_LOG_WARNING("Implement me.\n");
|
|
|
-
|
|
|
- DBFEXIT;
|
|
|
-}
|
|
|
-
|
|
|
-/* Handles all "rx" BAP operations */
|
|
|
-static void hfa384x_bap_tasklet(unsigned long data)
|
|
|
-{
|
|
|
- hfa384x_t *hw = (hfa384x_t *) data;
|
|
|
- wlandevice_t *wlandev = hw->wlandev;
|
|
|
- int counter = prism2_irq_evread_max;
|
|
|
- int reg;
|
|
|
-
|
|
|
- DBFENTER;
|
|
|
-
|
|
|
- while (counter-- > 0) {
|
|
|
- /* Get interrupt register */
|
|
|
- reg = hfa384x_getreg(hw, HFA384x_EVSTAT);
|
|
|
-
|
|
|
- if ((reg == 0xffff) ||
|
|
|
- !(reg & HFA384x_INT_BAP_OP)) {
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- if ( HFA384x_EVSTAT_ISINFO(reg) ){
|
|
|
- hfa384x_int_info(wlandev);
|
|
|
- hfa384x_setreg(hw, HFA384x_EVACK_INFO_SET(1),
|
|
|
- HFA384x_EVACK);
|
|
|
- }
|
|
|
- if ( HFA384x_EVSTAT_ISTXEXC(reg) ){
|
|
|
- hfa384x_int_txexc(wlandev);
|
|
|
- hfa384x_setreg(hw, HFA384x_EVACK_TXEXC_SET(1),
|
|
|
- HFA384x_EVACK);
|
|
|
- }
|
|
|
- if ( HFA384x_EVSTAT_ISTX(reg) ){
|
|
|
- hfa384x_int_tx(wlandev);
|
|
|
- hfa384x_setreg(hw, HFA384x_EVACK_TX_SET(1),
|
|
|
- HFA384x_EVACK);
|
|
|
- }
|
|
|
- if ( HFA384x_EVSTAT_ISRX(reg) ){
|
|
|
- hfa384x_int_rx(wlandev);
|
|
|
- hfa384x_setreg(hw, HFA384x_EVACK_RX_SET(1),
|
|
|
- HFA384x_EVACK);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /* re-enable interrupts */
|
|
|
- hfa384x_events_all(hw);
|
|
|
-
|
|
|
- DBFEXIT;
|
|
|
-}
|