blob: 88d0d472142fde3334516a2166ce6e80904f945f [file] [log] [blame]
/*******************************************************************************
* Agere Systems Inc.
* Wireless device driver for Linux (wlags49).
*
* Copyright (c) 1998-2003 Agere Systems Inc.
* All rights reserved.
* http://www.agere.com
*
* Initially developed by TriplePoint, Inc.
* http://www.triplepoint.com
*
*------------------------------------------------------------------------------
*
* This file contains the main driver entry points and other adapter
* specific routines.
*
*------------------------------------------------------------------------------
*
* SOFTWARE LICENSE
*
* This software is provided subject to the following terms and conditions,
* which you should read carefully before using the software. Using this
* software indicates your acceptance of these terms and conditions. If you do
* not agree with these terms and conditions, do not use the software.
*
* Copyright © 2003 Agere Systems Inc.
* All rights reserved.
*
* Redistribution and use in source or binary forms, with or without
* modifications, are permitted provided that the following conditions are met:
*
* . Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following Disclaimer as comments in the code as
* well as in the documentation and/or other materials provided with the
* distribution.
*
* . Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following Disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* . Neither the name of Agere Systems Inc. nor the names of the contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* Disclaimer
*
* THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
* USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
* RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
******************************************************************************/
/*******************************************************************************
* constant definitions
******************************************************************************/
/* Allow support for calling system fcns to access F/W iamge file */
#define __KERNEL_SYSCALLS__
/*******************************************************************************
* include files
******************************************************************************/
#include <wl_version.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/types.h>
#include <linux/kernel.h>
// #include <linux/sched.h>
// #include <linux/ptrace.h>
// #include <linux/slab.h>
// #include <linux/ctype.h>
// #include <linux/string.h>
// #include <linux/timer.h>
//#include <linux/interrupt.h>
// #include <linux/tqueue.h>
// #include <linux/in.h>
// #include <linux/delay.h>
// #include <asm/io.h>
// #include <asm/system.h>
// #include <asm/bitops.h>
#include <linux/unistd.h>
#include <asm/uaccess.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
// #include <linux/skbuff.h>
// #include <linux/if_arp.h>
// #include <linux/ioport.h>
#define BIN_DL 0
#if BIN_DL
#include <linux/vmalloc.h>
#endif // BIN_DL
#include <debug.h>
#include <hcf.h>
#include <dhf.h>
//in order to get around:: wl_main.c:2229: `HREG_EV_RDMAD' undeclared (first use in this function)
#include <hcfdef.h>
#include <wl_if.h>
#include <wl_internal.h>
#include <wl_util.h>
#include <wl_main.h>
#include <wl_netdev.h>
#include <wl_wext.h>
#ifdef USE_PROFILE
#include <wl_profile.h>
#endif /* USE_PROFILE */
#ifdef BUS_PCMCIA
#include <wl_cs.h>
#endif /* BUS_PCMCIA */
#ifdef BUS_PCI
#include <wl_pci.h>
#endif /* BUS_PCI */
/*******************************************************************************
* macro defintions
******************************************************************************/
#define VALID_PARAM(C) \
{ \
if (!(C)) \
{ \
printk(KERN_INFO "Wireless, parameter error: \"%s\"\n", #C); \
goto failed; \
} \
}
/*******************************************************************************
* local functions
******************************************************************************/
void wl_isr_handler( unsigned long p );
#if 0 //SCULL_USE_PROC /* don't waste space if unused */
//int scull_read_procmem(char *buf, char **start, off_t offset, int len, int unused);
int scull_read_procmem(char *buf, char **start, off_t offset, int len, int *eof, void *data );
static int write_int(struct file *file, const char *buffer, unsigned long count, void *data);
static void proc_write(const char *name, write_proc_t *w, void *data);
#endif /* SCULL_USE_PROC */
/*******************************************************************************
* module parameter definitions - set with 'insmod'
******************************************************************************/
static p_u16 irq_mask = 0xdeb8; // IRQ3,4,5,7,9,10,11,12,14,15
static p_s8 irq_list[4] = { -1 };
#if 0
MODULE_PARM(irq_mask, "h");
MODULE_PARM_DESC(irq_mask, "IRQ mask [0xdeb8]");
MODULE_PARM(irq_list, "1-4b");
MODULE_PARM_DESC(irq_list, "IRQ list [<irq_mask>]");
#endif
static p_u8 PARM_AUTHENTICATION = PARM_DEFAULT_AUTHENTICATION;
static p_u16 PARM_AUTH_KEY_MGMT_SUITE = PARM_DEFAULT_AUTH_KEY_MGMT_SUITE;
static p_u16 PARM_BRSC_2GHZ = PARM_DEFAULT_BRSC_2GHZ;
static p_u16 PARM_BRSC_5GHZ = PARM_DEFAULT_BRSC_5GHZ;
static p_u16 PARM_COEXISTENCE = PARM_DEFAULT_COEXISTENCE;
static p_u16 PARM_CONNECTION_CONTROL = PARM_DEFAULT_CONNECTION_CONTROL; //;?rename and move
static p_char *PARM_CREATE_IBSS = PARM_DEFAULT_CREATE_IBSS_STR;
static p_char *PARM_DESIRED_SSID = PARM_DEFAULT_SSID;
static p_char *PARM_DOWNLOAD_FIRMWARE = "";
static p_u16 PARM_ENABLE_ENCRYPTION = PARM_DEFAULT_ENABLE_ENCRYPTION;
static p_char *PARM_EXCLUDE_UNENCRYPTED = PARM_DEFAULT_EXCLUDE_UNENCRYPTED_STR;
static p_char *PARM_INTRA_BSS_RELAY = PARM_DEFAULT_INTRA_BSS_RELAY_STR;
static p_char *PARM_KEY1 = "";
static p_char *PARM_KEY2 = "";
static p_char *PARM_KEY3 = "";
static p_char *PARM_KEY4 = "";
static p_char *PARM_LOAD_BALANCING = PARM_DEFAULT_LOAD_BALANCING_STR;
static p_u16 PARM_MAX_SLEEP = PARM_DEFAULT_MAX_PM_SLEEP;
static p_char *PARM_MEDIUM_DISTRIBUTION = PARM_DEFAULT_MEDIUM_DISTRIBUTION_STR;
static p_char *PARM_MICROWAVE_ROBUSTNESS = PARM_DEFAULT_MICROWAVE_ROBUSTNESS_STR;
static p_char *PARM_MULTICAST_PM_BUFFERING = PARM_DEFAULT_MULTICAST_PM_BUFFERING_STR;
static p_u16 PARM_MULTICAST_RATE = PARM_DEFAULT_MULTICAST_RATE_2GHZ;
static p_char *PARM_MULTICAST_RX = PARM_DEFAULT_MULTICAST_RX_STR;
static p_u8 PARM_NETWORK_ADDR[ETH_ALEN] = PARM_DEFAULT_NETWORK_ADDR;
static p_u16 PARM_OWN_ATIM_WINDOW = PARM_DEFAULT_OWN_ATIM_WINDOW;
static p_u16 PARM_OWN_BEACON_INTERVAL = PARM_DEFAULT_OWN_BEACON_INTERVAL;
static p_u8 PARM_OWN_CHANNEL = PARM_DEFAULT_OWN_CHANNEL;
static p_u8 PARM_OWN_DTIM_PERIOD = PARM_DEFAULT_OWN_DTIM_PERIOD;
static p_char *PARM_OWN_NAME = PARM_DEFAULT_OWN_NAME;
static p_char *PARM_OWN_SSID = PARM_DEFAULT_SSID;
static p_u16 PARM_PM_ENABLED = WVLAN_PM_STATE_DISABLED;
static p_u16 PARM_PM_HOLDOVER_DURATION = PARM_DEFAULT_PM_HOLDOVER_DURATION;
static p_u8 PARM_PORT_TYPE = PARM_DEFAULT_PORT_TYPE;
static p_char *PARM_PROMISCUOUS_MODE = PARM_DEFAULT_PROMISCUOUS_MODE_STR;
static p_char *PARM_REJECT_ANY = PARM_DEFAULT_REJECT_ANY_STR;
#ifdef USE_WDS
static p_u16 PARM_RTS_THRESHOLD1 = PARM_DEFAULT_RTS_THRESHOLD;
static p_u16 PARM_RTS_THRESHOLD2 = PARM_DEFAULT_RTS_THRESHOLD;
static p_u16 PARM_RTS_THRESHOLD3 = PARM_DEFAULT_RTS_THRESHOLD;
static p_u16 PARM_RTS_THRESHOLD4 = PARM_DEFAULT_RTS_THRESHOLD;
static p_u16 PARM_RTS_THRESHOLD5 = PARM_DEFAULT_RTS_THRESHOLD;
static p_u16 PARM_RTS_THRESHOLD6 = PARM_DEFAULT_RTS_THRESHOLD;
#endif // USE_WDS
static p_u16 PARM_RTS_THRESHOLD = PARM_DEFAULT_RTS_THRESHOLD;
static p_u16 PARM_SRSC_2GHZ = PARM_DEFAULT_SRSC_2GHZ;
static p_u16 PARM_SRSC_5GHZ = PARM_DEFAULT_SRSC_5GHZ;
static p_u8 PARM_SYSTEM_SCALE = PARM_DEFAULT_SYSTEM_SCALE;
static p_u8 PARM_TX_KEY = PARM_DEFAULT_TX_KEY;
static p_u16 PARM_TX_POW_LEVEL = PARM_DEFAULT_TX_POW_LEVEL;
#ifdef USE_WDS
static p_u16 PARM_TX_RATE1 = PARM_DEFAULT_TX_RATE_2GHZ;
static p_u16 PARM_TX_RATE2 = PARM_DEFAULT_TX_RATE_2GHZ;
static p_u16 PARM_TX_RATE3 = PARM_DEFAULT_TX_RATE_2GHZ;
static p_u16 PARM_TX_RATE4 = PARM_DEFAULT_TX_RATE_2GHZ;
static p_u16 PARM_TX_RATE5 = PARM_DEFAULT_TX_RATE_2GHZ;
static p_u16 PARM_TX_RATE6 = PARM_DEFAULT_TX_RATE_2GHZ;
#endif // USE_WDS
static p_u16 PARM_TX_RATE = PARM_DEFAULT_TX_RATE_2GHZ;
#ifdef USE_WDS
static p_u8 PARM_WDS_ADDRESS1[ETH_ALEN] = PARM_DEFAULT_NETWORK_ADDR;
static p_u8 PARM_WDS_ADDRESS2[ETH_ALEN] = PARM_DEFAULT_NETWORK_ADDR;
static p_u8 PARM_WDS_ADDRESS3[ETH_ALEN] = PARM_DEFAULT_NETWORK_ADDR;
static p_u8 PARM_WDS_ADDRESS4[ETH_ALEN] = PARM_DEFAULT_NETWORK_ADDR;
static p_u8 PARM_WDS_ADDRESS5[ETH_ALEN] = PARM_DEFAULT_NETWORK_ADDR;
static p_u8 PARM_WDS_ADDRESS6[ETH_ALEN] = PARM_DEFAULT_NETWORK_ADDR;
#endif // USE_WDS
#if 0
MODULE_PARM(PARM_DESIRED_SSID, "s");
MODULE_PARM_DESC(PARM_DESIRED_SSID, "Network Name (<string>) [ANY]");
MODULE_PARM(PARM_OWN_SSID, "s");
MODULE_PARM_DESC(PARM_OWN_SSID, "Network Name (<string>) [ANY]");
MODULE_PARM(PARM_OWN_CHANNEL, "b");
MODULE_PARM_DESC(PARM_OWN_CHANNEL, "Channel (0 - 14) [0]");
MODULE_PARM(PARM_SYSTEM_SCALE, "b");
MODULE_PARM_DESC(PARM_SYSTEM_SCALE, "Distance Between APs (1 - 3) [1]");
MODULE_PARM(PARM_TX_RATE, "b");
MODULE_PARM_DESC(PARM_TX_RATE, "Transmit Rate Control");
MODULE_PARM(PARM_RTS_THRESHOLD, "h");
MODULE_PARM_DESC(PARM_RTS_THRESHOLD, "Medium Reservation (RTS/CTS Fragment Length) (256 - 2347) [2347]");
MODULE_PARM(PARM_MICROWAVE_ROBUSTNESS, "s");
MODULE_PARM_DESC(PARM_MICROWAVE_ROBUSTNESS, "Microwave Oven Robustness Enabled (<string> N or Y) [N]");
MODULE_PARM(PARM_OWN_NAME, "s");
MODULE_PARM_DESC(PARM_OWN_NAME, "Station Name (<string>) [Linux]");
MODULE_PARM(PARM_ENABLE_ENCRYPTION, "b");
MODULE_PARM_DESC(PARM_ENABLE_ENCRYPTION, "Encryption Mode (0 - 7) [0]");
MODULE_PARM(PARM_KEY1, "s");
MODULE_PARM_DESC(PARM_KEY1, "Data Encryption Key 1 (<string>) []");
MODULE_PARM(PARM_KEY2, "s");
MODULE_PARM_DESC(PARM_KEY2, "Data Encryption Key 2 (<string>) []");
MODULE_PARM(PARM_KEY3, "s");
MODULE_PARM_DESC(PARM_KEY3, "Data Encryption Key 3 (<string>) []");
MODULE_PARM(PARM_KEY4, "s");
MODULE_PARM_DESC(PARM_KEY4, "Data Encryption Key 4 (<string>) []");
MODULE_PARM(PARM_TX_KEY, "b");
MODULE_PARM_DESC(PARM_TX_KEY, "Transmit Key ID (1 - 4) [1]");
MODULE_PARM(PARM_MULTICAST_RATE, "b");
MODULE_PARM_DESC(PARM_MULTICAST_RATE, "Multicast Rate");
MODULE_PARM(PARM_DOWNLOAD_FIRMWARE, "s");
MODULE_PARM_DESC(PARM_DOWNLOAD_FIRMWARE, "filename of firmware image");
MODULE_PARM(PARM_AUTH_KEY_MGMT_SUITE, "b");
MODULE_PARM_DESC(PARM_AUTH_KEY_MGMT_SUITE, "Authentication Key Management suite (0-4) [0]");
MODULE_PARM(PARM_LOAD_BALANCING, "s");
MODULE_PARM_DESC(PARM_LOAD_BALANCING, "Load Balancing Enabled (<string> N or Y) [Y]");
MODULE_PARM(PARM_MEDIUM_DISTRIBUTION, "s");
MODULE_PARM_DESC(PARM_MEDIUM_DISTRIBUTION, "Medium Distribution Enabled (<string> N or Y) [Y]");
MODULE_PARM(PARM_TX_POW_LEVEL, "b");
MODULE_PARM_DESC(PARM_TX_POW_LEVEL, "Transmit Power (0 - 6) [3]");
MODULE_PARM(PARM_SRSC_2GHZ, "b");
MODULE_PARM_DESC(PARM_SRSC_2GHZ, "Supported Rate Set Control 2.4 GHz");
MODULE_PARM(PARM_SRSC_5GHZ, "b");
MODULE_PARM_DESC(PARM_SRSC_5GHZ, "Supported Rate Set Control 5.0 GHz");
MODULE_PARM(PARM_BRSC_2GHZ, "b");
MODULE_PARM_DESC(PARM_BRSC_2GHZ, "Basic Rate Set Control 2.4 GHz");
MODULE_PARM(PARM_BRSC_5GHZ, "b");
MODULE_PARM_DESC(PARM_BRSC_5GHZ, "Basic Rate Set Control 5.0 GHz");
#if 1 //;? (HCF_TYPE) & HCF_TYPE_STA
//;?seems reasonable that even an AP-only driver could afford this small additional footprint
MODULE_PARM(PARM_PM_ENABLED, "h");
MODULE_PARM_DESC(PARM_PM_ENABLED, "Power Management State (0 - 2, 8001 - 8002) [0]");
MODULE_PARM(PARM_PORT_TYPE, "b");
MODULE_PARM_DESC(PARM_PORT_TYPE, "Port Type (1 - 3) [1]");
//;?MODULE_PARM(PARM_CREATE_IBSS, "s");
//;?MODULE_PARM_DESC(PARM_CREATE_IBSS, "Create IBSS (<string> N or Y) [N]");
//;?MODULE_PARM(PARM_MULTICAST_RX, "s");
//;?MODULE_PARM_DESC(PARM_MULTICAST_RX, "Multicast Receive Enable (<string> N or Y) [Y]");
//;?MODULE_PARM(PARM_MAX_SLEEP, "h");
//;?MODULE_PARM_DESC(PARM_MAX_SLEEP, "Maximum Power Management Sleep Duration (0 - 65535) [100]");
//;?MODULE_PARM(PARM_NETWORK_ADDR, "6b");
//;?MODULE_PARM_DESC(PARM_NETWORK_ADDR, "Hardware Ethernet Address ([0x00-0xff],[0x00-0xff],[0x00-0xff],[0x00-0xff],[0x00-0xff],[0x00-0xff]) [<factory value>]");
//;?MODULE_PARM(PARM_AUTHENTICATION, "b");
//
//tracker 12448
//;?MODULE_PARM_DESC(PARM_AUTHENTICATION, "Authentication Type (0-2) [0] 0=Open 1=SharedKey 2=LEAP");
//;?MODULE_PARM_DESC(authentication, "Authentication Type (1-2) [1] 1=Open 2=SharedKey");
//tracker 12448
//
//;?MODULE_PARM(PARM_OWN_ATIM_WINDOW, "b");
//;?MODULE_PARM_DESC(PARM_OWN_ATIM_WINDOW, "ATIM Window time in TU for IBSS creation (0-100) [0]");
//;?MODULE_PARM(PARM_PM_HOLDOVER_DURATION, "b");
//;?MODULE_PARM_DESC(PARM_PM_HOLDOVER_DURATION, "Time station remains awake after MAC frame transfer when PM is on (0-65535) [100]");
//;?MODULE_PARM(PARM_PROMISCUOUS_MODE, "s");
//;?MODULE_PARM_DESC(PARM_PROMISCUOUS_MODE, "Promiscuous Mode Enable (<string> Y or N ) [N]" );
//;?
MODULE_PARM(PARM_CONNECTION_CONTROL, "b");
MODULE_PARM_DESC(PARM_CONNECTION_CONTROL, "Connection Control (0 - 3) [2]");
#endif /* HCF_STA */
#if 1 //;? (HCF_TYPE) & HCF_TYPE_AP
//;?should we restore this to allow smaller memory footprint
MODULE_PARM(PARM_OWN_DTIM_PERIOD, "b");
MODULE_PARM_DESC(PARM_OWN_DTIM_PERIOD, "DTIM Period (0 - 255) [1]");
MODULE_PARM(PARM_REJECT_ANY, "s");
MODULE_PARM_DESC(PARM_REJECT_ANY, "Closed System (<string> N or Y) [N]");
MODULE_PARM(PARM_EXCLUDE_UNENCRYPTED, "s");
MODULE_PARM_DESC(PARM_EXCLUDE_UNENCRYPTED, "Deny non-encrypted (<string> N or Y) [Y]");
MODULE_PARM(PARM_MULTICAST_PM_BUFFERING,"s");
MODULE_PARM_DESC(PARM_MULTICAST_PM_BUFFERING, "Buffer MAC frames for Tx after DTIM (<string> Y or N) [Y]");
MODULE_PARM(PARM_INTRA_BSS_RELAY, "s");
MODULE_PARM_DESC(PARM_INTRA_BSS_RELAY, "IntraBSS Relay (<string> N or Y) [Y]");
MODULE_PARM(PARM_RTS_THRESHOLD1, "h");
MODULE_PARM_DESC(PARM_RTS_THRESHOLD1, "RTS Threshold, WDS Port 1 (256 - 2347) [2347]");
MODULE_PARM(PARM_RTS_THRESHOLD2, "h");
MODULE_PARM_DESC(PARM_RTS_THRESHOLD2, "RTS Threshold, WDS Port 2 (256 - 2347) [2347]");
MODULE_PARM(PARM_RTS_THRESHOLD3, "h");
MODULE_PARM_DESC(PARM_RTS_THRESHOLD3, "RTS Threshold, WDS Port 3 (256 - 2347) [2347]");
MODULE_PARM(PARM_RTS_THRESHOLD4, "h");
MODULE_PARM_DESC(PARM_RTS_THRESHOLD4, "RTS Threshold, WDS Port 4 (256 - 2347) [2347]");
MODULE_PARM(PARM_RTS_THRESHOLD5, "h");
MODULE_PARM_DESC(PARM_RTS_THRESHOLD5, "RTS Threshold, WDS Port 5 (256 - 2347) [2347]");
MODULE_PARM(PARM_RTS_THRESHOLD6, "h");
MODULE_PARM_DESC(PARM_RTS_THRESHOLD6, "RTS Threshold, WDS Port 6 (256 - 2347) [2347]");
MODULE_PARM(PARM_TX_RATE1, "b");
MODULE_PARM_DESC(PARM_TX_RATE1, "Transmit Rate Control, WDS Port 1 (1 - 7) [3]");
MODULE_PARM(PARM_TX_RATE2, "b");
MODULE_PARM_DESC(PARM_TX_RATE2, "Transmit Rate Control, WDS Port 2 (1 - 7) [3]");
MODULE_PARM(PARM_TX_RATE3, "b");
MODULE_PARM_DESC(PARM_TX_RATE3, "Transmit Rate Control, WDS Port 3 (1 - 7) [3]");
MODULE_PARM(PARM_TX_RATE4, "b");
MODULE_PARM_DESC(PARM_TX_RATE4, "Transmit Rate Control, WDS Port 4 (1 - 7) [3]");
MODULE_PARM(PARM_TX_RATE5, "b");
MODULE_PARM_DESC(PARM_TX_RATE5, "Transmit Rate Control, WDS Port 5 (1 - 7) [3]");
MODULE_PARM(PARM_TX_RATE6, "b");
MODULE_PARM_DESC(PARM_TX_RATE6, "Transmit Rate Control, WDS Port 6 (1 - 7) [3]");
MODULE_PARM(PARM_WDS_ADDRESS1, "6b");
MODULE_PARM_DESC(PARM_WDS_ADDRESS1, "MAC Address, WDS Port 1 ([0x00-0xff],[0x00-0xff],[0x00-0xff],[0x00-0xff],[0x00-0xff],[0x00-0xff]) [{0}]");
MODULE_PARM(PARM_WDS_ADDRESS2, "6b");
MODULE_PARM_DESC(PARM_WDS_ADDRESS2, "MAC Address, WDS Port 2 ([0x00-0xff],[0x00-0xff],[0x00-0xff],[0x00-0xff],[0x00-0xff],[0x00-0xff]) [{0}]");
MODULE_PARM(PARM_WDS_ADDRESS3, "6b");
MODULE_PARM_DESC(PARM_WDS_ADDRESS3, "MAC Address, WDS Port 3 ([0x00-0xff],[0x00-0xff],[0x00-0xff],[0x00-0xff],[0x00-0xff],[0x00-0xff]) [{0}]");
MODULE_PARM(PARM_WDS_ADDRESS4, "6b");
MODULE_PARM_DESC(PARM_WDS_ADDRESS4, "MAC Address, WDS Port 4 ([0x00-0xff],[0x00-0xff],[0x00-0xff],[0x00-0xff],[0x00-0xff],[0x00-0xff]) [{0}]");
MODULE_PARM(PARM_WDS_ADDRESS5, "6b");
MODULE_PARM_DESC(PARM_WDS_ADDRESS5, "MAC Address, WDS Port 5 ([0x00-0xff],[0x00-0xff],[0x00-0xff],[0x00-0xff],[0x00-0xff],[0x00-0xff]) [{0}]");
MODULE_PARM(PARM_WDS_ADDRESS6, "6b");
MODULE_PARM_DESC(PARM_WDS_ADDRESS6, "MAC Address, WDS Port 6 ([0x00-0xff],[0x00-0xff],[0x00-0xff],[0x00-0xff],[0x00-0xff],[0x00-0xff]) [{0}]");
MODULE_PARM(PARM_OWN_BEACON_INTERVAL, "b");
MODULE_PARM_DESC(PARM_OWN_BEACON_INTERVAL, "Own Beacon Interval (20 - 200) [100]");
MODULE_PARM(PARM_COEXISTENCE, "b");
MODULE_PARM_DESC(PARM_COEXISTENCE, "Coexistence (0-7) [0]");
#endif /* HCF_AP */
#endif
/* END NEW PARAMETERS */
/*******************************************************************************
* debugging specifics
******************************************************************************/
#if DBG
static p_u32 pc_debug = DBG_LVL;
//MODULE_PARM(pc_debug, "i");
/*static ;?conflicts with my understanding of CL parameters and breaks now I moved
* the correspondig logic to wl_profile
*/ p_u32 DebugFlag = ~0; //recognizable "undefined value" rather then DBG_DEFAULTS;
//MODULE_PARM(DebugFlag, "l");
dbg_info_t wl_info = { DBG_MOD_NAME, 0, 0 };
dbg_info_t *DbgInfo = &wl_info;
#endif /* DBG */
#ifdef USE_RTS
static p_char *useRTS = "N";
MODULE_PARM( useRTS, "s" );
MODULE_PARM_DESC( useRTS, "Use RTS test interface (<string> N or Y) [N]" );
#endif /* USE_RTS */
/*******************************************************************************
* firmware download specifics
******************************************************************************/
extern struct CFG_RANGE2_STRCT BASED
cfg_drv_act_ranges_pri; // describes primary-actor range of HCF
#if 0 //;? (HCF_TYPE) & HCF_TYPE_AP
extern memimage ap; // AP firmware image to be downloaded
#endif /* HCF_AP */
#if 1 //;? (HCF_TYPE) & HCF_TYPE_STA
//extern memimage station; // STA firmware image to be downloaded
extern memimage fw_image; // firmware image to be downloaded
#endif /* HCF_STA */
/*******************************************************************************
* wl_insert()
*******************************************************************************
*
* DESCRIPTION:
*
* wl_insert() is scheduled to run after a CARD_INSERTION event is
* received, to configure the PCMCIA socket, and to make the ethernet device
* available to the system.
*
* PARAMETERS:
*
* dev - a pointer to the net_device struct of the wireless device
*
* RETURNS:
*
* TRUE or FALSE
*
******************************************************************************/
int wl_insert( struct net_device *dev )
{
int result = 0;
int hcf_status = HCF_SUCCESS;
int i;
unsigned long flags = 0;
struct wl_private *lp = wl_priv(dev);
/*------------------------------------------------------------------------*/
DBG_FUNC( "wl_insert" );
DBG_ENTER( DbgInfo );
/* Initialize the adapter hardware. */
memset( &( lp->hcfCtx ), 0, sizeof( IFB_STRCT ));
/* Initialize the adapter parameters. */
spin_lock_init( &( lp->slock ));
/* Intialize states */
//lp->lockcount = 0; //PE1DNN
lp->is_handling_int = WL_NOT_HANDLING_INT;
lp->firmware_present = WL_FRIMWARE_NOT_PRESENT;
lp->dev = dev;
DBG_PARAM( DbgInfo, "irq_mask", "0x%04x", irq_mask & 0x0FFFF );
DBG_PARAM( DbgInfo, "irq_list", "0x%02x 0x%02x 0x%02x 0x%02x",
irq_list[0] & 0x0FF, irq_list[1] & 0x0FF,
irq_list[2] & 0x0FF, irq_list[3] & 0x0FF );
DBG_PARAM( DbgInfo, PARM_NAME_DESIRED_SSID, "\"%s\"", PARM_DESIRED_SSID );
DBG_PARAM( DbgInfo, PARM_NAME_OWN_SSID, "\"%s\"", PARM_OWN_SSID );
DBG_PARAM( DbgInfo, PARM_NAME_OWN_CHANNEL, "%d", PARM_OWN_CHANNEL);
DBG_PARAM( DbgInfo, PARM_NAME_SYSTEM_SCALE, "%d", PARM_SYSTEM_SCALE );
DBG_PARAM( DbgInfo, PARM_NAME_TX_RATE, "%d", PARM_TX_RATE );
DBG_PARAM( DbgInfo, PARM_NAME_RTS_THRESHOLD, "%d", PARM_RTS_THRESHOLD );
DBG_PARAM( DbgInfo, PARM_NAME_MICROWAVE_ROBUSTNESS, "\"%s\"", PARM_MICROWAVE_ROBUSTNESS );
DBG_PARAM( DbgInfo, PARM_NAME_OWN_NAME, "\"%s\"", PARM_OWN_NAME );
//;? DBG_PARAM( DbgInfo, PARM_NAME_ENABLE_ENCRYPTION, "\"%s\"", PARM_ENABLE_ENCRYPTION );
DBG_PARAM( DbgInfo, PARM_NAME_KEY1, "\"%s\"", PARM_KEY1 );
DBG_PARAM( DbgInfo, PARM_NAME_KEY2, "\"%s\"", PARM_KEY2 );
DBG_PARAM( DbgInfo, PARM_NAME_KEY3, "\"%s\"", PARM_KEY3 );
DBG_PARAM( DbgInfo, PARM_NAME_KEY4, "\"%s\"", PARM_KEY4 );
DBG_PARAM( DbgInfo, PARM_NAME_TX_KEY, "%d", PARM_TX_KEY );
DBG_PARAM( DbgInfo, PARM_NAME_MULTICAST_RATE, "%d", PARM_MULTICAST_RATE );
DBG_PARAM( DbgInfo, PARM_NAME_DOWNLOAD_FIRMWARE, "\"%s\"", PARM_DOWNLOAD_FIRMWARE );
DBG_PARAM( DbgInfo, PARM_NAME_AUTH_KEY_MGMT_SUITE, "%d", PARM_AUTH_KEY_MGMT_SUITE );
//;?#if (HCF_TYPE) & HCF_TYPE_STA
//;?should we make this code conditional depending on in STA mode
//;? DBG_PARAM( DbgInfo, PARM_NAME_PORT_TYPE, "%d", PARM_PORT_TYPE );
DBG_PARAM( DbgInfo, PARM_NAME_PM_ENABLED, "%04x", PARM_PM_ENABLED );
//;? DBG_PARAM( DbgInfo, PARM_NAME_CREATE_IBSS, "\"%s\"", PARM_CREATE_IBSS );
//;? DBG_PARAM( DbgInfo, PARM_NAME_MULTICAST_RX, "\"%s\"", PARM_MULTICAST_RX );
//;? DBG_PARAM( DbgInfo, PARM_NAME_MAX_SLEEP, "%d", PARM_MAX_SLEEP );
//;? DBG_PARAM( DbgInfo, PARM_NAME_NETWORK_ADDR, "\"%s\"", DbgHwAddr( PARM_NETWORK_ADDR ));
//;? DBG_PARAM( DbgInfo, PARM_NAME_AUTHENTICATION, "%d", PARM_AUTHENTICATION );
//;? DBG_PARAM( DbgInfo, PARM_NAME_OWN_ATIM_WINDOW, "%d", PARM_OWN_ATIM_WINDOW );
//;? DBG_PARAM( DbgInfo, PARM_NAME_PM_HOLDOVER_DURATION, "%d", PARM_PM_HOLDOVER_DURATION );
//;? DBG_PARAM( DbgInfo, PARM_NAME_PROMISCUOUS_MODE, "\"%s\"", PARM_PROMISCUOUS_MODE );
//;?#endif /* HCF_STA */
#if 1 //;? (HCF_TYPE) & HCF_TYPE_AP
//;?should we restore this to allow smaller memory footprint
//;?I guess: no, since this is Debug mode only
DBG_PARAM( DbgInfo, PARM_NAME_OWN_DTIM_PERIOD, "%d", PARM_OWN_DTIM_PERIOD );
DBG_PARAM( DbgInfo, PARM_NAME_REJECT_ANY, "\"%s\"", PARM_REJECT_ANY );
DBG_PARAM( DbgInfo, PARM_NAME_EXCLUDE_UNENCRYPTED, "\"%s\"", PARM_EXCLUDE_UNENCRYPTED );
DBG_PARAM( DbgInfo, PARM_NAME_MULTICAST_PM_BUFFERING, "\"%s\"", PARM_MULTICAST_PM_BUFFERING );
DBG_PARAM( DbgInfo, PARM_NAME_INTRA_BSS_RELAY, "\"%s\"", PARM_INTRA_BSS_RELAY );
#ifdef USE_WDS
DBG_PARAM( DbgInfo, PARM_NAME_RTS_THRESHOLD1, "%d", PARM_RTS_THRESHOLD1 );
DBG_PARAM( DbgInfo, PARM_NAME_RTS_THRESHOLD2, "%d", PARM_RTS_THRESHOLD2 );
DBG_PARAM( DbgInfo, PARM_NAME_RTS_THRESHOLD3, "%d", PARM_RTS_THRESHOLD3 );
DBG_PARAM( DbgInfo, PARM_NAME_RTS_THRESHOLD4, "%d", PARM_RTS_THRESHOLD4 );
DBG_PARAM( DbgInfo, PARM_NAME_RTS_THRESHOLD5, "%d", PARM_RTS_THRESHOLD5 );
DBG_PARAM( DbgInfo, PARM_NAME_RTS_THRESHOLD6, "%d", PARM_RTS_THRESHOLD6 );
DBG_PARAM( DbgInfo, PARM_NAME_TX_RATE1, "%d", PARM_TX_RATE1 );
DBG_PARAM( DbgInfo, PARM_NAME_TX_RATE2, "%d", PARM_TX_RATE2 );
DBG_PARAM( DbgInfo, PARM_NAME_TX_RATE3, "%d", PARM_TX_RATE3 );
DBG_PARAM( DbgInfo, PARM_NAME_TX_RATE4, "%d", PARM_TX_RATE4 );
DBG_PARAM( DbgInfo, PARM_NAME_TX_RATE5, "%d", PARM_TX_RATE5 );
DBG_PARAM( DbgInfo, PARM_NAME_TX_RATE6, "%d", PARM_TX_RATE6 );
DBG_PARAM( DbgInfo, PARM_NAME_WDS_ADDRESS1, "\"%s\"", DbgHwAddr( PARM_WDS_ADDRESS1 ));
DBG_PARAM( DbgInfo, PARM_NAME_WDS_ADDRESS2, "\"%s\"", DbgHwAddr( PARM_WDS_ADDRESS2 ));
DBG_PARAM( DbgInfo, PARM_NAME_WDS_ADDRESS3, "\"%s\"", DbgHwAddr( PARM_WDS_ADDRESS3 ));
DBG_PARAM( DbgInfo, PARM_NAME_WDS_ADDRESS4, "\"%s\"", DbgHwAddr( PARM_WDS_ADDRESS4 ));
DBG_PARAM( DbgInfo, PARM_NAME_WDS_ADDRESS5, "\"%s\"", DbgHwAddr( PARM_WDS_ADDRESS5 ));
DBG_PARAM( DbgInfo, PARM_NAME_WDS_ADDRESS6, "\"%s\"", DbgHwAddr( PARM_WDS_ADDRESS6 ));
#endif /* USE_WDS */
#endif /* HCF_AP */
VALID_PARAM( !PARM_DESIRED_SSID || ( strlen( PARM_DESIRED_SSID ) <= PARM_MAX_NAME_LEN ));
VALID_PARAM( !PARM_OWN_SSID || ( strlen( PARM_OWN_SSID ) <= PARM_MAX_NAME_LEN ));
VALID_PARAM(( PARM_OWN_CHANNEL <= PARM_MAX_OWN_CHANNEL ));
VALID_PARAM(( PARM_SYSTEM_SCALE >= PARM_MIN_SYSTEM_SCALE ) && ( PARM_SYSTEM_SCALE <= PARM_MAX_SYSTEM_SCALE ));
VALID_PARAM(( PARM_TX_RATE >= PARM_MIN_TX_RATE ) && ( PARM_TX_RATE <= PARM_MAX_TX_RATE ));
VALID_PARAM(( PARM_RTS_THRESHOLD <= PARM_MAX_RTS_THRESHOLD ));
VALID_PARAM( !PARM_MICROWAVE_ROBUSTNESS || strchr( "NnYy", PARM_MICROWAVE_ROBUSTNESS[0] ) != NULL );
VALID_PARAM( !PARM_OWN_NAME || ( strlen( PARM_NAME_OWN_NAME ) <= PARM_MAX_NAME_LEN ));
VALID_PARAM(( PARM_ENABLE_ENCRYPTION <= PARM_MAX_ENABLE_ENCRYPTION ));
VALID_PARAM( is_valid_key_string( PARM_KEY1 ));
VALID_PARAM( is_valid_key_string( PARM_KEY2 ));
VALID_PARAM( is_valid_key_string( PARM_KEY3 ));
VALID_PARAM( is_valid_key_string( PARM_KEY4 ));
VALID_PARAM(( PARM_TX_KEY >= PARM_MIN_TX_KEY ) && ( PARM_TX_KEY <= PARM_MAX_TX_KEY ));
VALID_PARAM(( PARM_MULTICAST_RATE >= PARM_MIN_MULTICAST_RATE ) &&
( PARM_MULTICAST_RATE <= PARM_MAX_MULTICAST_RATE ));
VALID_PARAM( !PARM_DOWNLOAD_FIRMWARE || ( strlen( PARM_DOWNLOAD_FIRMWARE ) <= 255 /*;?*/ ));
VALID_PARAM(( PARM_AUTH_KEY_MGMT_SUITE < PARM_MAX_AUTH_KEY_MGMT_SUITE ));
VALID_PARAM( !PARM_LOAD_BALANCING || strchr( "NnYy", PARM_LOAD_BALANCING[0] ) != NULL );
VALID_PARAM( !PARM_MEDIUM_DISTRIBUTION || strchr( "NnYy", PARM_MEDIUM_DISTRIBUTION[0] ) != NULL );
VALID_PARAM(( PARM_TX_POW_LEVEL <= PARM_MAX_TX_POW_LEVEL ));
VALID_PARAM(( PARM_PORT_TYPE >= PARM_MIN_PORT_TYPE ) && ( PARM_PORT_TYPE <= PARM_MAX_PORT_TYPE ));
VALID_PARAM( PARM_PM_ENABLED <= WVLAN_PM_STATE_STANDARD ||
( PARM_PM_ENABLED & 0x7FFF ) <= WVLAN_PM_STATE_STANDARD );
VALID_PARAM( !PARM_CREATE_IBSS || strchr( "NnYy", PARM_CREATE_IBSS[0] ) != NULL );
VALID_PARAM( !PARM_MULTICAST_RX || strchr( "NnYy", PARM_MULTICAST_RX[0] ) != NULL );
VALID_PARAM(( PARM_MAX_SLEEP <= PARM_MAX_MAX_PM_SLEEP ));
VALID_PARAM(( PARM_AUTHENTICATION <= PARM_MAX_AUTHENTICATION ));
VALID_PARAM(( PARM_OWN_ATIM_WINDOW <= PARM_MAX_OWN_ATIM_WINDOW ));
VALID_PARAM(( PARM_PM_HOLDOVER_DURATION <= PARM_MAX_PM_HOLDOVER_DURATION ));
VALID_PARAM( !PARM_PROMISCUOUS_MODE || strchr( "NnYy", PARM_PROMISCUOUS_MODE[0] ) != NULL );
VALID_PARAM(( PARM_CONNECTION_CONTROL <= PARM_MAX_CONNECTION_CONTROL ));
VALID_PARAM(( PARM_OWN_DTIM_PERIOD >= PARM_MIN_OWN_DTIM_PERIOD ));
VALID_PARAM( !PARM_REJECT_ANY || strchr( "NnYy", PARM_REJECT_ANY[0] ) != NULL );
VALID_PARAM( !PARM_EXCLUDE_UNENCRYPTED || strchr( "NnYy", PARM_EXCLUDE_UNENCRYPTED[0] ) != NULL );
VALID_PARAM( !PARM_MULTICAST_PM_BUFFERING || strchr( "NnYy", PARM_MULTICAST_PM_BUFFERING[0] ) != NULL );
VALID_PARAM( !PARM_INTRA_BSS_RELAY || strchr( "NnYy", PARM_INTRA_BSS_RELAY[0] ) != NULL );
#ifdef USE_WDS
VALID_PARAM(( PARM_RTS_THRESHOLD1 <= PARM_MAX_RTS_THRESHOLD ));
VALID_PARAM(( PARM_RTS_THRESHOLD2 <= PARM_MAX_RTS_THRESHOLD ));
VALID_PARAM(( PARM_RTS_THRESHOLD3 <= PARM_MAX_RTS_THRESHOLD ));
VALID_PARAM(( PARM_RTS_THRESHOLD4 <= PARM_MAX_RTS_THRESHOLD ));
VALID_PARAM(( PARM_RTS_THRESHOLD5 <= PARM_MAX_RTS_THRESHOLD ));
VALID_PARAM(( PARM_RTS_THRESHOLD6 <= PARM_MAX_RTS_THRESHOLD ));
VALID_PARAM(( PARM_TX_RATE1 >= PARM_MIN_TX_RATE ) && (PARM_TX_RATE1 <= PARM_MAX_TX_RATE ));
VALID_PARAM(( PARM_TX_RATE2 >= PARM_MIN_TX_RATE ) && (PARM_TX_RATE2 <= PARM_MAX_TX_RATE ));
VALID_PARAM(( PARM_TX_RATE3 >= PARM_MIN_TX_RATE ) && (PARM_TX_RATE3 <= PARM_MAX_TX_RATE ));
VALID_PARAM(( PARM_TX_RATE4 >= PARM_MIN_TX_RATE ) && (PARM_TX_RATE4 <= PARM_MAX_TX_RATE ));
VALID_PARAM(( PARM_TX_RATE5 >= PARM_MIN_TX_RATE ) && (PARM_TX_RATE5 <= PARM_MAX_TX_RATE ));
VALID_PARAM(( PARM_TX_RATE6 >= PARM_MIN_TX_RATE ) && (PARM_TX_RATE6 <= PARM_MAX_TX_RATE ));
#endif /* USE_WDS */
VALID_PARAM(( PARM_OWN_BEACON_INTERVAL >= PARM_MIN_OWN_BEACON_INTERVAL ) && ( PARM_OWN_BEACON_INTERVAL <= PARM_MAX_OWN_BEACON_INTERVAL ));
VALID_PARAM(( PARM_COEXISTENCE <= PARM_COEXISTENCE ));
/* Set the driver parameters from the passed in parameters. */
/* THESE MODULE PARAMETERS ARE TO BE DEPRECATED IN FAVOR OF A NAMING CONVENTION
WHICH IS INLINE WITH THE FORTHCOMING WAVELAN API */
/* START NEW PARAMETERS */
lp->Channel = PARM_OWN_CHANNEL;
lp->DistanceBetweenAPs = PARM_SYSTEM_SCALE;
/* Need to determine how to handle the new bands for 5GHz */
lp->TxRateControl[0] = PARM_DEFAULT_TX_RATE_2GHZ;
lp->TxRateControl[1] = PARM_DEFAULT_TX_RATE_5GHZ;
lp->RTSThreshold = PARM_RTS_THRESHOLD;
/* Need to determine how to handle the new bands for 5GHz */
lp->MulticastRate[0] = PARM_DEFAULT_MULTICAST_RATE_2GHZ;
lp->MulticastRate[1] = PARM_DEFAULT_MULTICAST_RATE_5GHZ;
if ( strchr( "Yy", PARM_MICROWAVE_ROBUSTNESS[0] ) != NULL ) {
lp->MicrowaveRobustness = 1;
} else {
lp->MicrowaveRobustness = 0;
}
if ( PARM_DESIRED_SSID && ( strlen( PARM_DESIRED_SSID ) <= HCF_MAX_NAME_LEN )) {
strcpy( lp->NetworkName, PARM_DESIRED_SSID );
}
if ( PARM_OWN_SSID && ( strlen( PARM_OWN_SSID ) <= HCF_MAX_NAME_LEN )) {
strcpy( lp->NetworkName, PARM_OWN_SSID );
}
if ( PARM_OWN_NAME && ( strlen( PARM_OWN_NAME ) <= HCF_MAX_NAME_LEN )) {
strcpy( lp->StationName, PARM_OWN_NAME );
}
lp->EnableEncryption = PARM_ENABLE_ENCRYPTION;
if ( PARM_KEY1 && ( strlen( PARM_KEY1 ) <= MAX_KEY_LEN )) {
strcpy( lp->Key1, PARM_KEY1 );
}
if ( PARM_KEY2 && ( strlen( PARM_KEY2 ) <= MAX_KEY_LEN )) {
strcpy( lp->Key2, PARM_KEY2 );
}
if ( PARM_KEY3 && ( strlen( PARM_KEY3 ) <= MAX_KEY_LEN )) {
strcpy( lp->Key3, PARM_KEY3 );
}
if ( PARM_KEY4 && ( strlen( PARM_KEY4 ) <= MAX_KEY_LEN )) {
strcpy( lp->Key4, PARM_KEY4 );
}
lp->TransmitKeyID = PARM_TX_KEY;
key_string2key( lp->Key1, &(lp->DefaultKeys.key[0] ));
key_string2key( lp->Key2, &(lp->DefaultKeys.key[1] ));
key_string2key( lp->Key3, &(lp->DefaultKeys.key[2] ));
key_string2key( lp->Key4, &(lp->DefaultKeys.key[3] ));
lp->DownloadFirmware = 1 ; //;?to be upgraded PARM_DOWNLOAD_FIRMWARE;
lp->AuthKeyMgmtSuite = PARM_AUTH_KEY_MGMT_SUITE;
if ( strchr( "Yy", PARM_LOAD_BALANCING[0] ) != NULL ) {
lp->loadBalancing = 1;
} else {
lp->loadBalancing = 0;
}
if ( strchr( "Yy", PARM_MEDIUM_DISTRIBUTION[0] ) != NULL ) {
lp->mediumDistribution = 1;
} else {
lp->mediumDistribution = 0;
}
lp->txPowLevel = PARM_TX_POW_LEVEL;
lp->srsc[0] = PARM_SRSC_2GHZ;
lp->srsc[1] = PARM_SRSC_5GHZ;
lp->brsc[0] = PARM_BRSC_2GHZ;
lp->brsc[1] = PARM_BRSC_5GHZ;
#if 1 //;? (HCF_TYPE) & HCF_TYPE_STA
//;?seems reasonable that even an AP-only driver could afford this small additional footprint
lp->PortType = PARM_PORT_TYPE;
lp->MaxSleepDuration = PARM_MAX_SLEEP;
lp->authentication = PARM_AUTHENTICATION;
lp->atimWindow = PARM_OWN_ATIM_WINDOW;
lp->holdoverDuration = PARM_PM_HOLDOVER_DURATION;
lp->PMEnabled = PARM_PM_ENABLED; //;?
if ( strchr( "Yy", PARM_CREATE_IBSS[0] ) != NULL ) {
lp->CreateIBSS = 1;
} else {
lp->CreateIBSS = 0;
}
if ( strchr( "Nn", PARM_MULTICAST_RX[0] ) != NULL ) {
lp->MulticastReceive = 0;
} else {
lp->MulticastReceive = 1;
}
if ( strchr( "Yy", PARM_PROMISCUOUS_MODE[0] ) != NULL ) {
lp->promiscuousMode = 1;
} else {
lp->promiscuousMode = 0;
}
for( i = 0; i < ETH_ALEN; i++ ) {
lp->MACAddress[i] = PARM_NETWORK_ADDR[i];
}
lp->connectionControl = PARM_CONNECTION_CONTROL;
#endif /* HCF_STA */
#if 1 //;? (HCF_TYPE) & HCF_TYPE_AP
//;?should we restore this to allow smaller memory footprint
lp->DTIMPeriod = PARM_OWN_DTIM_PERIOD;
if ( strchr( "Yy", PARM_REJECT_ANY[0] ) != NULL ) {
lp->RejectAny = 1;
} else {
lp->RejectAny = 0;
}
if ( strchr( "Nn", PARM_EXCLUDE_UNENCRYPTED[0] ) != NULL ) {
lp->ExcludeUnencrypted = 0;
} else {
lp->ExcludeUnencrypted = 1;
}
if ( strchr( "Yy", PARM_MULTICAST_PM_BUFFERING[0] ) != NULL ) {
lp->multicastPMBuffering = 1;
} else {
lp->multicastPMBuffering = 0;
}
if ( strchr( "Yy", PARM_INTRA_BSS_RELAY[0] ) != NULL ) {
lp->intraBSSRelay = 1;
} else {
lp->intraBSSRelay = 0;
}
lp->ownBeaconInterval = PARM_OWN_BEACON_INTERVAL;
lp->coexistence = PARM_COEXISTENCE;
#ifdef USE_WDS
lp->wds_port[0].rtsThreshold = PARM_RTS_THRESHOLD1;
lp->wds_port[1].rtsThreshold = PARM_RTS_THRESHOLD2;
lp->wds_port[2].rtsThreshold = PARM_RTS_THRESHOLD3;
lp->wds_port[3].rtsThreshold = PARM_RTS_THRESHOLD4;
lp->wds_port[4].rtsThreshold = PARM_RTS_THRESHOLD5;
lp->wds_port[5].rtsThreshold = PARM_RTS_THRESHOLD6;
lp->wds_port[0].txRateCntl = PARM_TX_RATE1;
lp->wds_port[1].txRateCntl = PARM_TX_RATE2;
lp->wds_port[2].txRateCntl = PARM_TX_RATE3;
lp->wds_port[3].txRateCntl = PARM_TX_RATE4;
lp->wds_port[4].txRateCntl = PARM_TX_RATE5;
lp->wds_port[5].txRateCntl = PARM_TX_RATE6;
for( i = 0; i < ETH_ALEN; i++ ) {
lp->wds_port[0].wdsAddress[i] = PARM_WDS_ADDRESS1[i];
}
for( i = 0; i < ETH_ALEN; i++ ) {
lp->wds_port[1].wdsAddress[i] = PARM_WDS_ADDRESS2[i];
}
for( i = 0; i < ETH_ALEN; i++ ) {
lp->wds_port[2].wdsAddress[i] = PARM_WDS_ADDRESS3[i];
}
for( i = 0; i < ETH_ALEN; i++ ) {
lp->wds_port[3].wdsAddress[i] = PARM_WDS_ADDRESS4[i];
}
for( i = 0; i < ETH_ALEN; i++ ) {
lp->wds_port[4].wdsAddress[i] = PARM_WDS_ADDRESS5[i];
}
for( i = 0; i < ETH_ALEN; i++ ) {
lp->wds_port[5].wdsAddress[i] = PARM_WDS_ADDRESS6[i];
}
#endif /* USE_WDS */
#endif /* HCF_AP */
#ifdef USE_RTS
if ( strchr( "Yy", useRTS[0] ) != NULL ) {
lp->useRTS = 1;
} else {
lp->useRTS = 0;
}
#endif /* USE_RTS */
/* END NEW PARAMETERS */
wl_lock( lp, &flags );
/* Initialize the portState variable */
lp->portState = WVLAN_PORT_STATE_DISABLED;
/* Initialize the ScanResult struct */
memset( &( lp->scan_results ), 0, sizeof( lp->scan_results ));
lp->scan_results.scan_complete = FALSE;
/* Initialize the ProbeResult struct */
memset( &( lp->probe_results ), 0, sizeof( lp->probe_results ));
lp->probe_results.scan_complete = FALSE;
lp->probe_num_aps = 0;
/* Initialize Tx queue stuff */
memset( lp->txList, 0, sizeof( lp->txList ));
INIT_LIST_HEAD( &( lp->txFree ));
lp->txF.skb = NULL;
lp->txF.port = 0;
for( i = 0; i < DEFAULT_NUM_TX_FRAMES; i++ ) {
list_add_tail( &( lp->txList[i].node ), &( lp->txFree ));
}
for( i = 0; i < WVLAN_MAX_TX_QUEUES; i++ ) {
INIT_LIST_HEAD( &( lp->txQ[i] ));
}
lp->netif_queue_on = TRUE;
lp->txQ_count = 0;
/* Initialize the use_dma element in the adapter structure. Not sure if
this should be a compile-time or run-time configurable. So for now,
implement as run-time and just define here */
#ifdef WARP
#ifdef ENABLE_DMA
DBG_TRACE( DbgInfo, "HERMES 2.5 BUSMASTER DMA MODE\n" );
lp->use_dma = 1;
#else
DBG_TRACE( DbgInfo, "HERMES 2.5 PORT I/O MODE\n" );
lp->use_dma = 0;
#endif // ENABLE_DMA
#endif // WARP
/* Register the ISR handler information here, so that it's not done
repeatedly in the ISR */
tasklet_init(&lp->task, wl_isr_handler, (unsigned long)lp);
/* Connect to the adapter */
DBG_TRACE( DbgInfo, "Calling hcf_connect()...\n" );
hcf_status = hcf_connect( &lp->hcfCtx, dev->base_addr );
//HCF_ERR_INCOMP_FW is acceptable, because download must still take place
//HCF_ERR_INCOMP_PRI is not acceptable
if ( hcf_status != HCF_SUCCESS && hcf_status != HCF_ERR_INCOMP_FW ) {
DBG_ERROR( DbgInfo, "hcf_connect() failed, status: 0x%x\n", hcf_status );
wl_unlock( lp, &flags );
goto hcf_failed;
}
//;?should set HCF_version and how about driver_stat
lp->driverInfo.IO_address = dev->base_addr;
lp->driverInfo.IO_range = HCF_NUM_IO_PORTS; //;?conditionally 0x40 or 0x80 seems better
lp->driverInfo.IRQ_number = dev->irq;
lp->driverInfo.card_stat = lp->hcfCtx.IFB_CardStat;
//;? what happened to frame_type
/* Fill in the driver identity structure */
lp->driverIdentity.len = ( sizeof( lp->driverIdentity ) / sizeof( hcf_16 )) - 1;
lp->driverIdentity.typ = CFG_DRV_IDENTITY;
lp->driverIdentity.comp_id = DRV_IDENTITY;
lp->driverIdentity.variant = DRV_VARIANT;
lp->driverIdentity.version_major = DRV_MAJOR_VERSION;
lp->driverIdentity.version_minor = DRV_MINOR_VERSION;
/* Start the card here - This needs to be done in order to get the
MAC address for the network layer */
DBG_TRACE( DbgInfo, "Calling wvlan_go() to perform a card reset...\n" );
hcf_status = wl_go( lp );
if ( hcf_status != HCF_SUCCESS ) {
DBG_ERROR( DbgInfo, "wl_go() failed\n" );
wl_unlock( lp, &flags );
goto hcf_failed;
}
/* Certain RIDs must be set before enabling the ports */
wl_put_ltv_init( lp );
#if 0 //;?why was this already commented out in wl_lkm_720
/* Enable the ports */
if ( wl_adapter_is_open( lp->dev )) {
/* Enable the ports */
DBG_TRACE( DbgInfo, "Enabling Port 0\n" );
hcf_status = wl_enable( lp );
if ( hcf_status != HCF_SUCCESS ) {
DBG_TRACE( DbgInfo, "Enable port 0 failed: 0x%x\n", hcf_status );
}
#if (HCF_TYPE) & HCF_TYPE_AP
DBG_TRACE( DbgInfo, "Enabling WDS Ports\n" );
//wl_enable_wds_ports( lp );
#endif /* (HCF_TYPE) & HCF_TYPE_AP */
}
#endif
/* Fill out the MAC address information in the net_device struct */
memcpy( lp->dev->dev_addr, lp->MACAddress, ETH_ALEN );
dev->addr_len = ETH_ALEN;
lp->is_registered = TRUE;
#ifdef USE_PROFILE
/* Parse the config file for the sake of creating WDS ports if WDS is
configured there but not in the module options */
parse_config( dev );
#endif /* USE_PROFILE */
/* If we're going into AP Mode, register the "virtual" ethernet devices
needed for WDS */
WL_WDS_NETDEV_REGISTER( lp );
/* Reset the DownloadFirmware variable in the private struct. If the
config file is not used, this will not matter; if it is used, it
will be reparsed in wl_open(). This is done because logic in wl_open
used to check if a firmware download is needed is broken by parsing
the file here; however, this parsing is needed to register WDS ports
in AP mode, if they are configured */
lp->DownloadFirmware = WVLAN_DRV_MODE_STA; //;?download_firmware;
#ifdef USE_RTS
if ( lp->useRTS == 1 ) {
DBG_TRACE( DbgInfo, "ENTERING RTS MODE...\n" );
wl_act_int_off( lp );
lp->is_handling_int = WL_NOT_HANDLING_INT; // Not handling interrupts anymore
wl_disable( lp );
hcf_connect( &lp->hcfCtx, HCF_DISCONNECT);
}
#endif /* USE_RTS */
wl_unlock( lp, &flags );
DBG_TRACE( DbgInfo, "%s: Wireless, io_addr %#03lx, irq %d, ""mac_address ",
dev->name, dev->base_addr, dev->irq );
for( i = 0; i < ETH_ALEN; i++ ) {
printk( "%02X%c", dev->dev_addr[i], (( i < ( ETH_ALEN-1 )) ? ':' : '\n' ));
}
#if 0 //SCULL_USE_PROC /* don't waste space if unused */
create_proc_read_entry( "wlags", 0, NULL, scull_read_procmem, dev );
proc_mkdir("driver/wlags49", 0);
proc_write("driver/wlags49/wlags49_type", write_int, &lp->wlags49_type);
#endif /* SCULL_USE_PROC */
DBG_LEAVE( DbgInfo );
return result;
hcf_failed:
wl_hcf_error( dev, hcf_status );
failed:
DBG_ERROR( DbgInfo, "wl_insert() FAILED\n" );
if ( lp->is_registered == TRUE ) {
lp->is_registered = FALSE;
}
WL_WDS_NETDEV_DEREGISTER( lp );
result = -EFAULT;
DBG_LEAVE( DbgInfo );
return result;
} // wl_insert
/*============================================================================*/
/*******************************************************************************
* wl_reset()
*******************************************************************************
*
* DESCRIPTION:
*
* Reset the adapter.
*
* PARAMETERS:
*
* dev - a pointer to the net_device struct of the wireless device
*
* RETURNS:
*
* an HCF status code
*
******************************************************************************/
int wl_reset(struct net_device *dev)
{
struct wl_private *lp = wl_priv(dev);
int hcf_status = HCF_SUCCESS;
/*------------------------------------------------------------------------*/
DBG_FUNC( "wl_reset" );
DBG_ENTER( DbgInfo );
DBG_PARAM( DbgInfo, "dev", "%s (0x%p)", dev->name, dev );
DBG_PARAM( DbgInfo, "dev->base_addr", "(%#03lx)", dev->base_addr );
/*
* The caller should already have a lock and
* disable the interrupts, we do not lock here,
* nor do we enable/disable interrupts!
*/
DBG_TRACE( DbgInfo, "Device Base Address: %#03lx\n", dev->base_addr );
if ( dev->base_addr ) {
/* Shutdown the adapter. */
hcf_connect( &lp->hcfCtx, HCF_DISCONNECT );
/* Reset the driver information. */
lp->txBytes = 0;
/* Connect to the adapter. */
hcf_status = hcf_connect( &lp->hcfCtx, dev->base_addr );
if ( hcf_status != HCF_SUCCESS && hcf_status != HCF_ERR_INCOMP_FW ) {
DBG_ERROR( DbgInfo, "hcf_connect() failed, status: 0x%x\n", hcf_status );
goto out;
}
/* Check if firmware is present, if not change state */
if ( hcf_status == HCF_ERR_INCOMP_FW ) {
lp->firmware_present = WL_FRIMWARE_NOT_PRESENT;
}
/* Initialize the portState variable */
lp->portState = WVLAN_PORT_STATE_DISABLED;
/* Restart the adapter. */
hcf_status = wl_go( lp );
if ( hcf_status != HCF_SUCCESS ) {
DBG_ERROR( DbgInfo, "wl_go() failed, status: 0x%x\n", hcf_status );
goto out;
}
/* Certain RIDs must be set before enabling the ports */
wl_put_ltv_init( lp );
} else {
DBG_ERROR( DbgInfo, "Device Base Address INVALID!!!\n" );
}
out:
DBG_LEAVE( DbgInfo );
return hcf_status;
} // wl_reset
/*============================================================================*/
/*******************************************************************************
* wl_go()
*******************************************************************************
*
* DESCRIPTION:
*
* Reset the adapter.
*
* PARAMETERS:
*
* dev - a pointer to the net_device struct of the wireless device
*
* RETURNS:
*
* an HCF status code
*
******************************************************************************/
int wl_go( struct wl_private *lp )
{
int hcf_status = HCF_SUCCESS;
char *cp = NULL; //fw_image
int retries = 0;
/*------------------------------------------------------------------------*/
DBG_FUNC( "wl_go" );
DBG_ENTER( DbgInfo );
hcf_status = wl_disable( lp );
if ( hcf_status != HCF_SUCCESS ) {
DBG_TRACE( DbgInfo, "Disable port 0 failed: 0x%x\n", hcf_status );
while (( hcf_status != HCF_SUCCESS ) && (retries < 10)) {
retries++;
hcf_status = wl_disable( lp );
}
if ( hcf_status == HCF_SUCCESS ) {
DBG_TRACE( DbgInfo, "Disable port 0 succes : %d retries\n", retries );
} else {
DBG_TRACE( DbgInfo, "Disable port 0 failed after: %d retries\n", retries );
}
}
#if 1 //;? (HCF_TYPE) & HCF_TYPE_AP
//DBG_TRACE( DbgInfo, "Disabling WDS Ports\n" );
//wl_disable_wds_ports( lp );
#endif /* (HCF_TYPE) & HCF_TYPE_AP */
//;?what was the purpose of this
// /* load the appropriate firmware image, depending on driver mode */
// lp->ltvRecord.len = ( sizeof( CFG_RANGE20_STRCT ) / sizeof( hcf_16 )) - 1;
// lp->ltvRecord.typ = CFG_DRV_ACT_RANGES_PRI;
// hcf_get_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
#if BIN_DL
if ( strlen( lp->fw_image_filename ) ) {
mm_segment_t fs;
int file_desc;
int rc;
DBG_TRACE( DbgInfo, "F/W image:%s:\n", lp->fw_image_filename );
/* Obtain a user-space process context, storing the original context */
fs = get_fs( );
set_fs( get_ds( ));
file_desc = open( lp->fw_image_filename, O_RDONLY, 0 );
if ( file_desc == -1 ) {
DBG_ERROR( DbgInfo, "No image file found\n" );
} else {
DBG_TRACE( DbgInfo, "F/W image file found\n" );
#define DHF_ALLOC_SIZE 96000 //just below 96K, let's hope it suffices for now and for the future
cp = (char*)vmalloc( DHF_ALLOC_SIZE );
if ( cp == NULL ) {
DBG_ERROR( DbgInfo, "error in vmalloc\n" );
} else {
rc = read( file_desc, cp, DHF_ALLOC_SIZE );
if ( rc == DHF_ALLOC_SIZE ) {
DBG_ERROR( DbgInfo, "buffer too small, %d\n", DHF_ALLOC_SIZE );
} else if ( rc > 0 ) {
DBG_TRACE( DbgInfo, "read O.K.: %d bytes %.12s\n", rc, cp );
rc = read( file_desc, &cp[rc], 1 );
if ( rc == 0 ) { //;/change to an until-loop at rc<=0
DBG_TRACE( DbgInfo, "no more to read\n" );
}
}
if ( rc != 0 ) {
DBG_ERROR( DbgInfo, "file not read in one swoop or other error"\
", give up, too complicated, rc = %0X\n", rc );
DBG_ERROR( DbgInfo, "still have to change code to get a real download now !!!!!!!!\n" );
} else {
DBG_TRACE( DbgInfo, "before dhf_download_binary\n" );
hcf_status = dhf_download_binary( (memimage *)cp );
DBG_TRACE( DbgInfo, "after dhf_download_binary, before dhf_download_fw\n" );
//;?improve error flow/handling
hcf_status = dhf_download_fw( &lp->hcfCtx, (memimage *)cp );
DBG_TRACE( DbgInfo, "after dhf_download_fw\n" );
}
vfree( cp );
}
close( file_desc );
}
set_fs( fs ); /* Return to the original context */
}
#endif // BIN_DL
/* If firmware is present but the type is unknown then download anyway */
if ( (lp->firmware_present == WL_FRIMWARE_PRESENT)
&&
( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) != COMP_ID_FW_STA )
&&
( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) != COMP_ID_FW_AP ) ) {
/* Unknown type, download needed. */
lp->firmware_present = WL_FRIMWARE_NOT_PRESENT;
}
if(lp->firmware_present == WL_FRIMWARE_NOT_PRESENT)
{
if ( cp == NULL ) {
DBG_TRACE( DbgInfo, "Downloading STA firmware...\n" );
// hcf_status = dhf_download_fw( &lp->hcfCtx, &station );
hcf_status = dhf_download_fw( &lp->hcfCtx, &fw_image );
}
if ( hcf_status != HCF_SUCCESS ) {
DBG_ERROR( DbgInfo, "Firmware Download failed\n" );
DBG_LEAVE( DbgInfo );
return hcf_status;
}
}
/* Report the FW versions */
//;?obsolete, use the available IFB info:: wl_get_pri_records( lp );
if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_STA ) {
DBG_TRACE( DbgInfo, "downloaded station F/W\n" );
} else if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_AP ) {
DBG_TRACE( DbgInfo, "downloaded AP F/W\n" );
} else {
DBG_ERROR( DbgInfo, "unknown F/W type\n" );
}
/*
* Downloaded, no need to repeat this next time, assume the
* contents stays in the card until it is powered off. Note we
* do not switch firmware on the fly, the firmware is fixed in
* the driver for now.
*/
lp->firmware_present = WL_FRIMWARE_PRESENT;
DBG_TRACE( DbgInfo, "ComponentID:%04x variant:%04x major:%04x minor:%04x\n",
CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ),
CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.variant ),
CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.version_major ),
CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.version_minor ));
/* now we wil get the MAC address of the card */
lp->ltvRecord.len = 4;
if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_AP ) {
lp->ltvRecord.typ = CFG_NIC_MAC_ADDR;
} else
{
lp->ltvRecord.typ = CFG_CNF_OWN_MAC_ADDR;
}
hcf_status = hcf_get_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
if ( hcf_status != HCF_SUCCESS ) {
DBG_ERROR( DbgInfo, "Could not retrieve MAC address\n" );
DBG_LEAVE( DbgInfo );
return hcf_status;
}
memcpy( lp->MACAddress, &lp->ltvRecord.u.u8[0], ETH_ALEN );
DBG_TRACE( DbgInfo, "Card MAC Address: %s\n", DbgHwAddr( lp->MACAddress ));
/* Write out configuration to the device, enable, and reconnect. However,
only reconnect if in AP mode. For STA mode, need to wait for passive scan
completion before a connect can be issued */
wl_put_ltv( lp );
/* Enable the ports */
hcf_status = wl_enable( lp );
if ( lp->DownloadFirmware == WVLAN_DRV_MODE_AP ) {
#ifdef USE_WDS
wl_enable_wds_ports( lp );
#endif // USE_WDS
hcf_status = wl_connect( lp );
}
DBG_LEAVE( DbgInfo );
return hcf_status;
} // wl_go
/*============================================================================*/
/*******************************************************************************
* wl_set_wep_keys()
*******************************************************************************
*
* DESCRIPTION:
*
* Write TxKeyID and WEP keys to the adapter. This is separated from
* wl_apply() to allow dynamic WEP key updates through the wireless
* extensions.
*
* PARAMETERS:
*
* lp - a pointer to the wireless adapter's private structure
*
* RETURNS:
*
* N/A
*
******************************************************************************/
void wl_set_wep_keys( struct wl_private *lp )
{
int count = 0;
/*------------------------------------------------------------------------*/
DBG_FUNC( "wl_set_wep_keys" );
DBG_ENTER( DbgInfo );
DBG_PARAM( DbgInfo, "lp", "%s (0x%p)", lp->dev->name, lp );
if ( lp->EnableEncryption ) {
/* NOTE: CFG_CNF_ENCRYPTION is set in wl_put_ltv() as it's a static
RID */
/* set TxKeyID */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_TX_KEY_ID;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE(lp->TransmitKeyID - 1);
hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
DBG_TRACE( DbgInfo, "Key 1 len: %d\n", lp->DefaultKeys.key[0].len );
DBG_TRACE( DbgInfo, "Key 2 len: %d\n", lp->DefaultKeys.key[1].len );
DBG_TRACE( DbgInfo, "Key 3 len: %d\n", lp->DefaultKeys.key[2].len );
DBG_TRACE( DbgInfo, "Key 4 len: %d\n", lp->DefaultKeys.key[3].len );
/* write keys */
lp->DefaultKeys.len = sizeof( lp->DefaultKeys ) / sizeof( hcf_16 ) - 1;
lp->DefaultKeys.typ = CFG_DEFAULT_KEYS;
/* endian translate the appropriate key information */
for( count = 0; count < MAX_KEYS; count++ ) {
lp->DefaultKeys.key[count].len = CNV_INT_TO_LITTLE( lp->DefaultKeys.key[count].len );
}
hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->DefaultKeys ));
/* Reverse the above endian translation, since these keys are accessed
elsewhere */
for( count = 0; count < MAX_KEYS; count++ ) {
lp->DefaultKeys.key[count].len = CNV_INT_TO_LITTLE( lp->DefaultKeys.key[count].len );
}
DBG_NOTICE( DbgInfo, "encrypt: %d, ID: %d\n", lp->EnableEncryption, lp->TransmitKeyID );
DBG_NOTICE( DbgInfo, "set key: %s(%d) [%d]\n", lp->DefaultKeys.key[lp->TransmitKeyID-1].key, lp->DefaultKeys.key[lp->TransmitKeyID-1].len, lp->TransmitKeyID-1 );
}
DBG_LEAVE( DbgInfo );
} // wl_set_wep_keys
/*============================================================================*/
/*******************************************************************************
* wl_apply()
*******************************************************************************
*
* DESCRIPTION:
*
* Write the parameters to the adapter. (re-)enables the card if device is
* open. Returns hcf_status of hcf_enable().
*
* PARAMETERS:
*
* lp - a pointer to the wireless adapter's private structure
*
* RETURNS:
*
* an HCF status code
*
******************************************************************************/
int wl_apply(struct wl_private *lp)
{
int hcf_status = HCF_SUCCESS;
/*------------------------------------------------------------------------*/
DBG_FUNC( "wl_apply" );
DBG_ENTER( DbgInfo );
DBG_ASSERT( lp != NULL);
DBG_PARAM( DbgInfo, "lp", "%s (0x%p)", lp->dev->name, lp );
if ( !( lp->flags & WVLAN2_UIL_BUSY )) {
/* The adapter parameters have changed:
disable card
reload parameters
enable card
*/
if ( wl_adapter_is_open( lp->dev )) {
/* Disconnect and disable if necessary */
hcf_status = wl_disconnect( lp );
if ( hcf_status != HCF_SUCCESS ) {
DBG_ERROR( DbgInfo, "Disconnect failed\n" );
DBG_LEAVE( DbgInfo );
return -1;
}
hcf_status = wl_disable( lp );
if ( hcf_status != HCF_SUCCESS ) {
DBG_ERROR( DbgInfo, "Disable failed\n" );
DBG_LEAVE( DbgInfo );
return -1;
} else {
/* Write out configuration to the device, enable, and reconnect.
However, only reconnect if in AP mode. For STA mode, need to
wait for passive scan completion before a connect can be
issued */
hcf_status = wl_put_ltv( lp );
if ( hcf_status == HCF_SUCCESS ) {
hcf_status = wl_enable( lp );
if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_AP ) {
hcf_status = wl_connect( lp );
}
} else {
DBG_WARNING( DbgInfo, "wl_put_ltv() failed\n" );
}
}
}
}
DBG_LEAVE( DbgInfo );
return hcf_status;
} // wl_apply
/*============================================================================*/
/*******************************************************************************
* wl_put_ltv_init()
*******************************************************************************
*
* DESCRIPTION:
*
* Used to set basic parameters for card initialization.
*
* PARAMETERS:
*
* lp - a pointer to the wireless adapter's private structure
*
* RETURNS:
*
* an HCF status code
*
******************************************************************************/
int wl_put_ltv_init( struct wl_private *lp )
{
int i;
int hcf_status;
CFG_RID_LOG_STRCT *RidLog;
/*------------------------------------------------------------------------*/
DBG_FUNC( "wl_put_ltv_init" );
DBG_ENTER( DbgInfo );
if ( lp == NULL ) {
DBG_ERROR( DbgInfo, "lp pointer is NULL\n" );
DBG_LEAVE( DbgInfo );
return -1;
}
/* DMA/IO */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_CNTL_OPT;
/* The Card Services build must ALWAYS configure for 16-bit I/O. PCI or
CardBus can be set to either 16/32 bit I/O, or Bus Master DMA, but only
for Hermes-2.5 */
#ifdef BUS_PCMCIA
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( USE_16BIT );
#else
if ( lp->use_dma ) {
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( USE_DMA );
} else {
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( 0 );
}
#endif
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
DBG_TRACE( DbgInfo, "CFG_CNTL_OPT : 0x%04x\n",
lp->ltvRecord.u.u16[0] );
DBG_TRACE( DbgInfo, "CFG_CNTL_OPT result : 0x%04x\n",
hcf_status );
/* Register the list of RIDs on which asynchronous notification is
required. Note that this mechanism replaces the mailbox, so the mailbox
can be queried by the host (if desired) without contention from us */
i=0;
lp->RidList[i].len = sizeof( lp->ProbeResp );
lp->RidList[i].typ = CFG_ACS_SCAN;
lp->RidList[i].bufp = (wci_recordp)&lp->ProbeResp;
//lp->ProbeResp.infoType = 0xFFFF;
i++;
lp->RidList[i].len = sizeof( lp->assoc_stat );
lp->RidList[i].typ = CFG_ASSOC_STAT;
lp->RidList[i].bufp = (wci_recordp)&lp->assoc_stat;
lp->assoc_stat.len = 0xFFFF;
i++;
lp->RidList[i].len = 4;
lp->RidList[i].typ = CFG_UPDATED_INFO_RECORD;
lp->RidList[i].bufp = (wci_recordp)&lp->updatedRecord;
lp->updatedRecord.len = 0xFFFF;
i++;
lp->RidList[i].len = sizeof( lp->sec_stat );
lp->RidList[i].typ = CFG_SECURITY_STAT;
lp->RidList[i].bufp = (wci_recordp)&lp->sec_stat;
lp->sec_stat.len = 0xFFFF;
i++;
lp->RidList[i].typ = 0; // Terminate List
RidLog = (CFG_RID_LOG_STRCT *)&lp->ltvRecord;
RidLog->len = 3;
RidLog->typ = CFG_REG_INFO_LOG;
RidLog->recordp = (RID_LOGP)&lp->RidList[0];
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
DBG_TRACE( DbgInfo, "CFG_REG_INFO_LOG\n" );
DBG_TRACE( DbgInfo, "CFG_REG_INFO_LOG result : 0x%04x\n",
hcf_status );
DBG_LEAVE( DbgInfo );
return hcf_status;
} // wl_put_ltv_init
/*============================================================================*/
/*******************************************************************************
* wl_put_ltv()
*******************************************************************************
*
* DESCRIPTION:
*
* Used by wvlan_apply() and wvlan_go to set the card's configuration.
*
* PARAMETERS:
*
* lp - a pointer to the wireless adapter's private structure
*
* RETURNS:
*
* an HCF status code
*
******************************************************************************/
int wl_put_ltv( struct wl_private *lp )
{
int len;
int hcf_status;
/*------------------------------------------------------------------------*/
DBG_FUNC( "wl_put_ltv" );
DBG_ENTER( DbgInfo );
if ( lp == NULL ) {
DBG_ERROR( DbgInfo, "lp pointer is NULL\n" );
return -1;
}
if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_AP ) {
lp->maxPort = 6; //;?why set this here and not as part of download process
} else {
lp->maxPort = 0;
}
/* Send our configuration to the card. Perform any endian translation
necessary */
/* Register the Mailbox; VxWorks does this elsewhere; why;? */
lp->ltvRecord.len = 4;
lp->ltvRecord.typ = CFG_REG_MB;
lp->ltvRecord.u.u32[0] = (u_long)&( lp->mailbox );
lp->ltvRecord.u.u16[2] = ( MB_SIZE / sizeof( hcf_16 ));
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* Max Data Length */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_CNF_MAX_DATA_LEN;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( HCF_MAX_PACKET_SIZE );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* System Scale / Distance between APs */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_CNF_SYSTEM_SCALE;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->DistanceBetweenAPs );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* Channel */
if ( lp->CreateIBSS && ( lp->Channel == 0 )) {
DBG_TRACE( DbgInfo, "Create IBSS" );
lp->Channel = 10;
}
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_CNF_OWN_CHANNEL;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->Channel );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* Microwave Robustness */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_CNF_MICRO_WAVE;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->MicrowaveRobustness );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* Load Balancing */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_CNF_LOAD_BALANCING;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->loadBalancing );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* Medium Distribution */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_CNF_MEDIUM_DISTRIBUTION;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->mediumDistribution );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* Country Code */
#ifdef WARP
/* Tx Power Level (for supported cards) */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_CNF_TX_POW_LVL;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->txPowLevel );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* Short Retry Limit */
/*lp->ltvRecord.len = 2;
lp->ltvRecord.typ = 0xFC32;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->shortRetryLimit );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
*/
/* Long Retry Limit */
/*lp->ltvRecord.len = 2;
lp->ltvRecord.typ = 0xFC33;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->longRetryLimit );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
*/
/* Supported Rate Set Control */
lp->ltvRecord.len = 3;
lp->ltvRecord.typ = CFG_SUPPORTED_RATE_SET_CNTL; //0xFC88;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->srsc[0] );
lp->ltvRecord.u.u16[1] = CNV_INT_TO_LITTLE( lp->srsc[1] );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* Basic Rate Set Control */
lp->ltvRecord.len = 3;
lp->ltvRecord.typ = CFG_BASIC_RATE_SET_CNTL; //0xFC89;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->brsc[0] );
lp->ltvRecord.u.u16[1] = CNV_INT_TO_LITTLE( lp->brsc[1] );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* Frame Burst Limit */
/* Defined, but not currently available in Firmware */
#endif // WARP
#ifdef WARP
/* Multicast Rate */
lp->ltvRecord.len = 3;
lp->ltvRecord.typ = CFG_CNF_MCAST_RATE;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->MulticastRate[0] );
lp->ltvRecord.u.u16[1] = CNV_INT_TO_LITTLE( lp->MulticastRate[1] );
#else
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_CNF_MCAST_RATE;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->MulticastRate[0] );
#endif // WARP
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* Own Name (Station Nickname) */
if (( len = ( strlen( lp->StationName ) + 1 ) & ~0x01 ) != 0 ) {
//DBG_TRACE( DbgInfo, "CFG_CNF_OWN_NAME : %s\n",
// lp->StationName );
lp->ltvRecord.len = 2 + ( len / sizeof( hcf_16 ));
lp->ltvRecord.typ = CFG_CNF_OWN_NAME;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( strlen( lp->StationName ));
memcpy( &( lp->ltvRecord.u.u8[2] ), lp->StationName, len );
} else {
//DBG_TRACE( DbgInfo, "CFG_CNF_OWN_NAME : EMPTY\n" );
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_CNF_OWN_NAME;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( 0 );
}
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
//DBG_TRACE( DbgInfo, "CFG_CNF_OWN_NAME result : 0x%04x\n",
// hcf_status );
/* The following are set in STA mode only */
if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_STA ) {
/* RTS Threshold */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_RTS_THRH;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->RTSThreshold );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* Port Type */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_CNF_PORT_TYPE;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->PortType );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* Tx Rate Control */
#ifdef WARP
lp->ltvRecord.len = 3;
lp->ltvRecord.typ = CFG_TX_RATE_CNTL;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->TxRateControl[0] );
lp->ltvRecord.u.u16[1] = CNV_INT_TO_LITTLE( lp->TxRateControl[1] );
#else
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_TX_RATE_CNTL;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->TxRateControl[0] );
#endif // WARP
//;?skip temporarily to see whether the RID or something else is the probelm hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
DBG_TRACE( DbgInfo, "CFG_TX_RATE_CNTL 2.4GHz : 0x%04x\n",
lp->TxRateControl[0] );
DBG_TRACE( DbgInfo, "CFG_TX_RATE_CNTL 5.0GHz : 0x%04x\n",
lp->TxRateControl[1] );
DBG_TRACE( DbgInfo, "CFG_TX_RATE_CNTL result : 0x%04x\n",
hcf_status );
/* Power Management */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_CNF_PM_ENABLED;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->PMEnabled );
// lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( 0x8001 );
DBG_TRACE( DbgInfo, "CFG_CNF_PM_ENABLED : 0x%04x\n", lp->PMEnabled );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* Multicast Receive */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_CNF_MCAST_RX;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->MulticastReceive );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* Max Sleep Duration */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_CNF_MAX_SLEEP_DURATION;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->MaxSleepDuration );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* Create IBSS */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_CREATE_IBSS;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->CreateIBSS );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* Desired SSID */
if ((( len = ( strlen( lp->NetworkName ) + 1 ) & ~0x01 ) != 0 ) &&
( strcmp( lp->NetworkName, "ANY" ) != 0 ) &&
( strcmp( lp->NetworkName, "any" ) != 0 )) {
//DBG_TRACE( DbgInfo, "CFG_DESIRED_SSID : %s\n",
// lp->NetworkName );
lp->ltvRecord.len = 2 + (len / sizeof(hcf_16));
lp->ltvRecord.typ = CFG_DESIRED_SSID;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( strlen( lp->NetworkName ));
memcpy( &( lp->ltvRecord.u.u8[2] ), lp->NetworkName, len );
} else {
//DBG_TRACE( DbgInfo, "CFG_DESIRED_SSID : ANY\n" );
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_DESIRED_SSID;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( 0 );
}
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
//DBG_TRACE( DbgInfo, "CFG_DESIRED_SSID result : 0x%04x\n",
// hcf_status );
/* Own ATIM window */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_CNF_OWN_ATIM_WINDOW;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->atimWindow );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* Holdover Duration */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_CNF_HOLDOVER_DURATION;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->holdoverDuration );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* Promiscuous Mode */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_PROMISCUOUS_MODE;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->promiscuousMode );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* Authentication */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_CNF_AUTHENTICATION;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->authentication );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
#ifdef WARP
/* Connection Control */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_CNF_CONNECTION_CNTL;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->connectionControl );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* Probe data rate */
/*lp->ltvRecord.len = 3;
lp->ltvRecord.typ = CFG_PROBE_DATA_RATE;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->probeDataRates[0] );
lp->ltvRecord.u.u16[1] = CNV_INT_TO_LITTLE( lp->probeDataRates[1] );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
DBG_TRACE( DbgInfo, "CFG_PROBE_DATA_RATE 2.4GHz : 0x%04x\n",
lp->probeDataRates[0] );
DBG_TRACE( DbgInfo, "CFG_PROBE_DATA_RATE 5.0GHz : 0x%04x\n",
lp->probeDataRates[1] );
DBG_TRACE( DbgInfo, "CFG_PROBE_DATA_RATE result : 0x%04x\n",
hcf_status );*/
#endif // WARP
} else {
/* The following are set in AP mode only */
#if 0 //;? (HCF_TYPE) & HCF_TYPE_AP
//;?should we restore this to allow smaller memory footprint
/* DTIM Period */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_CNF_OWN_DTIM_PERIOD;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->DTIMPeriod );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* Multicast PM Buffering */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_CNF_MCAST_PM_BUF;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->multicastPMBuffering );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* Reject ANY - Closed System */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_CNF_REJECT_ANY;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->RejectAny );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* Exclude Unencrypted */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_CNF_EXCL_UNENCRYPTED;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->ExcludeUnencrypted );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* IntraBSS Relay */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_CNF_INTRA_BSS_RELAY;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->intraBSSRelay );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* RTS Threshold 0 */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_RTS_THRH0;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->RTSThreshold );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* Tx Rate Control 0 */
#ifdef WARP
lp->ltvRecord.len = 3;
lp->ltvRecord.typ = CFG_TX_RATE_CNTL0;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->TxRateControl[0] );
lp->ltvRecord.u.u16[1] = CNV_INT_TO_LITTLE( lp->TxRateControl[1] );
#else
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_TX_RATE_CNTL0;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->TxRateControl[0] );
#endif // WARP
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* Own Beacon Interval */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = 0xFC31;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->ownBeaconInterval );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* Co-Existence Behavior */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = 0xFCC7;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->coexistence );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
#ifdef USE_WDS
/* RTS Threshold 1 */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_RTS_THRH1;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->wds_port[0].rtsThreshold );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* RTS Threshold 2 */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_RTS_THRH2;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->wds_port[1].rtsThreshold );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* RTS Threshold 3 */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_RTS_THRH3;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->wds_port[2].rtsThreshold );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* RTS Threshold 4 */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_RTS_THRH4;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->wds_port[3].rtsThreshold );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* RTS Threshold 5 */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_RTS_THRH5;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->wds_port[4].rtsThreshold );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* RTS Threshold 6 */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_RTS_THRH6;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->wds_port[5].rtsThreshold );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
#if 0
/* TX Rate Control 1 */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_TX_RATE_CNTL1;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->wds_port[0].txRateCntl );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* TX Rate Control 2 */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_TX_RATE_CNTL2;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->wds_port[1].txRateCntl );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* TX Rate Control 3 */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_TX_RATE_CNTL3;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->wds_port[2].txRateCntl );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* TX Rate Control 4 */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_TX_RATE_CNTL4;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->wds_port[3].txRateCntl );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* TX Rate Control 5 */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_TX_RATE_CNTL5;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->wds_port[4].txRateCntl );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* TX Rate Control 6 */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_TX_RATE_CNTL6;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->wds_port[5].txRateCntl );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
#endif
/* WDS addresses. It's okay to blindly send these parameters, because
the port needs to be enabled, before anything is done with it. */
/* WDS Address 1 */
lp->ltvRecord.len = 4;
lp->ltvRecord.typ = CFG_CNF_WDS_ADDR1;
memcpy( &lp->ltvRecord.u.u8[0], lp->wds_port[0].wdsAddress, ETH_ALEN );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* WDS Address 2 */
lp->ltvRecord.len = 4;
lp->ltvRecord.typ = CFG_CNF_WDS_ADDR2;
memcpy( &lp->ltvRecord.u.u8[0], lp->wds_port[1].wdsAddress, ETH_ALEN );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* WDS Address 3 */
lp->ltvRecord.len = 4;
lp->ltvRecord.typ = CFG_CNF_WDS_ADDR3;
memcpy( &lp->ltvRecord.u.u8[0], lp->wds_port[2].wdsAddress, ETH_ALEN );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* WDS Address 4 */
lp->ltvRecord.len = 4;
lp->ltvRecord.typ = CFG_CNF_WDS_ADDR4;
memcpy( &lp->ltvRecord.u.u8[0], lp->wds_port[3].wdsAddress, ETH_ALEN );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* WDS Address 5 */
lp->ltvRecord.len = 4;
lp->ltvRecord.typ = CFG_CNF_WDS_ADDR5;
memcpy( &lp->ltvRecord.u.u8[0], lp->wds_port[4].wdsAddress, ETH_ALEN );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* WDS Address 6 */
lp->ltvRecord.len = 4;
lp->ltvRecord.typ = CFG_CNF_WDS_ADDR6;
memcpy( &lp->ltvRecord.u.u8[0], lp->wds_port[5].wdsAddress, ETH_ALEN );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
#endif /* USE_WDS */
#endif /* (HCF_TYPE) & HCF_TYPE_AP */
}
/* Own MAC Address */
//DBG_TRACE( DbgInfo, "MAC Address : %s\n",
// DbgHwAddr( lp->MACAddress ));
if ( WVLAN_VALID_MAC_ADDRESS( lp->MACAddress )) {
/* Make the MAC address valid by:
Clearing the multicast bit
Setting the local MAC address bit
*/
//lp->MACAddress[0] &= ~0x03; //;?why is this commented out already in 720
//lp->MACAddress[0] |= 0x02;
lp->ltvRecord.len = 1 + ( ETH_ALEN / sizeof( hcf_16 ));
if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_AP ) {
//DBG_TRACE( DbgInfo, "CFG_NIC_MAC_ADDR\n" );
lp->ltvRecord.typ = CFG_NIC_MAC_ADDR;
} else {
//DBG_TRACE( DbgInfo, "CFG_CNF_OWN_MAC_ADDR\n" );
lp->ltvRecord.typ = CFG_CNF_OWN_MAC_ADDR;
}
/* MAC address is byte aligned, no endian conversion needed */
memcpy( &( lp->ltvRecord.u.u8[0] ), lp->MACAddress, ETH_ALEN );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
//DBG_TRACE( DbgInfo, "CFG_XXX_MAC_ADDR result : 0x%04x\n",
// hcf_status );
/* Update the MAC address in the netdevice struct */
memcpy( lp->dev->dev_addr, lp->MACAddress, ETH_ALEN ); //;?what is the purpose of this seemingly complex logic
}
/* Own SSID */
if ((( len = ( strlen( lp->NetworkName ) + 1 ) & ~0x01 ) != 0 ) &&
( strcmp( lp->NetworkName, "ANY" ) != 0 ) &&
( strcmp( lp->NetworkName, "any" ) != 0 )) {
//DBG_TRACE( DbgInfo, "CFG_CNF_OWN_SSID : %s\n",
// lp->NetworkName );
lp->ltvRecord.len = 2 + (len / sizeof(hcf_16));
lp->ltvRecord.typ = CFG_CNF_OWN_SSID;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( strlen( lp->NetworkName ));
memcpy( &( lp->ltvRecord.u.u8[2] ), lp->NetworkName, len );
} else {
//DBG_TRACE( DbgInfo, "CFG_CNF_OWN_SSID : ANY\n" );
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_CNF_OWN_SSID;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( 0 );
}
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
//DBG_TRACE( DbgInfo, "CFG_CNF_OWN_SSID result : 0x%04x\n",
// hcf_status );
/* enable/disable encryption */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_CNF_ENCRYPTION;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->EnableEncryption );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* Set the Authentication Key Management Suite */
lp->ltvRecord.len = 2;
lp->ltvRecord.typ = CFG_SET_WPA_AUTH_KEY_MGMT_SUITE;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->AuthKeyMgmtSuite );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* WEP Keys */
wl_set_wep_keys( lp );
/* Country Code */
/* countryInfo, ltvCountryInfo, CFG_CNF_COUNTRY_INFO */
DBG_LEAVE( DbgInfo );
return hcf_status;
} // wl_put_ltv
/*============================================================================*/
/*******************************************************************************
* init_module()
*******************************************************************************
*
* DESCRIPTION:
*
* Load the kernel module.
*
* PARAMETERS:
*
* N/A
*
* RETURNS:
*
* 0 on success
* an errno value otherwise
*
******************************************************************************/
static int __init wl_module_init( void )
{
int result;
/*------------------------------------------------------------------------*/
DBG_FUNC( "wl_module_init" );
#if DBG
/* Convert "standard" PCMCIA parameter pc_debug to a reasonable DebugFlag value.
* NOTE: The values all fall through to the lower values. */
DbgInfo->DebugFlag = 0;
DbgInfo->DebugFlag = DBG_TRACE_ON; //;?get this mess resolved one day
if ( pc_debug ) switch( pc_debug ) {
case 8:
DbgInfo->DebugFlag |= DBG_DS_ON;
case 7:
DbgInfo->DebugFlag |= DBG_RX_ON | DBG_TX_ON;
case 6:
DbgInfo->DebugFlag |= DBG_PARAM_ON;
case 5:
DbgInfo->DebugFlag |= DBG_TRACE_ON;
case 4:
DbgInfo->DebugFlag |= DBG_VERBOSE_ON;
case 1:
DbgInfo->DebugFlag |= DBG_DEFAULTS;
default:
break;
}
#endif /* DBG */
DBG_ENTER( DbgInfo );
printk(KERN_INFO "%s\n", VERSION_INFO);
printk(KERN_INFO "*** Modified for kernel 2.6 by Henk de Groot <pe1dnn@amsat.org>\n");
printk(KERN_INFO "*** Based on 7.18 version by Andrey Borzenkov <arvidjaar@mail.ru> $Revision: 39 $\n");
// ;?#if (HCF_TYPE) & HCF_TYPE_AP
// DBG_PRINT( "Access Point Mode (AP) Support: YES\n" );
// #else
// DBG_PRINT( "Access Point Mode (AP) Support: NO\n" );
// #endif /* (HCF_TYPE) & HCF_TYPE_AP */
result = wl_adapter_init_module( );
DBG_LEAVE( DbgInfo );
return result;
} // init_module
/*============================================================================*/
/*******************************************************************************
* cleanup_module()
*******************************************************************************
*
* DESCRIPTION:
*
* Unload the kernel module.
*
* PARAMETERS:
*
* N/A
*
* RETURNS:
*
* N/A
*
******************************************************************************/
static void __exit wl_module_exit( void )
{
DBG_FUNC( "wl_module_exit" );
DBG_ENTER(DbgInfo);
wl_adapter_cleanup_module( );
#if 0 //SCULL_USE_PROC /* don't waste space if unused */
remove_proc_entry( "wlags", NULL ); //;?why so a-symmetric compared to location of create_proc_read_entry
#endif
DBG_LEAVE( DbgInfo );
return;
} // cleanup_module
/*============================================================================*/
module_init(wl_module_init);
module_exit(wl_module_exit);
/*******************************************************************************
* wl_isr()
*******************************************************************************
*
* DESCRIPTION:
*
* The Interrupt Service Routine for the driver.
*
* PARAMETERS:
*
* irq - the irq the interrupt came in on
* dev_id - a buffer containing information about the request
* regs -
*
* RETURNS:
*
* N/A
*
******************************************************************************/
irqreturn_t wl_isr( int irq, void *dev_id, struct pt_regs *regs )
{
int events;
struct net_device *dev = (struct net_device *) dev_id;
struct wl_private *lp = NULL;
/*------------------------------------------------------------------------*/
if (( dev == NULL ) || ( !netif_device_present( dev ))) {
return IRQ_NONE;
}
/* Set the wl_private pointer (lp), now that we know that dev is non-null */
lp = wl_priv(dev);
#ifdef USE_RTS
if ( lp->useRTS == 1 ) {
DBG_PRINT( "EXITING ISR, IN RTS MODE...\n" );
return;
}
#endif /* USE_RTS */
/* If we have interrupts pending, then put them on a system task
queue. Otherwise turn interrupts back on */
events = hcf_action( &lp->hcfCtx, HCF_ACT_INT_OFF );
if ( events == HCF_INT_PENDING ) {
/* Schedule the ISR handler as a bottom-half task in the
tq_immediate queue */
tasklet_schedule(&lp->task);
} else {
//DBG_PRINT( "NOT OUR INTERRUPT\n" );
hcf_action( &lp->hcfCtx, HCF_ACT_INT_ON );
}
return IRQ_RETVAL(events == HCF_INT_PENDING);
} // wl_isr
/*============================================================================*/
/*******************************************************************************
* wl_isr_handler()
*******************************************************************************
*
* DESCRIPTION:
*
* The ISR handler, scheduled to run in a deferred context by the ISR. This
* is where the ISR's work actually gets done.
*
* PARAMETERS:
*
* lp - a pointer to the device's private adapter structure
*
* RETURNS:
*
* N/A
*
******************************************************************************/
#define WVLAN_MAX_INT_SERVICES 50
void wl_isr_handler( unsigned long p )
{
struct net_device *dev;
unsigned long flags;
bool_t stop = TRUE;
int count;
int result;
struct wl_private *lp = (struct wl_private *)p;
/*------------------------------------------------------------------------*/
if ( lp == NULL ) {
DBG_PRINT( "wl_isr_handler lp adapter pointer is NULL!!!\n" );
} else {
wl_lock( lp, &flags );
dev = (struct net_device *)lp->dev;
if ( dev != NULL && netif_device_present( dev ) ) stop = FALSE;
for( count = 0; stop == FALSE && count < WVLAN_MAX_INT_SERVICES; count++ ) {
stop = TRUE;
result = hcf_service_nic( &lp->hcfCtx,
(wci_bufp)lp->lookAheadBuf,
sizeof( lp->lookAheadBuf ));
if ( result == HCF_ERR_MIC ) {
wl_wext_event_mic_failed( dev ); /* Send an event that MIC failed */
//;?this seems wrong if HCF_ERR_MIC coincides with another event, stop gets FALSE
//so why not do it always ;?
}
#ifndef USE_MBOX_SYNC
if ( lp->hcfCtx.IFB_MBInfoLen != 0 ) { /* anything in the mailbox */
wl_mbx( lp );
stop = FALSE;
}
#endif
/* Check for a Link status event */
if ( ( lp->hcfCtx.IFB_LinkStat & CFG_LINK_STAT_FW ) != 0 ) {
wl_process_link_status( lp );
stop = FALSE;
}
/* Check for probe response events */
if ( lp->ProbeResp.infoType != 0 &&
lp->ProbeResp.infoType != 0xFFFF ) {
wl_process_probe_response( lp );
memset( &lp->ProbeResp, 0, sizeof( lp->ProbeResp ));
lp->ProbeResp.infoType = 0xFFFF;
stop = FALSE;
}
/* Check for updated record events */
if ( lp->updatedRecord.len != 0xFFFF ) {
wl_process_updated_record( lp );
lp->updatedRecord.len = 0xFFFF;
stop = FALSE;
}
/* Check for association status events */
if ( lp->assoc_stat.len != 0xFFFF ) {
wl_process_assoc_status( lp );
lp->assoc_stat.len = 0xFFFF;
stop = FALSE;
}
/* Check for security status events */
if ( lp->sec_stat.len != 0xFFFF ) {
wl_process_security_status( lp );
lp->sec_stat.len = 0xFFFF;
stop = FALSE;
}
#ifdef ENABLE_DMA
if ( lp->use_dma ) {
/* Check for DMA Rx packets */
if ( lp->hcfCtx.IFB_DmaPackets & HREG_EV_RDMAD ) {
wl_rx_dma( dev );
stop = FALSE;
}
/* Return Tx DMA descriptors to host */
if ( lp->hcfCtx.IFB_DmaPackets & HREG_EV_TDMAD ) {
wl_pci_dma_hcf_reclaim_tx( lp );
stop = FALSE;
}
}
else
#endif // ENABLE_DMA
{
/* Check for Rx packets */
if ( lp->hcfCtx.IFB_RxLen != 0 ) {
wl_rx( dev );
stop = FALSE;
}
/* Make sure that queued frames get sent */
if ( wl_send( lp )) {
stop = FALSE;
}
}
}
/* We're done, so turn interrupts which were turned off in wl_isr, back on */
hcf_action( &lp->hcfCtx, HCF_ACT_INT_ON );
wl_unlock( lp, &flags );
}
return;
} // wl_isr_handler
/*============================================================================*/
/*******************************************************************************
* wl_remove()
*******************************************************************************
*
* DESCRIPTION:
*
* Notify the adapter that it has been removed. Since the adapter is gone,
* we should no longer try to talk to it.
*
* PARAMETERS:
*
* dev - a pointer to the device's net_device structure
*
* RETURNS:
*
* N/A
*
******************************************************************************/
void wl_remove( struct net_device *dev )
{
struct wl_private *lp = wl_priv(dev);
unsigned long flags;
/*------------------------------------------------------------------------*/
DBG_FUNC( "wl_remove" );
DBG_ENTER( DbgInfo );
DBG_PARAM( DbgInfo, "dev", "%s (0x%p)", dev->name, dev );
wl_lock( lp, &flags );
/* stop handling interrupts */
wl_act_int_off( lp );
lp->is_handling_int = WL_NOT_HANDLING_INT;
/*
* Disable the ports: just change state: since the
* card is gone it is useless to talk to it and at
* disconnect all state information is lost anyway.
*/
/* Reset portState */
lp->portState = WVLAN_PORT_STATE_DISABLED;
#if 0 //;? (HCF_TYPE) & HCF_TYPE_AP
#ifdef USE_WDS
//wl_disable_wds_ports( lp );
#endif // USE_WDS
#endif /* (HCF_TYPE) & HCF_TYPE_AP */
/* Mark the device as unregistered */
lp->is_registered = FALSE;
/* Deregister the WDS ports as well */
WL_WDS_NETDEV_DEREGISTER( lp );
#ifdef USE_RTS
if ( lp->useRTS == 1 ) {
wl_unlock( lp, &flags );
DBG_LEAVE( DbgInfo );
return;
}
#endif /* USE_RTS */
/* Inform the HCF that the card has been removed */
hcf_connect( &lp->hcfCtx, HCF_DISCONNECT );
wl_unlock( lp, &flags );
DBG_LEAVE( DbgInfo );
return;
} // wl_remove
/*============================================================================*/
/*******************************************************************************
* wl_suspend()
*******************************************************************************
*
* DESCRIPTION:
*
* Power-down and halt the adapter.
*
* PARAMETERS:
*
* dev - a pointer to the device's net_device structure
*
* RETURNS:
*
* N/A
*
******************************************************************************/
void wl_suspend( struct net_device *dev )
{
struct wl_private *lp = wl_priv(dev);
unsigned long flags;
/*------------------------------------------------------------------------*/
DBG_FUNC( "wl_suspend" );
DBG_ENTER( DbgInfo );
DBG_PARAM( DbgInfo, "dev", "%s (0x%p)", dev->name, dev );
/* The adapter is suspended:
Stop the adapter
Power down
*/
wl_lock( lp, &flags );
/* Disable interrupt handling */
wl_act_int_off( lp );
/* Disconnect */
wl_disconnect( lp );
/* Disable */
wl_disable( lp );
/* Disconnect from the adapter */
hcf_connect( &lp->hcfCtx, HCF_DISCONNECT );
/* Reset portState to be sure (should have been done by wl_disable */
lp->portState = WVLAN_PORT_STATE_DISABLED;
wl_unlock( lp, &flags );
DBG_LEAVE( DbgInfo );
return;
} // wl_suspend
/*============================================================================*/
/*******************************************************************************
* wl_resume()
*******************************************************************************
*
* DESCRIPTION:
*
* Resume a previously suspended adapter.
*
* PARAMETERS:
*
* dev - a pointer to the device's net_device structure
*
* RETURNS:
*
* N/A
*
******************************************************************************/
void wl_resume(struct net_device *dev)
{
struct wl_private *lp = wl_priv(dev);
unsigned long flags;
/*------------------------------------------------------------------------*/
DBG_FUNC( "wl_resume" );
DBG_ENTER( DbgInfo );
DBG_PARAM( DbgInfo, "dev", "%s (0x%p)", dev->name, dev );
wl_lock( lp, &flags );
/* Connect to the adapter */
hcf_connect( &lp->hcfCtx, dev->base_addr );
/* Reset portState */
lp->portState = WVLAN_PORT_STATE_DISABLED;
/* Power might have been off, assume the card lost the firmware*/
lp->firmware_present = WL_FRIMWARE_NOT_PRESENT;
/* Reload the firmware and restart */
wl_reset( dev );
/* Resume interrupt handling */
wl_act_int_on( lp );
wl_unlock( lp, &flags );
DBG_LEAVE( DbgInfo );
return;
} // wl_resume
/*============================================================================*/
/*******************************************************************************
* wl_release()
*******************************************************************************
*
* DESCRIPTION:
*
* This function perfroms a check on the device and calls wl_remove() if
* necessary. This function can be used for all bus types, but exists mostly
* for the benefit of the Card Services driver, as there are times when
* wl_remove() does not get called.
*
* PARAMETERS:
*
* dev - a pointer to the device's net_device structure
*
* RETURNS:
*
* N/A
*
******************************************************************************/
void wl_release( struct net_device *dev )
{
struct wl_private *lp = wl_priv(dev);
/*------------------------------------------------------------------------*/
DBG_FUNC( "wl_release" );
DBG_ENTER( DbgInfo );
DBG_PARAM( DbgInfo, "dev", "%s (0x%p)", dev->name, dev );
/* If wl_remove() hasn't been called (i.e. when Card Services is shut
down with the card in the slot), then call it */
if ( lp->is_registered == TRUE ) {
DBG_TRACE( DbgInfo, "Calling unregister_netdev(), as it wasn't called yet\n" );
wl_remove( dev );
lp->is_registered = FALSE;
}
DBG_LEAVE( DbgInfo );
return;
} // wl_release
/*============================================================================*/
/*******************************************************************************
* wl_get_irq_mask()
*******************************************************************************
*
* DESCRIPTION:
*
* Accessor function to retrieve the irq_mask module parameter
*
* PARAMETERS:
*
* N/A
*
* RETURNS:
*
* The irq_mask module parameter
*
******************************************************************************/
p_u16 wl_get_irq_mask( void )
{
return irq_mask;
} // wl_get_irq_mask
/*============================================================================*/
/*******************************************************************************
* wl_get_irq_list()
*******************************************************************************
*
* DESCRIPTION:
*
* Accessor function to retrieve the irq_list module parameter
*
* PARAMETERS:
*
* N/A
*
* RETURNS:
*
* The irq_list module parameter
*
******************************************************************************/
p_s8 * wl_get_irq_list( void )
{
return irq_list;
} // wl_get_irq_list
/*============================================================================*/
/*******************************************************************************
* wl_enable()
*******************************************************************************
*
* DESCRIPTION:
*
* Used to enable MAC ports
*
* PARAMETERS:
*
* lp - pointer to the device's private adapter structure
*
* RETURNS:
*
* N/A
*
******************************************************************************/
int wl_enable( struct wl_private *lp )
{
int hcf_status = HCF_SUCCESS;
/*------------------------------------------------------------------------*/
DBG_FUNC( "wl_enable" );
DBG_ENTER( DbgInfo );
if ( lp->portState == WVLAN_PORT_STATE_ENABLED ) {
DBG_TRACE( DbgInfo, "No action: Card already enabled\n" );
} else if ( lp->portState == WVLAN_PORT_STATE_CONNECTED ) {
//;?suspicuous logic, how can you be connected without being enabled so this is probably dead code
DBG_TRACE( DbgInfo, "No action: Card already connected\n" );
} else {
hcf_status = hcf_cntl( &lp->hcfCtx, HCF_CNTL_ENABLE );
if ( hcf_status == HCF_SUCCESS ) {
/* Set the status of the NIC to enabled */
lp->portState = WVLAN_PORT_STATE_ENABLED; //;?bad mnemonic, NIC iso PORT
#ifdef ENABLE_DMA
if ( lp->use_dma ) {
wl_pci_dma_hcf_supply( lp ); //;?always succes?
}
#endif
}
}
if ( hcf_status != HCF_SUCCESS ) { //;?make this an assert
DBG_TRACE( DbgInfo, "failed: 0x%x\n", hcf_status );
}
DBG_LEAVE( DbgInfo );
return hcf_status;
} // wl_enable
/*============================================================================*/
#ifdef USE_WDS
/*******************************************************************************
* wl_enable_wds_ports()
*******************************************************************************
*
* DESCRIPTION:
*
* Used to enable the WDS MAC ports 1-6
*
* PARAMETERS:
*
* lp - pointer to the device's private adapter structure
*
* RETURNS:
*
* N/A
*
******************************************************************************/
void wl_enable_wds_ports( struct wl_private * lp )
{
DBG_FUNC( "wl_enable_wds_ports" );
DBG_ENTER( DbgInfo );
if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_AP ){
DBG_ERROR( DbgInfo, "!!!!;? someone misunderstood something !!!!!\n" );
}
DBG_LEAVE( DbgInfo );
return;
} // wl_enable_wds_ports
#endif /* USE_WDS */
/*============================================================================*/
/*******************************************************************************
* wl_connect()
*******************************************************************************
*
* DESCRIPTION:
*
* Used to connect a MAC port
*
* PARAMETERS:
*
* lp - pointer to the device's private adapter structure
*
* RETURNS:
*
* N/A
*
******************************************************************************/
int wl_connect( struct wl_private *lp )
{
int hcf_status;
/*------------------------------------------------------------------------*/
DBG_FUNC( "wl_connect" );
DBG_ENTER( DbgInfo );
if ( lp->portState != WVLAN_PORT_STATE_ENABLED ) {
DBG_TRACE( DbgInfo, "No action: Not in enabled state\n" );
DBG_LEAVE( DbgInfo );
return HCF_SUCCESS;
}
hcf_status = hcf_cntl( &lp->hcfCtx, HCF_CNTL_CONNECT );
if ( hcf_status == HCF_SUCCESS ) {
lp->portState = WVLAN_PORT_STATE_CONNECTED;
}
DBG_LEAVE( DbgInfo );
return hcf_status;
} // wl_connect
/*============================================================================*/
/*******************************************************************************
* wl_disconnect()
*******************************************************************************
*
* DESCRIPTION:
*
* Used to disconnect a MAC port
*
* PARAMETERS:
*
* lp - pointer to the device's private adapter structure
*
* RETURNS:
*
* N/A
*
******************************************************************************/
int wl_disconnect( struct wl_private *lp )
{
int hcf_status;
/*------------------------------------------------------------------------*/
DBG_FUNC( "wl_disconnect" );
DBG_ENTER( DbgInfo );
if ( lp->portState != WVLAN_PORT_STATE_CONNECTED ) {
DBG_TRACE( DbgInfo, "No action: Not in connected state\n" );
DBG_LEAVE( DbgInfo );
return HCF_SUCCESS;
}
hcf_status = hcf_cntl( &lp->hcfCtx, HCF_CNTL_DISCONNECT );
if ( hcf_status == HCF_SUCCESS ) {
lp->portState = WVLAN_PORT_STATE_ENABLED;
}
DBG_LEAVE( DbgInfo );
return hcf_status;
} // wl_disconnect
/*============================================================================*/
/*******************************************************************************
* wl_disable()
*******************************************************************************
*
* DESCRIPTION:
*
* Used to disable MAC ports
*
* PARAMETERS:
*
* lp - pointer to the device's private adapter structure
* port - the MAC port to disable
*
* RETURNS:
*
* N/A
*
******************************************************************************/
int wl_disable( struct wl_private *lp )
{
int hcf_status = HCF_SUCCESS;
/*------------------------------------------------------------------------*/
DBG_FUNC( "wl_disable" );
DBG_ENTER( DbgInfo );
if ( lp->portState == WVLAN_PORT_STATE_DISABLED ) {
DBG_TRACE( DbgInfo, "No action: Port state is disabled\n" );
} else {
hcf_status = hcf_cntl( &lp->hcfCtx, HCF_CNTL_DISABLE );
if ( hcf_status == HCF_SUCCESS ) {
/* Set the status of the port to disabled */ //;?bad mnemonic use NIC iso PORT
lp->portState = WVLAN_PORT_STATE_DISABLED;
#ifdef ENABLE_DMA
if ( lp->use_dma ) {
wl_pci_dma_hcf_reclaim( lp );
}
#endif
}
}
if ( hcf_status != HCF_SUCCESS ) {
DBG_TRACE( DbgInfo, "failed: 0x%x\n", hcf_status );
}
DBG_LEAVE( DbgInfo );
return hcf_status;
} // wl_disable
/*============================================================================*/
#ifdef USE_WDS
/*******************************************************************************
* wl_disable_wds_ports()
*******************************************************************************
*
* DESCRIPTION:
*
* Used to disable the WDS MAC ports 1-6
*
* PARAMETERS:
*
* lp - pointer to the device's private adapter structure
*
* RETURNS:
*
* N/A
*
******************************************************************************/
void wl_disable_wds_ports( struct wl_private * lp )
{
DBG_FUNC( "wl_disable_wds_ports" );
DBG_ENTER( DbgInfo );
if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_AP ){
DBG_ERROR( DbgInfo, "!!!!;? someone misunderstood something !!!!!\n" );
}
// if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_AP ) {
// wl_disable( lp, HCF_PORT_1 );
// wl_disable( lp, HCF_PORT_2 );
// wl_disable( lp, HCF_PORT_3 );
// wl_disable( lp, HCF_PORT_4 );
// wl_disable( lp, HCF_PORT_5 );
// wl_disable( lp, HCF_PORT_6 );
// }
DBG_LEAVE( DbgInfo );
return;
} // wl_disable_wds_ports
#endif // USE_WDS
/*============================================================================*/
#ifndef USE_MBOX_SYNC
/*******************************************************************************
* wl_mbx()
*******************************************************************************
*
* DESCRIPTION:
* This function is used to read and process a mailbox message.
*
*
* PARAMETERS:
*
* lp - pointer to the device's private adapter structure
*
* RETURNS:
*
* an HCF status code
*
******************************************************************************/
int wl_mbx( struct wl_private *lp )
{
int hcf_status = HCF_SUCCESS;
/*------------------------------------------------------------------------*/
DBG_FUNC( "wl_mbx" );
DBG_ENTER( DbgInfo );
DBG_TRACE( DbgInfo, "Mailbox Info: IFB_MBInfoLen: %d\n",
lp->hcfCtx.IFB_MBInfoLen );
memset( &( lp->ltvRecord ), 0, sizeof( ltv_t ));
lp->ltvRecord.len = MB_SIZE;
lp->ltvRecord.typ = CFG_MB_INFO;
hcf_status = hcf_get_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
if ( hcf_status != HCF_SUCCESS ) {
DBG_ERROR( DbgInfo, "hcf_get_info returned 0x%x\n", hcf_status );
DBG_LEAVE( DbgInfo );
return hcf_status;
}
if ( lp->ltvRecord.typ == CFG_MB_INFO ) {
DBG_LEAVE( DbgInfo );
return hcf_status;
}
/* Endian translate the mailbox data, then process the message */
wl_endian_translate_mailbox( &( lp->ltvRecord ));
wl_process_mailbox( lp );
DBG_LEAVE( DbgInfo );
return hcf_status;
} // wl_mbx
/*============================================================================*/
/*******************************************************************************
* wl_endian_translate_mailbox()
*******************************************************************************
*
* DESCRIPTION:
*
* This function will perform the tedious task of endian translating all
* fields withtin a mailbox message which need translating.
*
* PARAMETERS:
*
* ltv - pointer to the LTV to endian translate
*
* RETURNS:
*
* none
*
******************************************************************************/
void wl_endian_translate_mailbox( ltv_t *ltv )
{
DBG_FUNC( "wl_endian_translate_mailbox" );
DBG_ENTER( DbgInfo );
switch( ltv->typ ) {
case CFG_TALLIES:
break;
case CFG_SCAN:
{
int num_aps;
SCAN_RS_STRCT *aps = (SCAN_RS_STRCT *)&ltv->u.u8[0];
num_aps = (hcf_16)(( (size_t)(ltv->len - 1 ) * 2 ) /
( sizeof( SCAN_RS_STRCT )));
while( num_aps >= 1 ) {
num_aps--;
aps[num_aps].channel_id =
CNV_LITTLE_TO_INT( aps[num_aps].channel_id );
aps[num_aps].noise_level =
CNV_LITTLE_TO_INT( aps[num_aps].noise_level );
aps[num_aps].signal_level =
CNV_LITTLE_TO_INT( aps[num_aps].signal_level );
aps[num_aps].beacon_interval_time =
CNV_LITTLE_TO_INT( aps[num_aps].beacon_interval_time );
aps[num_aps].capability =
CNV_LITTLE_TO_INT( aps[num_aps].capability );
aps[num_aps].ssid_len =
CNV_LITTLE_TO_INT( aps[num_aps].ssid_len );
aps[num_aps].ssid_val[aps[num_aps].ssid_len] = 0;
}
}
break;
case CFG_ACS_SCAN:
{
PROBE_RESP *probe_resp = (PROBE_RESP *)ltv;
probe_resp->frameControl = CNV_LITTLE_TO_INT( probe_resp->frameControl );
probe_resp->durID = CNV_LITTLE_TO_INT( probe_resp->durID );
probe_resp->sequence = CNV_LITTLE_TO_INT( probe_resp->sequence );
probe_resp->dataLength = CNV_LITTLE_TO_INT( probe_resp->dataLength );
#ifndef WARP
probe_resp->lenType = CNV_LITTLE_TO_INT( probe_resp->lenType );
#endif // WARP
probe_resp->beaconInterval = CNV_LITTLE_TO_INT( probe_resp->beaconInterval );
probe_resp->capability = CNV_LITTLE_TO_INT( probe_resp->capability );
probe_resp->flags = CNV_LITTLE_TO_INT