📄 hfa384x.c
字号:
/* 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 <wlan/version.h>#include <linux/config.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/wlan_compat.h>// XXXX #define CMD_IRQ/*================================================================*//* Project Includes */#include <wlan/p80211types.h>#include <wlan/p80211hdr.h>#include <wlan/p80211mgmt.h>#include <wlan/p80211conv.h>#include <wlan/p80211msg.h>#include <wlan/p80211netdev.h>#include <wlan/p80211req.h>#include <wlan/p80211metadef.h>#include <wlan/p80211metastruct.h>#include <prism2/hfa384x.h>#include <prism2/prism2mgmt.h>/*================================================================*//* Local Constants */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_IRQstatic void hfa384x_int_cmd(wlandevice_t *wlandev);#endifstatic 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 */UINT16txfid_queue_empty(hfa384x_t *hw){ return (hw->txfid_head == hw->txfid_tail) ? 1 : 0;}UINT16txfid_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;}INT16txfid_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 *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_WORK(&hw->link_bh, prism2sta_processing_defer, hw); INIT_WORK(&hw->commsqual_bh, prism2sta_commsqual_defer, hw); 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 ----------------------------------------------------------------*/voidhfa384x_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;}/*----------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -